Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLarry Ewing <lewing@microsoft.com>2022-06-07 22:52:24 +0300
committerGitHub <noreply@github.com>2022-06-07 22:52:24 +0300
commitca4525ae0fc3fd7fb7f938869564b438dd1366b4 (patch)
tree07a7061cf85fd1e090a9c3a9e1c0732c7461b471
parent693eb07672d15aca6f504a0ef46dad24f971ca1e (diff)
parent9af8d302389305d2efaf1fd8db5c1dea0a246900 (diff)
Merge branch 'main' into darc-main-4c27684d-89e9-491d-9e86-4570d3be1a99darc-main-4c27684d-89e9-491d-9e86-4570d3be1a99
-rw-r--r--docs/design/coreclr/jit/first-class-structs.md35
-rw-r--r--docs/design/specs/Ecma-335-Augments.md7
-rw-r--r--docs/workflow/building/libraries/README.md5
-rw-r--r--docs/workflow/testing/libraries/testing-android.md2
-rw-r--r--eng/Version.Details.xml8
-rw-r--r--eng/Versions.props4
-rw-r--r--eng/native/functions.cmake7
-rw-r--r--eng/pipelines/common/templates/runtimes/run-test-job.yml1
-rw-r--r--eng/pipelines/libraries/outerloop-mono.yml1
-rw-r--r--src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs8
-rw-r--r--src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs1
-rw-r--r--src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs4
-rw-r--r--src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs2
-rw-r--r--src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs6
-rw-r--r--src/coreclr/inc/corinfo.h4
-rw-r--r--src/coreclr/inc/corjit.h6
-rw-r--r--src/coreclr/inc/icorjitinfoimpl_generated.h4
-rw-r--r--src/coreclr/inc/jiteeversionguid.h10
-rw-r--r--src/coreclr/inc/jithelpers.h3
-rw-r--r--src/coreclr/inc/utilcode.h184
-rw-r--r--src/coreclr/jit/ICorJitInfo_API_names.h1
-rw-r--r--src/coreclr/jit/ICorJitInfo_API_wrapper.hpp10
-rw-r--r--src/coreclr/jit/assertionprop.cpp37
-rw-r--r--src/coreclr/jit/codegen.h5
-rw-r--r--src/coreclr/jit/codegenarm64.cpp4
-rw-r--r--src/coreclr/jit/codegenarmarch.cpp12
-rw-r--r--src/coreclr/jit/codegencommon.cpp5
-rw-r--r--src/coreclr/jit/codegenlinear.cpp19
-rw-r--r--src/coreclr/jit/codegenxarch.cpp28
-rw-r--r--src/coreclr/jit/compiler.cpp7
-rw-r--r--src/coreclr/jit/compiler.h42
-rw-r--r--src/coreclr/jit/compiler.hpp46
-rw-r--r--src/coreclr/jit/ee_il_dll.cpp27
-rw-r--r--src/coreclr/jit/emit.cpp262
-rw-r--r--src/coreclr/jit/emit.h32
-rw-r--r--src/coreclr/jit/emitarm.h6
-rw-r--r--src/coreclr/jit/emitarm64.h6
-rw-r--r--src/coreclr/jit/emitpub.h6
-rw-r--r--src/coreclr/jit/emitxarch.cpp94
-rw-r--r--src/coreclr/jit/emitxarch.h6
-rw-r--r--src/coreclr/jit/fgopt.cpp36
-rw-r--r--src/coreclr/jit/flowgraph.cpp5
-rw-r--r--src/coreclr/jit/gentree.cpp457
-rw-r--r--src/coreclr/jit/gentree.h106
-rw-r--r--src/coreclr/jit/gtlist.h6
-rw-r--r--src/coreclr/jit/gtstructs.h1
-rw-r--r--src/coreclr/jit/hwintrinsic.cpp15
-rw-r--r--src/coreclr/jit/hwintrinsicarm64.cpp5
-rw-r--r--src/coreclr/jit/hwintrinsicxarch.cpp5
-rw-r--r--src/coreclr/jit/importer.cpp181
-rw-r--r--src/coreclr/jit/instr.cpp29
-rw-r--r--src/coreclr/jit/jitconfigvalues.h5
-rw-r--r--src/coreclr/jit/lclmorph.cpp95
-rw-r--r--src/coreclr/jit/liveness.cpp1
-rw-r--r--src/coreclr/jit/loopcloning.cpp23
-rw-r--r--src/coreclr/jit/loopcloning.h4
-rw-r--r--src/coreclr/jit/lower.cpp14
-rw-r--r--src/coreclr/jit/morph.cpp678
-rw-r--r--src/coreclr/jit/morphblock.cpp53
-rw-r--r--src/coreclr/jit/optimizer.cpp74
-rw-r--r--src/coreclr/jit/rationalize.cpp75
-rw-r--r--src/coreclr/jit/simd.cpp91
-rw-r--r--src/coreclr/jit/unwindamd64.cpp55
-rw-r--r--src/coreclr/jit/unwindx86.cpp54
-rw-r--r--src/coreclr/jit/valuenum.cpp36
-rw-r--r--src/coreclr/jit/varset.h5
-rw-r--r--src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets12
-rw-r--r--src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props44
-rw-r--r--src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets14
-rw-r--r--src/coreclr/nativeaot/Runtime/CommonMacros.h29
-rw-r--r--src/coreclr/nativeaot/Runtime/MathHelpers.cpp22
-rw-r--r--src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj17
-rw-r--r--src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs10
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ITraceableTypeMember.cs18
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj5
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs2
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs2
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs11
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs15
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs12
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs6
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs44
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs1
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs47
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs11
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs59
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs14
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs21
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs7
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs7
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs59
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Tracing/ReflectionEventSource.cs376
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs7
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs2
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs7
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs2
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs6
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs36
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs13
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs6
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs14
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs10
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs15
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs16
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs9
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs64
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj1
-rw-r--r--src/coreclr/nativeaot/System.Private.Reflection.Metadata/src/System.Private.Reflection.Metadata.csproj27
-rw-r--r--src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj1
-rw-r--r--src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj1
-rw-r--r--src/coreclr/nativeaot/docs/optimizing.md2
-rw-r--r--src/coreclr/nativeaot/docs/prerequisites.md16
-rw-r--r--src/coreclr/nativeaot/nativeaot.sln2
-rw-r--r--src/coreclr/scripts/superpmi_collect_setup.py11
-rw-r--r--src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs15
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/CsWriter.cs10
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/NativeFormatGen.csproj45
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/PublicGen.cs2
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs8
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs21
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs721
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs10
-rw-r--r--src/coreclr/tools/Common/Internal/Metadata/NativeFormat/UpdateNativeFormatSources.cmd3
-rw-r--r--src/coreclr/tools/Common/JitInterface/CorInfoBase.cs18
-rw-r--r--src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs1
-rw-r--r--src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt1
-rw-r--r--src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs134
-rw-r--r--src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs5
-rw-r--r--src/coreclr/tools/aot/.editorconfig29
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DependencyGraphTests.cs2
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ArrayValue.cs130
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticContext.cs26
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticUtilities.cs20
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs2
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/EcmaExtensions.cs2
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FieldValue.cs41
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs83
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterProxy.cs22
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterValue.cs35
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs126
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/IValueWithStaticType.cs18
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodBodyScanner.cs205
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodParameterValue.cs59
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodProxy.cs65
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs39
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodThisParameterValue.cs40
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ArrayValue.cs121
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticContext.cs23
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticUtilities.cs4
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersBinder.cs14
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersTypeHierarchy.cs265
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FieldValue.cs41
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FlowAnnotations.cs112
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterProxy.cs20
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterValue.cs33
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/HandleCallAction.cs133
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/IValueWithStaticType.cs16
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodBodyScanner.cs227
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodParameterValue.cs49
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodProxy.cs55
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodReturnValue.cs39
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodThisParameterValue.cs40
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/README.md2
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMarker.cs123
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMethodBodyScanner.cs2474
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionPatternContext.cs106
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/RequireDynamicallyAccessedMembersAction.cs43
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ScannerExtensions.cs4
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/SingleValueExtensions.cs87
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/TypeProxy.cs43
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ValueNode.cs1345
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs197
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs3074
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs124
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs47
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeExtensions.cs43
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeProxy.cs49
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ValueNode.cs1375
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logger.cs40
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs2
-rw-r--r--src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj15
-rw-r--r--src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs15
-rw-r--r--src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs47
-rw-r--r--src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs14
-rw-r--r--src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/SingleMethodCompilationModuleGroup.cs14
-rw-r--r--src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs27
-rw-r--r--src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs16
-rw-r--r--src/coreclr/tools/aot/ILCompiler/Program.cs2
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/Annotations.cs138
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/DefaultValueDictionary.cs88
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/DictionaryLattice.cs38
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/ForwardDataFlowAnalysis.cs356
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/IControlFlowGraph.cs67
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDataFlowState.cs26
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDeepCopyValue.cs14
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/ILattice.cs42
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/ITransfer.cs38
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/SingleValue.cs24
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSet.cs193
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSetLattice.cs19
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DiagnosticCategory.cs19
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs420
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs65
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/HashUtils.cs42
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd214
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems18
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.shproj4
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/IsExternalInit.cs15
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/MessageFormat.cs56
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs21
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/README.md2
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx41
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ArrayValue.cs20
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ConstIntValue.cs24
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs13
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FieldValue.cs10
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs31
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/GenericParameterValue.cs19
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/HandleCallAction.cs1445
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/IntrinsicId.cs71
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/Intrinsics.cs378
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/KnownStringValue.cs24
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs10
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodReturnValue.cs10
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs10
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullValue.cs23
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableSystemTypeValue.cs33
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableValueWithDynamicallyAccessedMembers.cs39
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs72
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeMethodHandleValue.cs28
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForGenericParameterValue.cs25
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableSystemTypeValue.cs33
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers.cs33
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleValue.cs28
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs25
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemTypeValue.cs28
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/UnknownValue.cs23
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueExtensions.cs59
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueWithDynamicallyAccessedMembers.cs19
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/GenericParameterProxy.cs13
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/IMemberProxy.cs15
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/MethodProxy.cs29
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/TypeProxy.cs15
-rw-r--r--src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/WellKnownType.cs71
-rw-r--r--src/coreclr/tools/aot/crossgen2/Program.cs42
-rw-r--r--src/coreclr/tools/aot/jitinterface/jitinterface.h11
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp10
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp8
-rw-r--r--src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp7
-rw-r--r--src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp7
-rw-r--r--src/coreclr/vm/appdomain.cpp55
-rw-r--r--src/coreclr/vm/appdomain.hpp4
-rw-r--r--src/coreclr/vm/dllimport.cpp2
-rw-r--r--src/coreclr/vm/jithelpers.cpp57
-rw-r--r--src/coreclr/vm/jitinterface.cpp52
-rw-r--r--src/coreclr/vm/jitinterface.h2
-rw-r--r--src/coreclr/vm/util.cpp178
-rw-r--r--src/coreclr/vm/util.hpp2
-rw-r--r--src/installer/pkg/sfx/installers/host.wxs3
-rw-r--r--src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPathTempDirectory.cs (renamed from src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs)0
-rw-r--r--src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.AnyMobile.cs (renamed from src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.Android.cs)0
-rw-r--r--src/libraries/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs1
-rw-r--r--src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/Http3SettingType.cs15
-rw-r--r--src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs4
-rw-r--r--src/libraries/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs5
-rw-r--r--src/libraries/Common/src/System/Net/SecurityStatusPal.cs3
-rw-r--r--src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs8
-rw-r--r--src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs2
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs2
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs4
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs2
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs18
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs3
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs2
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs2
-rw-r--r--src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs16
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyFileTests.cs2
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyPemTests.cs8
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSATestData.cs2
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.LimitedPrivate.cs2
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs2
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyPemTests.cs6
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs2
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyFileTests.cs2
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyPemTests.cs11
-rw-r--r--src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs5
-rw-r--r--src/libraries/Common/tests/Tests/System/StringTests.cs187
-rw-r--r--src/libraries/Microsoft.Extensions.HostFactoryResolver/Microsoft.Extensions.HostFactoryResolver.sln14
-rw-r--r--src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs24
-rw-r--r--src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs6
-rw-r--r--src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostAbortedException.cs (renamed from src/libraries/Microsoft.Extensions.Hosting/src/HostAbortedException.cs)0
-rw-r--r--src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Resources/Strings.resx123
-rw-r--r--src/libraries/Microsoft.Extensions.Hosting/ref/Microsoft.Extensions.Hosting.cs46
-rw-r--r--src/libraries/Microsoft.Extensions.Hosting/src/Resources/Strings.resx3
-rw-r--r--src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/AssociatedMetadataTypeTypeDescriptor.cs23
-rw-r--r--src/libraries/System.Data.Common/ref/System.Data.Common.cs19
-rw-r--r--src/libraries/System.Data.Common/src/Resources/Strings.resx2
-rw-r--r--src/libraries/System.Data.Common/src/System.Data.Common.csproj2
-rw-r--r--src/libraries/System.Data.Common/src/System/Data/Common/DbDataSource.cs584
-rw-r--r--src/libraries/System.Data.Common/src/System/Data/Common/DbProviderFactory.cs3
-rw-r--r--src/libraries/System.Data.Common/src/System/Data/Common/DefaultDataSource.cs32
-rw-r--r--src/libraries/System.Data.Common/src/System/Data/DataException.cs11
-rw-r--r--src/libraries/System.Diagnostics.Process/tests/RemotelyInvokable.cs2
-rw-r--r--src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs6
-rw-r--r--src/libraries/System.Drawing.Common/tests/ImageTests.cs12
-rw-r--r--src/libraries/System.Formats.Asn1/tests/Reader/ReadGeneralizedTime.cs8
-rw-r--r--src/libraries/System.Formats.Tar/ref/System.Formats.Tar.cs22
-rw-r--r--src/libraries/System.Formats.Tar/src/System.Formats.Tar.csproj2
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/GnuTarEntry.cs4
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/PaxTarEntry.cs4
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/PosixTarEntry.cs6
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs8
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryFormat.cs (renamed from src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFormat.cs)14
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryType.cs16
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFile.cs2
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Read.cs32
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs20
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs2
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs12
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarReader.cs32
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs10
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Windows.cs10
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.cs38
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/UstarTarEntry.cs2
-rw-r--r--src/libraries/System.Formats.Tar/src/System/Formats/Tar/V7TarEntry.cs2
-rw-r--r--src/libraries/System.Formats.Tar/tests/CompressedTar.Tests.cs4
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs6
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs198
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs10
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.Tests.cs36
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Gnu.Tests.cs22
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Pax.Tests.cs22
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Ustar.Tests.cs16
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.V7.Tests.cs26
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs36
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.cs58
-rw-r--r--src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs2
-rw-r--r--src/libraries/System.IO.Compression.ZipFile/tests/ZipFile.Unix.cs3
-rw-r--r--src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs6
-rw-r--r--src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs6
-rw-r--r--src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs6
-rw-r--r--src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs8
-rw-r--r--src/libraries/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs8
-rw-r--r--src/libraries/System.IO.Hashing/tests/Crc32Tests.cs4
-rw-r--r--src/libraries/System.IO.Hashing/tests/Crc64Tests.cs4
-rw-r--r--src/libraries/System.IO.Hashing/tests/XxHash32Tests.007.cs8
-rw-r--r--src/libraries/System.IO.Hashing/tests/XxHash32Tests.cs8
-rw-r--r--src/libraries/System.IO.Hashing/tests/XxHash32Tests.f00d.cs8
-rw-r--r--src/libraries/System.IO.Hashing/tests/XxHash64Tests.007.cs8
-rw-r--r--src/libraries/System.IO.Hashing/tests/XxHash64Tests.cs8
-rw-r--r--src/libraries/System.IO.Hashing/tests/XxHash64Tests.f00d.cs8
-rw-r--r--src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs20
-rw-r--r--src/libraries/System.IO.Pipelines/tests/PipeReaderReadAtLeastAsyncTests.cs10
-rw-r--r--src/libraries/System.IO.Pipelines/tests/PipeReaderStreamTests.nonnetstandard.cs6
-rw-r--r--src/libraries/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs10
-rw-r--r--src/libraries/System.IO.Pipelines/tests/PipeWriterCopyToAsyncTests.cs8
-rw-r--r--src/libraries/System.IO.Pipelines/tests/PipeWriterStreamTests.nonnetstandard.cs12
-rw-r--r--src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs4
-rw-r--r--src/libraries/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs8
-rw-r--r--src/libraries/System.IO.Pipelines/tests/SchedulerFacts.cs12
-rw-r--r--src/libraries/System.IO.Pipelines/tests/SequencePipeReaderTests.cs8
-rw-r--r--src/libraries/System.IO.Pipelines/tests/StreamPipeReaderTests.cs8
-rw-r--r--src/libraries/System.IO.Pipelines/tests/StreamPipeWriterTests.cs32
-rw-r--r--src/libraries/System.IO.Pipelines/tests/UnflushedBytesTests.cs2
-rw-r--r--src/libraries/System.Memory.Data/tests/BinaryDataTests.cs48
-rw-r--r--src/libraries/System.Memory/tests/Base64/Base64DecoderUnitTests.cs12
-rw-r--r--src/libraries/System.Memory/tests/BuffersExtensions/BuffersExtensionsTests.cs8
-rw-r--r--src/libraries/System.Memory/tests/EncodingExtensions/EncodingExtensionsTests.cs24
-rw-r--r--src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.byte.cs2
-rw-r--r--src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs4
-rw-r--r--src/libraries/System.Memory/tests/SequenceReader/SkipDelimiter.cs34
-rw-r--r--src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs4
-rw-r--r--src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs2
-rw-r--r--src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj1
-rw-r--r--src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/TrailingHeadersTest.cs2
-rw-r--r--src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpResponseStreamTest.cs4
-rw-r--r--src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs2
-rw-r--r--src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs2
-rw-r--r--src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs14
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs2
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HPackTest.cs5
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs1
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs13
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs111
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Url.cs46
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs3
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs7
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs12
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/MultipartContentTest.cs68
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamConformanceTests.cs8
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamZeroByteReadTests.cs10
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs2
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2FlowControl.cs7
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2KeepAlivePing.cs4
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs57
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs2
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs15
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj1
-rw-r--r--src/libraries/System.Net.Http/tests/UnitTests/Headers/MultipartContentTest.cs14
-rw-r--r--src/libraries/System.Net.Http/tests/UnitTests/MockContent.cs10
-rw-r--r--src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs2
-rw-r--r--src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStreamAsyncResult.cs2
-rw-r--r--src/libraries/System.Net.HttpListener/tests/HttpListenerAuthenticationTests.cs2
-rw-r--r--src/libraries/System.Net.HttpListener/tests/HttpListenerContextTests.cs2
-rw-r--r--src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.cs2
-rw-r--r--src/libraries/System.Net.HttpListener/tests/HttpResponseStreamTests.cs10
-rw-r--r--src/libraries/System.Net.Mail/src/System/Net/Mime/EncodedStreamFactory.cs2
-rw-r--r--src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs4
-rw-r--r--src/libraries/System.Net.Mail/tests/Unit/QuotedPrintableStreamTest.cs8
-rw-r--r--src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs2
-rw-r--r--src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs4
-rw-r--r--src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs4
-rw-r--r--src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs4
-rw-r--r--src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs4
-rw-r--r--src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs2
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs4
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs2
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.cs4
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs6
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs9
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs14
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs6
-rw-r--r--src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs4
-rw-r--r--src/libraries/System.Net.Security/tests/EnterpriseTests/NegotiateStreamLoopbackTest.cs2
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs2
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamKerberosTest.cs2
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs2
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs20
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs4
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs2
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs2
-rw-r--r--src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs4
-rw-r--r--src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs8
-rw-r--r--src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs4
-rw-r--r--src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs4
-rw-r--r--src/libraries/System.Net.WebSockets/tests/WebSocketDeflateTests.cs10
-rw-r--r--src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems15
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs110
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/DateTime.cs3
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Delegate.cs8
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs3
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs111
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Globalization/Ordinal.cs4
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Globalization/SortVersion.cs6
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs1
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs22
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs3
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs80
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs7
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInfo.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/EventInfo.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/MemberInfo.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/Module.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs5
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs2
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs22
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/String.cs4
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs389
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.AppendFormat.cs375
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs252
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs6
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs19
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Version.cs11
-rw-r--r--src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs10
-rw-r--r--src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/NamespaceHandlingTests.cs6
-rw-r--r--src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderReadTests.cs8
-rw-r--r--src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverAddRemoveTests.cs4
-rw-r--r--src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverGetEntity.cs2
-rw-r--r--src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs16
-rw-r--r--src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBinaryReaderTests.cs2
-rw-r--r--src/libraries/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs2
-rw-r--r--src/libraries/System.Reflection.Metadata/tests/Utilities/MemoryBlockTests.cs12
-rw-r--r--src/libraries/System.Reflection/tests/MethodInfoTests.cs1
-rw-r--r--src/libraries/System.Resources.Extensions/src/ILLink/ILLink.Suppressions.xml2
-rw-r--r--src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj1
-rw-r--r--src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64CharArray.cs2
-rw-r--r--src/libraries/System.Runtime.Extensions/tests/System/Diagnostics/Stopwatch.cs22
-rw-r--r--src/libraries/System.Runtime.Extensions/tests/System/Net/WebUtility.cs4
-rw-r--r--src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTestTypes/SampleTypes.cs24
-rw-r--r--src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs5
-rw-r--r--src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs4
-rw-r--r--src/libraries/System.Runtime/tests/System/Text/Latin1UtilityTests.cs4
-rw-r--r--src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs15
-rw-r--r--src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs2
-rw-r--r--src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs2
-rw-r--r--src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs38
-rw-r--r--src/libraries/System.Runtime/tests/default.rd.xml3
-rw-r--r--src/libraries/System.Security.Cryptography.Cose/tests/CoseTestHelpers.cs2
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs8
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs6
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs20
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/SignatureSupport.cs14
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs10
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs39
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs10
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs28
-rw-r--r--src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj3
-rw-r--r--src/libraries/System.Security.Cryptography.X509Certificates/tests/PublicKeyTests.cs10
-rw-r--r--src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs20
-rw-r--r--src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs22
-rw-r--r--src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.Pem.iOS.cs5
-rw-r--r--src/libraries/System.Security.Cryptography/tests/Base64TransformsTests.cs4
-rw-r--r--src/libraries/System.Security.Cryptography/tests/CryptoStream.cs2
-rw-r--r--src/libraries/System.Security.Cryptography/tests/Rfc2898OneShotTests.cs2
-rw-r--r--src/libraries/System.Security.Cryptography/tests/TripleDesTests.cs2
-rw-r--r--src/libraries/System.Text.Encoding.Extensions/tests/Fallback.cs2
-rw-r--r--src/libraries/System.Text.Encodings.Web/tests/TextEncoderTests.cs6
-rw-r--r--src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TimeOnlyConverter.cs56
-rw-r--r--src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs15
-rw-r--r--src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Stream.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonElementWriteTests.cs5
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/ParseTests.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonReaderStateAndOptionsTests.cs4
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/NewtonsoftTests/CustomObjectConverterTests.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Array.ReadTests.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Null.ReadTests.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ReadValueTests.cs24
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SpanTests.cs3
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.ReadTests.cs9
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs3
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.WriteTests.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/WriteValueTests.cs2
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.MultiSegment.cs6
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.ValueTextEquals.cs23
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs8
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs8
-rw-r--r--src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs42
-rw-r--r--src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs9
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx4
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj3
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs56
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/DfaMatchingState.cs4
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexBuilder.cs90
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Dgml.cs11
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Sample.cs10
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.cs485
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs93
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexRunnerFactory.cs14
-rw-r--r--src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexThresholds.cs62
-rw-r--r--src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs7
-rw-r--r--src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs77
-rw-r--r--src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Replace.Tests.cs12
-rw-r--r--src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Tests.Common.cs16
-rw-r--r--src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs254
-rw-r--r--src/libraries/System.Text.RegularExpressions/tests/UnitTests/System.Text.RegularExpressions.Unit.Tests.csproj24
-rw-r--r--src/libraries/tests.proj2
-rw-r--r--src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj9
-rw-r--r--src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs119
-rw-r--r--src/mono/mono/component/debugger-agent.c7
-rw-r--r--src/mono/mono/component/hot_reload-stub.c10
-rw-r--r--src/mono/mono/component/hot_reload.c28
-rw-r--r--src/mono/mono/component/hot_reload.h1
-rw-r--r--src/mono/mono/metadata/assembly.c35
-rw-r--r--src/mono/mono/metadata/class-init.h2
-rw-r--r--src/mono/mono/metadata/class.c4
-rw-r--r--src/mono/mono/metadata/image-internals.h13
-rw-r--r--src/mono/mono/metadata/image.c56
-rw-r--r--src/mono/mono/metadata/metadata-internals.h3
-rw-r--r--src/mono/mono/metadata/metadata-update.c6
-rw-r--r--src/mono/mono/metadata/metadata-update.h2
-rw-r--r--src/mono/mono/mini/aot-compiler.c289
-rw-r--r--src/mono/mono/mini/interp/interp.c4
-rw-r--r--src/mono/mono/mini/interp/tiering.c13
-rw-r--r--src/mono/mono/mini/interp/tiering.h8
-rw-r--r--src/mono/mono/mini/method-to-ir.c2
-rw-r--r--src/mono/mono/mini/mini-llvm.c16
-rw-r--r--src/mono/mono/mini/simd-intrinsics.c19
-rw-r--r--src/mono/wasm/build/WasmApp.Native.targets5
-rw-r--r--src/mono/wasm/build/WasmApp.targets2
-rw-r--r--src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs197
-rw-r--r--src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs99
-rw-r--r--src/mono/wasm/debugger/BrowserDebugProxy/ProxyOptions.cs2
-rw-r--r--src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs129
-rw-r--r--src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs17
-rw-r--r--src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs116
-rw-r--r--src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs7
-rw-r--r--src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs33
-rw-r--r--src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs53
-rw-r--r--src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs117
-rw-r--r--src/mono/wasm/host/CommonConfiguration.cs4
-rw-r--r--src/mono/wasm/host/RunConfiguration.cs2
-rw-r--r--src/mono/wasm/runtime/CMakeLists.txt2
-rw-r--r--src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js1
-rw-r--r--src/mono/wasm/runtime/crypto-worker.ts31
-rw-r--r--src/mono/wasm/runtime/cwraps.ts2
-rw-r--r--src/mono/wasm/runtime/debug.ts12
-rw-r--r--src/mono/wasm/runtime/dotnet-crypto-worker.js34
-rw-r--r--src/mono/wasm/runtime/driver.c11
-rw-r--r--src/mono/wasm/runtime/es6/dotnet.es6.lib.js1
-rw-r--r--src/mono/wasm/runtime/exports.ts2
-rw-r--r--src/mono/wasm/runtime/method-calls.ts6
-rw-r--r--src/mono/wasm/wasm.proj11
-rw-r--r--src/native/libs/ReadMe.md3
-rw-r--r--src/native/libs/System.Native/CMakeLists.txt5
-rw-r--r--src/native/libs/System.Native/pal_datetime.h2
-rw-r--r--src/native/libs/System.Native/pal_datetime.m12
-rw-r--r--src/native/libs/System.Native/pal_networking.c10
-rw-r--r--src/tasks/AotCompilerTask/MonoAOTCompiler.cs26
-rw-r--r--src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs1
-rw-r--r--src/tests/BuildWasmApps/Wasm.Build.Tests/WasmBuildAppTest.cs36
-rw-r--r--src/tests/BuildWasmApps/Wasm.Build.Tests/WasmSIMDTests.cs40
-rw-r--r--src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.cmd10
-rw-r--r--src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.sh10
-rw-r--r--src/tests/Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj1
-rw-r--r--src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs122
-rw-r--r--src/tests/Common/Coreclr.TestWrapper/MobileAppHandler.cs51
-rw-r--r--src/tests/Common/testenvironment.proj3
-rw-r--r--src/tests/JIT/Directed/StructABI/SevenByteStruct.cs35
-rw-r--r--src/tests/JIT/Directed/StructABI/SevenByteStruct.csproj12
-rw-r--r--src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.cs35
-rw-r--r--src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.csproj13
-rw-r--r--src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.cs46
-rw-r--r--src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.csproj13
-rw-r--r--src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.cs32
-rw-r--r--src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.csproj10
-rw-r--r--src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.cs24
-rw-r--r--src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.csproj9
-rw-r--r--src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.cs48
-rw-r--r--src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.il110
-rw-r--r--src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.ilproj12
-rw-r--r--src/tests/JIT/opt/Cloning/Runtime_61040_5.cs51
-rw-r--r--src/tests/JIT/opt/Cloning/Runtime_61040_5.csproj10
-rw-r--r--src/tests/JIT/opt/Cloning/callandindir.cs54
-rw-r--r--src/tests/JIT/opt/Cloning/callandindir.csproj9
-rw-r--r--src/tests/issues.targets28
629 files changed, 16094 insertions, 14291 deletions
diff --git a/docs/design/coreclr/jit/first-class-structs.md b/docs/design/coreclr/jit/first-class-structs.md
index 4571d311acc..5981413bd84 100644
--- a/docs/design/coreclr/jit/first-class-structs.md
+++ b/docs/design/coreclr/jit/first-class-structs.md
@@ -70,11 +70,6 @@ Current Representation of Struct Values
These struct-typed nodes are created by the importer, but transformed in morph, and so are not
encountered by most phases of the JIT:
-* `GT_INDEX`: This is transformed to a `GT_IND`
- * Currently, the IND is marked with `GTF_IND_ARR_INDEX` and the node pointer of the `GT_IND` acts as a key
- into the array info map.
- * Proposed: This should be transformed into a `GT_OBJ` when it represents a struct type, and then the
- class handle would no longer need to be obtained from the array info map.
* `GT_FIELD`: This is transformed to a `GT_LCL_VAR` by the `Compiler::fgMarkAddressExposedLocals()` phase
if it's a promoted struct field, or to a `GT_LCL_FLD` or GT_IND` by `fgMorphField()`.
* Proposed: A non-promoted struct typed field should be transformed into a `GT_OBJ`, so that consistently all struct
@@ -90,9 +85,7 @@ encountered by most phases of the JIT:
### Struct “objects” as lvalues
* The lhs of a struct assignment is a block or local node:
- * `GT_OBJ` nodes represent the “shape” info via a struct handle, along with the GC info
- (location and type of GC references within the struct).
- * These are currently used only to represent struct values that contain GC references (although see below).
+ * `GT_OBJ` nodes represent struct types with a handle, and store a pointer to the `ClassLayout` object.
* `GT_BLK` nodes represent struct types with no GC references, or opaque blocks of fixed size.
* These have no struct handle, resulting in some pessimization or even incorrect
code when the appropriate struct handle can't be determined.
@@ -101,12 +94,12 @@ encountered by most phases of the JIT:
[#21705](https://github.com/dotnet/coreclr/pull/21705) they are no longer large nodes.
* `GT_STORE_OBJ` and `GT_STORE_BLK` have the same structure as `GT_OBJ` and `GT_BLK`, respectively
* `Data()` is op2
- * `GT_DYN_BLK` and `GT_STORE_DYN_BLK` (GenTreeDynBlk extends GenTreeBlk)
+ * `GT_STORE_DYN_BLK` (GenTreeStoreDynBlk extends GenTreeBlk)
* Additional child `gtDynamicSize`
- * Note that these aren't really struct types; they represent dynamically sized blocks
+ * Note that these aren't really struct stores; they represent dynamically sized blocks
of arbitrary data.
- * For `GT_LCL_FLD` nodes, we don't retain shape information, except indirectly via the `FieldSeqNode`.
- * For `GT_LCL_VAR` nodes, the`ClassLayout` is obtained from the `LclVarDsc`.
+ * For `GT_LCL_FLD` nodes, we store a pointer to `ClassLayout` in the node.
+ * For `GT_LCL_VAR` nodes, the `ClassLayout` is obtained from the `LclVarDsc`.
### Struct “objects” as rvalues
@@ -131,10 +124,6 @@ After morph, a struct-typed value on the RHS of assignment is one of:
* `GT_CALL`
* `GT_LCL_VAR`
* `GT_LCL_FLD`
- * Note: With `compDoOldStructRetyping()`, a GT_LCL_FLD` with a primitive type of the same size as the struct
- is used to represent a reference to the full struct when it is passed in a register.
- This forces the struct to live on the stack, and makes it more difficult to optimize these struct values,
- which is why this mechanism is being phased out.
* `GT_SIMD`
* `GT_OBJ` nodes can also be used as rvalues when they are call arguments
* Proposed: `GT_OBJ` nodes can be used in any context where a struct rvalue or lvalue might occur,
@@ -173,8 +162,7 @@ There are three main phases in the JIT that make changes to the representation o
registers. The necessary transformations for correct code generation would be
made in `Lowering`.
- * With `compDoOldStructRetyping()`, if it is passed in a single register, it is morphed into a
- `GT_LCL_FLD` node of the appropriate primitive type.
+ * If it is passed in a single register, it is morphed into a `GT_LCL_FLD` node of the appropriate primitive type.
* This may involve making a copy, if the size cannot be safely loaded.
* Proposed: This would remain a `GT_OBJ` and would be appropriately transformed in `Lowering`,
e.g. using `GT_BITCAST`.
@@ -310,22 +298,13 @@ This would be enabled first by [Defer ABI-specific transformations to Lowering](
for block copies. See [\#21711 Improve init/copy block codegen](https://github.com/dotnet/coreclr/pull/21711).
* This also includes cleanup of the block morphing methods such that block nodes needn't be visited multiple
- times, such as `fgMorphBlkToInd` (may be simply unneeded), `fgMorphBlkNode` and `fgMorphBlkOperand`.
+ times, such as `fgMorphBlkNode` and `fgMorphBlkOperand`.
These methods were introduced to preserve old behavior, but should be simplified.
-* Somewhat related is the handling of struct-typed array elements. Currently, after the `GT_INDEX` is transformed
- into a `GT_IND`, that node must be retained as the key into the `ArrayInfoMap`. For structs, this is then
- wrapped in `OBJ(ADDR(...))`. We should be able to change the IND to OBJ and avoid wrapping, and should also be
- able to remove the class handle from the array info map and instead used the one provided by the `GT_OBJ`.
-
### Miscellaneous Cleanup
These are all marked with `TODO-1stClassStructs` or `TODO-Cleanup` in the last case:
-* The handling of `DYN_BLK` is unnecessarily complicated to duplicate previous behavior (i.e. to enable previous
- refactorings to be zero-diff). These nodes are infrequent so the special handling should just be eliminated
- (e.g. see `GenTree::GetChild()`).
-
* The checking at the end of `gtNewTempAssign()` should be simplified.
* When we create a struct assignment, we use `impAssignStruct()`. This code will, in some cases, create
diff --git a/docs/design/specs/Ecma-335-Augments.md b/docs/design/specs/Ecma-335-Augments.md
index dd481607d97..c0e56c9fa04 100644
--- a/docs/design/specs/Ecma-335-Augments.md
+++ b/docs/design/specs/Ecma-335-Augments.md
@@ -16,6 +16,7 @@ This is a list of additions and edits to be made in ECMA-335 specifications. It
- [Ref field support](#ref-fields)
- [Rules for IL rewriters](#rules-for-il-rewriters)
- [Checked user-defined operators](#checked-user-defined-operators)
+- [Atomic reads and writes](#atomic-reads-and-writes)
## Signatures
@@ -1013,3 +1014,9 @@ Section "I.10.3.3 Conversion operators" of ECMA-335 adds *op_CheckedExplicit* as
implementing checked explicit conversion operator.
A checked user-defined operator is expected to throw an exception when the result of an operation is too large to represent in the destination type. What does it mean to be too large actually depends on the nature of the destination type. Typically the exception thrown is a System.OverflowException.
+
+## Atomic reads and writes
+
+Section "I.12.6.6 Atomic reads and writes" adds clarification that the atomicity guarantees apply to built-in primitive value types and pointers only.
+
+A conforming CLI shall guarantee that read and write access of *built-in primitive value types and pointers* to properly aligned memory locations no larger than the native word size (the size of type native int) is atomic (see §I.12.6.2) when all the write accesses to a location are the same size.
diff --git a/docs/workflow/building/libraries/README.md b/docs/workflow/building/libraries/README.md
index 9d2e9e455ad..14093a1ac0d 100644
--- a/docs/workflow/building/libraries/README.md
+++ b/docs/workflow/building/libraries/README.md
@@ -116,6 +116,11 @@ The libraries build contains some native code. This includes shims over libc, op
./src/native/libs/build-native.sh debug x64
```
+- Building and updating the binplace (for e.g. the testhost), which is needed when iterating on native components
+```bash
+dotnet.sh build src/native/libraries/build-native.proj
+```
+
- The following example shows how you would do an arm cross-compile build
```bash
./src/native/libs/build-native.sh debug arm cross verbose
diff --git a/docs/workflow/testing/libraries/testing-android.md b/docs/workflow/testing/libraries/testing-android.md
index 9f34188d3cd..b4c5179e6be 100644
--- a/docs/workflow/testing/libraries/testing-android.md
+++ b/docs/workflow/testing/libraries/testing-android.md
@@ -14,7 +14,7 @@ To manage the dependencies, you can install them via terminal or using Android S
OpenJDK can be installed on Linux (Ubuntu) using `apt-get`:
```bash
-sudo apt-get install openjdk-8 zip unzip
+sudo apt-get install openjdk-8-jdk zip unzip
```
Android SDK and NDK can be automatically installed via the following script:
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 42d34f24df9..df1d92585c1 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -238,9 +238,9 @@
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>f21ace52e357bbf0019da5c9e42d66705a087235</Sha>
</Dependency>
- <Dependency Name="Microsoft.NET.ILLink.Tasks" Version="7.0.100-1.22270.1">
+ <Dependency Name="Microsoft.NET.ILLink.Tasks" Version="7.0.100-1.22306.1">
<Uri>https://github.com/dotnet/linker</Uri>
- <Sha>b0479355a71752de103a2aac89af5cdcdb0455ad</Sha>
+ <Sha>1481a51970586b26208a7bc6173dc77d658f3508</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.XHarness.TestRunners.Common" Version="1.0.0-prerelease.22305.1">
<Uri>https://github.com/dotnet/xharness</Uri>
@@ -274,9 +274,9 @@
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-optimization</Uri>
<Sha>d5b85fdae5fa46aa3955218446fb6809aeffb476</Sha>
</Dependency>
- <Dependency Name="Microsoft.DotNet.HotReload.Utils.Generator.BuildTool" Version="1.1.0-alpha.0.22281.2">
+ <Dependency Name="Microsoft.DotNet.HotReload.Utils.Generator.BuildTool" Version="1.1.0-alpha.0.22306.2">
<Uri>https://github.com/dotnet/hotreload-utils</Uri>
- <Sha>09c99e3060bc9e5230bd0638e48535ef15c73160</Sha>
+ <Sha>3c641f5b79f90b0341bc0b6f728bae56ede711fd</Sha>
</Dependency>
<Dependency Name="System.Runtime.Numerics.TestData" Version="7.0.0-beta.22281.1">
<Uri>https://github.com/dotnet/runtime-assets</Uri>
diff --git a/eng/Versions.props b/eng/Versions.props
index e46b304b5e3..86bf5b84d9a 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -153,7 +153,7 @@
<MicrosoftDotNetXHarnessTestRunnersCommonVersion>1.0.0-prerelease.22305.1</MicrosoftDotNetXHarnessTestRunnersCommonVersion>
<MicrosoftDotNetXHarnessTestRunnersXunitVersion>1.0.0-prerelease.22305.1</MicrosoftDotNetXHarnessTestRunnersXunitVersion>
<MicrosoftDotNetXHarnessCLIVersion>1.0.0-prerelease.22305.1</MicrosoftDotNetXHarnessCLIVersion>
- <MicrosoftDotNetHotReloadUtilsGeneratorBuildToolVersion>1.1.0-alpha.0.22281.2</MicrosoftDotNetHotReloadUtilsGeneratorBuildToolVersion>
+ <MicrosoftDotNetHotReloadUtilsGeneratorBuildToolVersion>1.1.0-alpha.0.22306.2</MicrosoftDotNetHotReloadUtilsGeneratorBuildToolVersion>
<XUnitVersion>2.4.2-pre.22</XUnitVersion>
<XUnitAnalyzersVersion>0.12.0-pre.20</XUnitAnalyzersVersion>
<XUnitRunnerVisualStudioVersion>2.4.5</XUnitRunnerVisualStudioVersion>
@@ -168,7 +168,7 @@
<!-- Docs -->
<MicrosoftPrivateIntellisenseVersion>7.0.0-preview-20220429.1</MicrosoftPrivateIntellisenseVersion>
<!-- ILLink -->
- <MicrosoftNETILLinkTasksVersion>7.0.100-1.22270.1</MicrosoftNETILLinkTasksVersion>
+ <MicrosoftNETILLinkTasksVersion>7.0.100-1.22306.1</MicrosoftNETILLinkTasksVersion>
<MicrosoftNETILLinkAnalyzerPackageVersion>$(MicrosoftNETILLinkTasksVersion)</MicrosoftNETILLinkAnalyzerPackageVersion>
<!-- ICU -->
<MicrosoftNETCoreRuntimeICUTransportVersion>7.0.0-preview.6.22306.1</MicrosoftNETCoreRuntimeICUTransportVersion>
diff --git a/eng/native/functions.cmake b/eng/native/functions.cmake
index d5a28fec536..eaef0d65df0 100644
--- a/eng/native/functions.cmake
+++ b/eng/native/functions.cmake
@@ -390,11 +390,12 @@ function(strip_symbols targetName outputFilename)
message(FATAL_ERROR "strip not found")
endif()
+ set(strip_command ${STRIP} -no_code_signature_warning -S ${strip_source_file})
+
+ # codesign release build
string(TOLOWER "${CMAKE_BUILD_TYPE}" LOWERCASE_CMAKE_BUILD_TYPE)
if (LOWERCASE_CMAKE_BUILD_TYPE STREQUAL release)
- set(strip_command ${STRIP} -no_code_signature_warning -S ${strip_source_file} && codesign -f -s - ${strip_source_file})
- else ()
- set(strip_command)
+ set(strip_command ${strip_command} && codesign -f -s - ${strip_source_file})
endif ()
execute_process(
diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml
index f7f310dfb97..9e75af0ac8f 100644
--- a/eng/pipelines/common/templates/runtimes/run-test-job.yml
+++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml
@@ -572,6 +572,7 @@ jobs:
- jitosr_stress
- jitosr_pgo
- jitosr_stress_random
+ - jit_stress_splitting
- jitpartialcompilation
- jitpartialcompilation_osr
- jitpartialcompilation_osr_pgo
diff --git a/eng/pipelines/libraries/outerloop-mono.yml b/eng/pipelines/libraries/outerloop-mono.yml
index 17a7101e260..a97e4ccc1f7 100644
--- a/eng/pipelines/libraries/outerloop-mono.yml
+++ b/eng/pipelines/libraries/outerloop-mono.yml
@@ -56,6 +56,7 @@ jobs:
- Linux_x64
- Linux_musl_x64
- OSX_x64
+ - Android_arm64
jobParameters:
testScope: outerloop
nameSuffix: AllSubsets_Mono
diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs
index 068d915dd4e..259bfc90070 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs
@@ -429,7 +429,6 @@ namespace System
return del;
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(MulticastDelegate? d1, MulticastDelegate? d2)
{
@@ -437,14 +436,12 @@ namespace System
// so it can become a simple test
if (d2 is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (d1 is null) ? true : false;
+ return d1 is null;
}
return ReferenceEquals(d2, d1) ? true : d2.Equals((object?)d1);
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(MulticastDelegate? d1, MulticastDelegate? d2)
{
@@ -454,8 +451,7 @@ namespace System
// so it can become a simple test
if (d2 is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (d1 is null) ? false : true;
+ return d1 is not null;
}
return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1);
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs
index 485bbeaa428..bd939a56daa 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs
@@ -229,7 +229,6 @@ namespace System.Reflection.Emit
// We create a transparent assembly to host DynamicMethods. Since the assembly does not have any
// non-public fields (or any fields at all), it is a safe anonymous assembly to host DynamicMethods
- [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
private static RuntimeModule GetDynamicMethodsModule()
{
if (s_anonymouslyHostedDynamicMethodsModule != null)
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs
index d2e84804adb..cc0c86e70a7 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs
@@ -1699,6 +1699,10 @@ namespace System.Reflection.Emit
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2083:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2068:UnrecognizedReflectionPattern",
+ Justification = "Reflection.Emit is not subject to trimming")]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2069:UnrecognizedReflectionPattern",
+ Justification = "Reflection.Emit is not subject to trimming")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
private TypeInfo? CreateTypeNoLock()
{
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 b3fdf8b21d2..ccd73948609 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
@@ -1137,7 +1137,7 @@ namespace System.Reflection
return result;
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2065:UnrecognizedReflectionPattern",
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:MethodParameterDoesntMeetThisParameterRequirements",
Justification = "Linker guarantees presence of all the constructor parameters, property setters and fields which are accessed by any " +
"attribute instantiation which is present in the code linker has analyzed." +
"As such the reflection usage in this method will never fail as those methods/fields will be present.")]
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
index 8bb78965595..2639b5e62df 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
@@ -237,6 +237,9 @@ namespace System
return outHandles;
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:ParameterDoesntMeetParameterRequirements",
+ Justification = "The parameter 'type' is passed by ref to QCallTypeHandle which only instantiates" +
+ "the type using the public parameterless constructor and doesn't modify it")]
internal static object CreateInstanceForAnotherGenericParameter(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
RuntimeType genericParameter)
@@ -257,6 +260,9 @@ namespace System
return instantiatedObject!;
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:ParameterDoesntMeetParameterRequirements",
+ Justification = "The parameter 'type' is passed by ref to QCallTypeHandle which only instantiates" +
+ "the type using the public parameterless constructor and doesn't modify it")]
internal static object CreateInstanceForAnotherGenericParameter(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
RuntimeType genericParameter1,
diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 156444dfeb8..7a673e52d7c 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -625,6 +625,7 @@ enum CorInfoHelpFunc
CORINFO_HELP_THROW_NOT_IMPLEMENTED, // throw NotImplementedException
CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, // throw PlatformNotSupportedException
CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED, // throw TypeNotSupportedException
+ CORINFO_HELP_THROW_AMBIGUOUS_RESOLUTION_EXCEPTION, // throw AmbiguousResolutionException for failed static virtual method resolution
CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument
CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument
@@ -646,8 +647,6 @@ enum CorInfoHelpFunc
CORINFO_HELP_VALIDATE_INDIRECT_CALL, // CFG: Validate function pointer
CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer
- CORINFO_HELP_STATIC_VIRTUAL_AMBIGUOUS_RESOLUTION, // Throw AmbiguousResolutionException for failed static virtual method resolution
-
CORINFO_HELP_COUNT,
};
@@ -1936,6 +1935,7 @@ struct CORINFO_VarArgInfo
#define OFFSETOF__CORINFO_String__stringLen SIZEOF__CORINFO_Object
#define OFFSETOF__CORINFO_String__chars (OFFSETOF__CORINFO_String__stringLen + sizeof(uint32_t) /* stringLen */)
+#define OFFSETOF__CORINFO_NullableOfT__hasValue 0
/* data to optimize delegate construction */
struct DelegateCtorArgs
diff --git a/src/coreclr/inc/corjit.h b/src/coreclr/inc/corjit.h
index 259ccdc8192..54aaded8f90 100644
--- a/src/coreclr/inc/corjit.h
+++ b/src/coreclr/inc/corjit.h
@@ -495,12 +495,6 @@ public:
uint32_t sizeInBytes /* IN: The size of the buffer. Note that this is effectively a
version number for the CORJIT_FLAGS value. */
) = 0;
-
- // Checks if a field belongs to a given class.
- virtual bool doesFieldBelongToClass(
- CORINFO_FIELD_HANDLE fldHnd, /* IN: the field that we are checking */
- CORINFO_CLASS_HANDLE cls /* IN: the class that we are checking */
- ) = 0;
};
/**********************************************************************************/
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 496a84c69dd..87f3054e626 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -710,10 +710,6 @@ uint32_t getJitFlags(
CORJIT_FLAGS* flags,
uint32_t sizeInBytes) override;
-bool doesFieldBelongToClass(
- CORINFO_FIELD_HANDLE fldHnd,
- CORINFO_CLASS_HANDLE cls) override;
-
/**********************************************************************************/
// clang-format on
/**********************************************************************************/
diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h
index 016c08df880..e03d9d9190c 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 = { /* f2a217c4-2a69-4308-99ce-8292c6763776 */
- 0xf2a217c4,
- 0x2a69,
- 0x4308,
- {0x99, 0xce, 0x82, 0x92, 0xc6, 0x76, 0x37, 0x76}
+constexpr GUID JITEEVersionIdentifier = { /* 5868685e-b877-4ef5-83f0-73d601e50013 */
+ 0x5868685e,
+ 0xb877,
+ 0x4ef5,
+ {0x83, 0xf0, 0x73, 0xd6, 0x01, 0xe5, 0x00, 0x13}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h
index f60104d068f..e40eb4105ee 100644
--- a/src/coreclr/inc/jithelpers.h
+++ b/src/coreclr/inc/jithelpers.h
@@ -309,6 +309,7 @@
JITHELPER(CORINFO_HELP_THROW_NOT_IMPLEMENTED, JIT_ThrowNotImplementedException, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JIT_ThrowPlatformNotSupportedException, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED, JIT_ThrowTypeNotSupportedException, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_THROW_AMBIGUOUS_RESOLUTION_EXCEPTION, JIT_ThrowAmbiguousResolutionException, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_JIT_PINVOKE_BEGIN, JIT_PInvokeBegin, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_JIT_PINVOKE_END, JIT_PInvokeEnd, CORINFO_HELP_SIG_REG_ONLY)
@@ -343,8 +344,6 @@
JITHELPER(CORINFO_HELP_DISPATCH_INDIRECT_CALL, NULL, CORINFO_HELP_SIG_REG_ONLY)
#endif
- JITHELPER(CORINFO_HELP_STATIC_VIRTUAL_AMBIGUOUS_RESOLUTION, JIT_StaticVirtualAmbiguousResolution, CORINFO_HELP_SIG_REG_ONLY)
-
#undef JITHELPER
#undef DYNAMICJITHELPER
#undef JITHELPER
diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h
index fa2dd61c6c9..5135c5b02f8 100644
--- a/src/coreclr/inc/utilcode.h
+++ b/src/coreclr/inc/utilcode.h
@@ -158,11 +158,6 @@ typedef LPSTR LPUTF8;
#define DIGIT_TO_INT(ch) ((ch) - W('0'))
#define INT_TO_DIGIT(i) ((WCHAR)(W('0') + (i)))
-#define IS_HEXDIGIT(ch) ((((ch) >= W('a')) && ((ch) <= W('f'))) || \
- (((ch) >= W('A')) && ((ch) <= W('F'))))
-#define HEXDIGIT_TO_INT(ch) ((towlower(ch) - W('a')) + 10)
-#define INT_TO_HEXDIGIT(i) ((WCHAR)(W('a') + ((i) - 10)))
-
// Helper will 4 byte align a value, rounding up.
#define ALIGN4BYTE(val) (((val) + 3) & ~0x3)
@@ -1185,79 +1180,6 @@ protected:
};
-template < typename T, typename U >
-struct Pair
-{
-public:
- typedef Pair< T, U > this_type;
- typedef T first_type;
- typedef U second_type;
-
- Pair()
- {}
-
- Pair( T const & t, U const & u )
- : m_first( t )
- , m_second( u )
- { SUPPORTS_DAC; }
-
- Pair( this_type const & obj )
- : m_first( obj.m_first )
- , m_second( obj.m_second )
- {}
-
- this_type & operator=( this_type const & obj )
- {
- m_first = obj.m_first;
- m_second = obj.m_second;
- return *this;
- }
-
- T & First()
- {
- return m_first;
- }
-
- T const & First() const
- {
- return m_first;
- }
-
- U & Second()
- {
- return m_second;
- }
-
- U const & Second() const
- {
- return m_second;
- }
-
- bool operator==(const Pair& rhs) const
- {
- return ((this->First() == rhs.First()) &&
- (this->Second() == rhs.Second()));
- }
-
- bool operator!=(const Pair& rhs) const
- {
- return !(*this == rhs);
- }
-
-private:
- first_type m_first;
- second_type m_second;
-};
-
-
-template < typename T, typename U >
-Pair< T, U > MakePair( T const & t, U const & u )
-{
- SUPPORTS_DAC;
- return Pair< T, U >( t, u );
-}
-
-
//*****************************************************************************
// This class implements a dynamic array of structures for which the order of
// the elements is unimportant. This means that any item placed in the list
@@ -1685,112 +1607,6 @@ typedef CDynArray<ULONG> ULONGARRAY;
typedef CDynArray<BYTE> BYTEARRAY;
typedef CDynArray<mdToken> TOKENARRAY;
-template <class T> class CStackArray : public CStructArray
-{
-public:
- CStackArray(short iGrowInc=4) :
- CStructArray(sizeof(T), iGrowInc),
- m_curPos(0)
- {
- LIMITED_METHOD_CONTRACT;
- }
-
- void Push(T p)
- {
- WRAPPER_NO_CONTRACT;
- // We should only inc m_curPos after we grow the array.
- T *pT = (T *)CStructArray::InsertThrowing(m_curPos);
- m_curPos ++;
- *pT = p;
- }
-
- T * Pop()
- {
- WRAPPER_NO_CONTRACT;
- T * retPtr;
-
- _ASSERTE(m_curPos > 0);
-
- retPtr = (T *)CStructArray::Get(m_curPos-1);
- CStructArray::Delete(m_curPos--);
-
- return (retPtr);
- }
-
- int Count()
- {
- LIMITED_METHOD_CONTRACT;
- return(m_curPos);
- }
-
-private:
- int m_curPos;
-};
-
-
-//*****************************************************************************
-// This template manages a list of free entries by their 0 based offset. By
-// making it a template, you can use whatever size free chain will match your
-// maximum count of items. -1 is reserved.
-//*****************************************************************************
-template <class T> class TFreeList
-{
-public:
- void Init(
- T *rgList,
- int iCount)
- {
- LIMITED_METHOD_CONTRACT;
- // Save off values.
- m_rgList = rgList;
- m_iCount = iCount;
- m_iNext = 0;
-
- // Init free list.
- int i;
- for (i=0; i<iCount - 1; i++)
- m_rgList[i] = i + 1;
- m_rgList[i] = (T) -1;
- }
-
- T GetFreeEntry() // Index of free item, or -1.
- {
- LIMITED_METHOD_CONTRACT;
- T iNext;
-
- if (m_iNext == (T) -1)
- return (-1);
-
- iNext = m_iNext;
- m_iNext = m_rgList[m_iNext];
- return (iNext);
- }
-
- void DelFreeEntry(T iEntry)
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(iEntry < m_iCount);
- m_rgList[iEntry] = m_iNext;
- m_iNext = iEntry;
- }
-
- // This function can only be used when it is guaranteed that the free
- // array is contigous, for example, right after creation to quickly
- // get a range of items from the heap.
- void ReserveRange(int iCount)
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(iCount < m_iCount);
- _ASSERTE(m_iNext == 0);
- m_iNext = iCount;
- }
-
-private:
- T *m_rgList; // List of free info.
- int m_iCount; // How many entries to manage.
- T m_iNext; // Next item to get.
-};
-
//*****************************************************************************
//*****************************************************************************
diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h
index fec05d5c398..520315b89f8 100644
--- a/src/coreclr/jit/ICorJitInfo_API_names.h
+++ b/src/coreclr/jit/ICorJitInfo_API_names.h
@@ -176,6 +176,5 @@ DEF_CLR_API(recordRelocation)
DEF_CLR_API(getRelocTypeHint)
DEF_CLR_API(getExpectedTargetArchitecture)
DEF_CLR_API(getJitFlags)
-DEF_CLR_API(doesFieldBelongToClass)
#undef DEF_CLR_API
diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
index 51d97b94b72..e65d1be26b3 100644
--- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
@@ -1690,16 +1690,6 @@ uint32_t WrapICorJitInfo::getJitFlags(
return temp;
}
-bool WrapICorJitInfo::doesFieldBelongToClass(
- CORINFO_FIELD_HANDLE fldHnd,
- CORINFO_CLASS_HANDLE cls)
-{
- API_ENTER(doesFieldBelongToClass);
- bool temp = wrapHnd->doesFieldBelongToClass(fldHnd, cls);
- API_LEAVE(doesFieldBelongToClass);
- return temp;
-}
-
/**********************************************************************************/
// clang-format on
/**********************************************************************************/
diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp
index b80c42875f3..ddee8ba3e6e 100644
--- a/src/coreclr/jit/assertionprop.cpp
+++ b/src/coreclr/jit/assertionprop.cpp
@@ -4326,23 +4326,11 @@ GenTree* Compiler::optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tr
return nullptr;
}
- // Check for add of a constant.
- GenTree* op1 = tree->AsIndir()->Addr();
- if ((op1->gtOper == GT_ADD) && (op1->AsOp()->gtOp2->gtOper == GT_CNS_INT))
- {
- op1 = op1->AsOp()->gtOp1;
- }
-
- if (op1->gtOper != GT_LCL_VAR)
- {
- return nullptr;
- }
-
#ifdef DEBUG
bool vnBased = false;
AssertionIndex index = NO_ASSERTION_INDEX;
#endif
- if (optAssertionIsNonNull(op1, assertions DEBUGARG(&vnBased) DEBUGARG(&index)))
+ if (optAssertionIsNonNull(tree->AsIndir()->Addr(), assertions DEBUGARG(&vnBased) DEBUGARG(&index)))
{
#ifdef DEBUG
if (verbose)
@@ -4388,19 +4376,28 @@ bool Compiler::optAssertionIsNonNull(GenTree* op,
ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased)
DEBUGARG(AssertionIndex* pIndex))
{
+ if (op->OperIs(GT_ADD) && op->AsOp()->gtGetOp2()->IsCnsIntOrI() &&
+ !fgIsBigOffset(op->AsOp()->gtGetOp2()->AsIntCon()->IconValue()))
+ {
+ op = op->AsOp()->gtGetOp1();
+ }
+
bool vnBased = (!optLocalAssertionProp && vnStore->IsKnownNonNull(op->gtVNPair.GetConservative()));
#ifdef DEBUG
+ *pIndex = NO_ASSERTION_INDEX;
*pVnBased = vnBased;
#endif
if (vnBased)
{
-#ifdef DEBUG
- *pIndex = NO_ASSERTION_INDEX;
-#endif
return true;
}
+ if (!op->OperIs(GT_LCL_VAR))
+ {
+ return false;
+ }
+
AssertionIndex index = optAssertionIsNonNullInternal(op, assertions DEBUGARG(pVnBased));
#ifdef DEBUG
*pIndex = index;
@@ -4523,16 +4520,13 @@ AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* op,
*/
GenTree* Compiler::optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call)
{
- if ((call->gtFlags & GTF_CALL_NULLCHECK) == 0)
+ if (!call->NeedsNullCheck())
{
return nullptr;
}
+
GenTree* op1 = call->gtArgs.GetThisArg()->GetNode();
noway_assert(op1 != nullptr);
- if (op1->gtOper != GT_LCL_VAR)
- {
- return nullptr;
- }
#ifdef DEBUG
bool vnBased = false;
@@ -4553,6 +4547,7 @@ GenTree* Compiler::optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, Gen
noway_assert(call->gtFlags & GTF_SIDE_EFFECT);
return call;
}
+
return nullptr;
}
diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h
index d567ef1537a..8646d9191ed 100644
--- a/src/coreclr/jit/codegen.h
+++ b/src/coreclr/jit/codegen.h
@@ -1472,8 +1472,11 @@ protected:
public:
void instGen(instruction ins);
-
+#if defined(TARGET_XARCH)
+ void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock, bool isRemovableJmpCandidate = false);
+#else
void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
+#endif
void inst_SET(emitJumpKind condition, regNumber reg);
diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp
index 9ad6220af8c..2b9d4be0abc 100644
--- a/src/coreclr/jit/codegenarm64.cpp
+++ b/src/coreclr/jit/codegenarm64.cpp
@@ -2324,12 +2324,8 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
switch (tree->TypeGet())
{
#if defined(FEATURE_SIMD)
- case TYP_LONG:
- case TYP_DOUBLE:
case TYP_SIMD8:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
-
if (vecCon->IsAllBitsSet())
{
emit->emitIns_R_I(INS_mvni, attr, targetReg, 0, INS_OPTS_2S);
diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp
index a706893053f..f5de4082325 100644
--- a/src/coreclr/jit/codegenarmarch.cpp
+++ b/src/coreclr/jit/codegenarmarch.cpp
@@ -4289,6 +4289,18 @@ void CodeGen::inst_SETCC(GenCondition condition, var_types type, regNumber dstRe
}
//------------------------------------------------------------------------
+// inst_JMP: Generate a jump instruction.
+//
+void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock)
+{
+#if !FEATURE_FIXED_OUT_ARGS
+ assert((tgtBlock->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed());
+#endif // !FEATURE_FIXED_OUT_ARGS
+
+ GetEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock);
+}
+
+//------------------------------------------------------------------------
// genCodeForStoreBlk: Produce code for a GT_STORE_OBJ/GT_STORE_DYN_BLK/GT_STORE_BLK node.
//
// Arguments:
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index b7555780229..ed16b9a9fa4 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -1944,11 +1944,12 @@ void CodeGen::genGenerateMachineCode()
#endif // DEBUG
/* We can now generate the function prolog and epilog */
-
genGeneratePrologsAndEpilogs();
- /* Bind jump distances */
+ // check to see if any jumps can be removed
+ GetEmitter()->emitRemoveJumpToNextInst();
+ /* Bind jump distances */
GetEmitter()->emitJumpDistBind();
#if FEATURE_LOOP_ALIGN
diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp
index d89217cdcda..6a44f1db324 100644
--- a/src/coreclr/jit/codegenlinear.cpp
+++ b/src/coreclr/jit/codegenlinear.cpp
@@ -753,7 +753,24 @@ void CodeGen::genCodeForBBlist()
break;
case BBJ_ALWAYS:
- inst_JMP(EJ_jmp, block->bbJumpDest);
+ inst_JMP(EJ_jmp, block->bbJumpDest
+#ifdef TARGET_AMD64
+ // AMD64 requires an instruction after a call instruction for unwinding
+ // inside an EH region so if the last instruction generated was a call instruction
+ // do not allow this jump to be marked for possible later removal.
+ //
+ // If a block was selected to place an alignment instruction because it ended
+ // with a jump, do not remove jumps from such blocks.
+ ,
+ /* isRemovableJmpCandidate */ !GetEmitter()->emitIsLastInsCall() && !block->hasAlign()
+#else
+#ifdef TARGET_XARCH
+ ,
+ /* isRemovableJmpCandidate */ !block->hasAlign()
+#endif
+
+#endif
+ );
FALLTHROUGH;
case BBJ_COND:
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index 97c884f0e41..039d4c11185 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -537,12 +537,8 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
switch (tree->TypeGet())
{
#if defined(FEATURE_SIMD)
- case TYP_LONG:
- case TYP_DOUBLE:
case TYP_SIMD8:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
-
simd8_t constValue = vecCon->gtSimd8Val;
CORINFO_FIELD_HANDLE hnd = emit->emitSimd8Const(constValue);
@@ -1441,6 +1437,30 @@ void CodeGen::inst_SETCC(GenCondition condition, var_types type, regNumber dstRe
}
//------------------------------------------------------------------------
+// inst_JMP: Generate a jump instruction.
+//
+void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock, bool isRemovableJmpCandidate)
+{
+#if !FEATURE_FIXED_OUT_ARGS
+ // On the x86 we are pushing (and changing the stack level), but on x64 and other archs we have
+ // a fixed outgoing args area that we store into and we never change the stack level when calling methods.
+ //
+ // Thus only on x86 do we need to assert that the stack level at the target block matches the current stack level.
+ //
+ CLANG_FORMAT_COMMENT_ANCHOR;
+
+#ifdef UNIX_X86_ABI
+ // bbTgtStkDepth is a (pure) argument count (stack alignment padding should be excluded).
+ assert((tgtBlock->bbTgtStkDepth * sizeof(int) == (genStackLevel - curNestedAlignment)) || isFramePointerUsed());
+#else
+ assert((tgtBlock->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed());
+#endif
+#endif // !FEATURE_FIXED_OUT_ARGS
+
+ GetEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock, 0, isRemovableJmpCandidate);
+}
+
+//------------------------------------------------------------------------
// genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
//
// Arguments:
diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index 5702221c022..2201c3a7d1e 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -9373,13 +9373,6 @@ void cTreeFlags(Compiler* comp, GenTree* tree)
}
break;
- case GT_INDEX:
-
- if (tree->gtFlags & GTF_INX_STRING_LAYOUT)
- {
- chars += printf("[INX_STRING_LAYOUT]");
- }
- FALLTHROUGH;
case GT_INDEX_ADDR:
if (tree->gtFlags & GTF_INX_RNGCHK)
{
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index ed2f3f55ce9..13a7791b18d 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -2587,7 +2587,19 @@ public:
GenTreeField* gtNewFieldRef(var_types type, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
- GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
+ GenTreeIndexAddr* gtNewIndexAddr(GenTree* arrayOp,
+ GenTree* indexOp,
+ var_types elemType,
+ CORINFO_CLASS_HANDLE elemClassHandle,
+ unsigned firstElemOffset,
+ unsigned lengthOffset);
+
+ GenTreeIndexAddr* gtNewArrayIndexAddr(GenTree* arrayOp,
+ GenTree* indexOp,
+ var_types elemType,
+ CORINFO_CLASS_HANDLE elemClassHandle);
+
+ GenTreeIndir* gtNewIndexIndir(GenTreeIndexAddr* indexAddr);
GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset, BasicBlock* block);
@@ -2758,6 +2770,7 @@ public:
GenTree* gtFoldExpr(GenTree* tree);
GenTree* gtFoldExprConst(GenTree* tree);
+ GenTree* gtFoldIndirConst(GenTreeIndir* indir);
GenTree* gtFoldExprSpecial(GenTree* tree);
GenTree* gtFoldBoxNullable(GenTree* tree);
GenTree* gtFoldExprCompare(GenTree* tree);
@@ -3260,6 +3273,19 @@ public:
bool lvaIsOriginalThisReadOnly(); // return true if there is no place in the code
// that writes to arg0
+#ifdef TARGET_X86
+ bool lvaIsArgAccessedViaVarArgsCookie(unsigned lclNum)
+ {
+ if (!info.compIsVarArgs)
+ {
+ return false;
+ }
+
+ LclVarDsc* varDsc = lvaGetDesc(lclNum);
+ return varDsc->lvIsParam && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg);
+ }
+#endif // TARGET_X86
+
// For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
// For ARM64, this is structs larger than 16 bytes that are passed by reference.
bool lvaIsImplicitByRefLocal(unsigned varNum)
@@ -5570,8 +5596,6 @@ private:
GenTree* fgMorphIntoHelperCall(
GenTree* tree, int helper, bool morphArgs, GenTree* arg1 = nullptr, GenTree* arg2 = nullptr);
- GenTree* fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
-
// A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
// it is useful to know whether the address will be immediately dereferenced, or whether the address value will
// be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
@@ -5616,13 +5640,15 @@ private:
Statement* fgPreviousCandidateSIMDFieldAsgStmt;
#endif // FEATURE_SIMD
- GenTree* fgMorphArrayIndex(GenTree* tree);
+ GenTree* fgMorphIndexAddr(GenTreeIndexAddr* tree);
GenTree* fgMorphExpandCast(GenTreeCast* tree);
GenTreeFieldList* fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl);
GenTreeCall* fgMorphArgs(GenTreeCall* call);
void fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg);
+ GenTree* fgMorphLocal(GenTreeLclVarCommon* lclNode);
+ GenTree* fgMorphExpandStackArgForVarArgs(GenTreeLclVarCommon* lclNode);
GenTree* fgMorphLocalVar(GenTree* tree, bool forceRemorph);
public:
@@ -5636,7 +5662,7 @@ private:
#endif
bool fgCheckStmtAfterTailCall();
GenTree* fgMorphTailCallViaHelpers(GenTreeCall* call, CORINFO_TAILCALL_HELPERS& help);
- bool fgCanTailCallViaJitHelper();
+ bool fgCanTailCallViaJitHelper(GenTreeCall* call);
void fgMorphTailCallViaJitHelper(GenTreeCall* call);
GenTree* fgCreateCallDispatcherAndGetResult(GenTreeCall* origCall,
CORINFO_METHOD_HANDLE callTargetStubHnd,
@@ -5682,7 +5708,7 @@ private:
GenTree* fgMorphInitBlock(GenTree* tree);
GenTree* fgMorphPromoteLocalInitBlock(GenTreeLclVar* destLclNode, GenTree* initVal, unsigned blockSize);
GenTree* fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
- GenTree* fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigned blockWidth, bool isBlkReqd);
+ GenTree* fgMorphBlockOperand(GenTree* tree, var_types asgType, ClassLayout* blockLayout, bool isBlkReqd);
GenTree* fgMorphCopyBlock(GenTree* tree);
GenTree* fgMorphStoreDynBlock(GenTreeStoreDynBlk* tree);
GenTree* fgMorphForRegisterFP(GenTree* tree);
@@ -7974,6 +8000,10 @@ private:
void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
+#ifdef DEBUG
+ void fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode);
+#endif // DEBUG
+
#endif // TARGET_AMD64 || (TARGET_X86 && FEATURE_EH_FUNCLETS)
UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp
index bda0cc6d73b..2fe7c10574c 100644
--- a/src/coreclr/jit/compiler.hpp
+++ b/src/coreclr/jit/compiler.hpp
@@ -1145,16 +1145,48 @@ inline GenTreeField* Compiler::gtNewFieldRef(var_types type, CORINFO_FIELD_HANDL
return fieldNode;
}
-/*****************************************************************************
- *
- * A little helper to create an array index node.
- */
+inline GenTreeIndexAddr* Compiler::gtNewIndexAddr(GenTree* arrayOp,
+ GenTree* indexOp,
+ var_types elemType,
+ CORINFO_CLASS_HANDLE elemClassHandle,
+ unsigned firstElemOffset,
+ unsigned lengthOffset)
+{
+ unsigned elemSize =
+ (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemClassHandle) : genTypeSize(elemType);
+
+ GenTreeIndexAddr* indexAddr = new (this, GT_INDEX_ADDR)
+ GenTreeIndexAddr(arrayOp, indexOp, elemType, elemClassHandle, elemSize, lengthOffset, firstElemOffset);
-inline GenTree* Compiler::gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp)
+ return indexAddr;
+}
+
+inline GenTreeIndexAddr* Compiler::gtNewArrayIndexAddr(GenTree* arrayOp,
+ GenTree* indexOp,
+ var_types elemType,
+ CORINFO_CLASS_HANDLE elemClassHandle)
{
- GenTreeIndex* gtIndx = new (this, GT_INDEX) GenTreeIndex(typ, arrayOp, indexOp, genTypeSize(typ));
+ unsigned lengthOffset = OFFSETOF__CORINFO_Array__length;
+ unsigned firstElemOffset = OFFSETOF__CORINFO_Array__data;
+
+ return gtNewIndexAddr(arrayOp, indexOp, elemType, elemClassHandle, firstElemOffset, lengthOffset);
+}
+
+inline GenTreeIndir* Compiler::gtNewIndexIndir(GenTreeIndexAddr* indexAddr)
+{
+ GenTreeIndir* index;
+ if (varTypeIsStruct(indexAddr->gtElemType))
+ {
+ index = gtNewObjNode(indexAddr->gtStructElemClass, indexAddr);
+ }
+ else
+ {
+ index = gtNewIndir(indexAddr->gtElemType, indexAddr);
+ }
+
+ index->gtFlags |= GTF_GLOB_REF;
- return gtIndx;
+ return index;
}
//------------------------------------------------------------------------------
diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp
index c7ac7b32e5e..f8c437e3266 100644
--- a/src/coreclr/jit/ee_il_dll.cpp
+++ b/src/coreclr/jit/ee_il_dll.cpp
@@ -1125,14 +1125,13 @@ void Compiler::eeDispLineInfos()
void Compiler::eeAllocMem(AllocMemArgs* args)
{
#ifdef DEBUG
- // Fake splitting implementation: hot section = hot code + 4K buffer + cold code
- const UNATIVE_OFFSET hotSizeRequest = args->hotCodeSize;
- const UNATIVE_OFFSET coldSizeRequest = args->coldCodeSize;
- const UNATIVE_OFFSET fakeSplittingBuffer = 4096;
+ const UNATIVE_OFFSET hotSizeRequest = args->hotCodeSize;
+ const UNATIVE_OFFSET coldSizeRequest = args->coldCodeSize;
+ // Fake splitting implementation: place hot/cold code in contiguous section
if (JitConfig.JitFakeProcedureSplitting() && (coldSizeRequest > 0))
{
- args->hotCodeSize = hotSizeRequest + fakeSplittingBuffer + coldSizeRequest;
+ args->hotCodeSize = hotSizeRequest + coldSizeRequest;
args->coldCodeSize = 0;
}
#endif
@@ -1143,8 +1142,8 @@ void Compiler::eeAllocMem(AllocMemArgs* args)
if (JitConfig.JitFakeProcedureSplitting() && (coldSizeRequest > 0))
{
// Fix up hot/cold code pointers
- args->coldCodeBlock = ((BYTE*)args->hotCodeBlock) + hotSizeRequest + fakeSplittingBuffer;
- args->coldCodeBlockRW = ((BYTE*)args->hotCodeBlockRW) + hotSizeRequest + fakeSplittingBuffer;
+ args->coldCodeBlock = ((BYTE*)args->hotCodeBlock) + hotSizeRequest;
+ args->coldCodeBlockRW = ((BYTE*)args->hotCodeBlockRW) + hotSizeRequest;
// Reset args' hot/cold code sizes in case caller reads them later
args->hotCodeSize = hotSizeRequest;
@@ -1161,13 +1160,6 @@ void Compiler::eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwind
printf("reserveUnwindInfo(isFunclet=%s, isColdCode=%s, unwindSize=0x%x)\n", isFunclet ? "true" : "false",
isColdCode ? "true" : "false", unwindSize);
}
-
- // Fake splitting currently does not handle unwind info for cold code
- if (isColdCode && JitConfig.JitFakeProcedureSplitting())
- {
- JITDUMP("reserveUnwindInfo for cold code with JitFakeProcedureSplitting enabled: ignoring cold unwind info\n");
- return;
- }
#endif // DEBUG
if (info.compMatchedVM)
@@ -1207,13 +1199,6 @@ void Compiler::eeAllocUnwindInfo(BYTE* pHotCode,
}
printf(")\n");
}
-
- // Fake splitting currently does not handle unwind info for cold code
- if (pColdCode && JitConfig.JitFakeProcedureSplitting())
- {
- JITDUMP("allocUnwindInfo for cold code with JitFakeProcedureSplitting enabled: ignoring cold unwind info\n");
- return;
- }
#endif // DEBUG
if (info.compMatchedVM)
diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp
index cd309ea308d..ebd4f212058 100644
--- a/src/coreclr/jit/emit.cpp
+++ b/src/coreclr/jit/emit.cpp
@@ -1006,6 +1006,15 @@ insGroup* emitter::emitSavIG(bool emitAdd)
assert(emitLastIns != nullptr);
assert(emitCurIGfreeBase <= (BYTE*)emitLastIns);
assert((BYTE*)emitLastIns < emitCurIGfreeBase + sz);
+
+#if defined(TARGET_XARCH)
+ assert(emitLastIns != nullptr);
+ if (emitLastIns->idIns() == INS_jmp)
+ {
+ ig->igFlags |= IGF_HAS_REMOVABLE_JMP;
+ }
+#endif
+
emitLastIns = (instrDesc*)((BYTE*)id + ((BYTE*)emitLastIns - (BYTE*)emitCurIGfreeBase));
}
@@ -1073,10 +1082,11 @@ void emitter::emitBegFN(bool hasFramePtr
emitJumpList = emitJumpLast = nullptr;
emitCurIGjmpList = nullptr;
- emitFwdJumps = false;
- emitNoGCRequestCount = 0;
- emitNoGCIG = false;
- emitForceNewIG = false;
+ emitFwdJumps = false;
+ emitNoGCRequestCount = 0;
+ emitNoGCIG = false;
+ emitForceNewIG = false;
+ emitContainsRemovableJmpCandidates = false;
#if FEATURE_LOOP_ALIGN
/* We don't have any align instructions */
@@ -3811,10 +3821,21 @@ void emitter::emitDispIG(insGroup* ig, insGroup* igPrev, bool verbose)
{
instrDesc* id = (instrDesc*)ins;
+#ifdef TARGET_XARCH
+ if (emitJmpInstHasNoCode(id))
+ {
+ // an instruction with no code prevents us being able to iterate to the
+ // next instructions so we must be certain that when we find one it is
+ // the last instruction in a group
+ assert(cnt == 1);
+ break;
+ }
+#endif
emitDispIns(id, false, true, false, ofs, nullptr, 0, ig);
ins += emitSizeOfInsDsc(id);
ofs += id->idCodeSize();
+
} while (--cnt);
printf("\n");
@@ -3864,6 +3885,29 @@ void emitter::emitDispGCinfo()
printf("\n\n");
}
+//------------------------------------------------------------------------
+// emitDispJumpList: displays the current emitter jump list
+//
+void emitter::emitDispJumpList()
+{
+ printf("Emitter Jump List:\n");
+ unsigned int jmpCount = 0;
+ for (instrDescJmp* jmp = emitJumpList; jmp != nullptr; jmp = jmp->idjNext)
+ {
+ printf("IG%02u IN%04x %3s[%u] -> IG%02u %s\n", jmp->idjIG->igNum, jmp->idDebugOnlyInfo()->idNum,
+ codeGen->genInsDisplayName(jmp), jmp->idCodeSize(),
+ ((insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel))->igNum,
+#if defined(TARGET_XARCH)
+ jmp->idjIsRemovableJmpCandidate ? " ; removal candidate" : ""
+#else
+ ""
+#endif
+ );
+ jmpCount += 1;
+ }
+ printf(" total jump count: %u\n", jmpCount);
+}
+
#endif // DEBUG
/*****************************************************************************
@@ -4102,6 +4146,205 @@ void emitter::emitDispCommentForHandle(size_t handle, GenTreeFlags flag)
#endif // DEBUG
}
+//****************************************************************************
+// emitRemoveJumpToNextInst: Checks all jumps in the jump list to see if they are
+// unconditional jumps marked with idjIsRemovableJmpCandidate,generated from
+// BBJ_ALWAYS blocks. Any such candidate that jumps to the next instruction
+// will be removed from the jump list.
+//
+// Assumptions:
+// the jump list must be ordered by increasing igNum+insNo
+//
+void emitter::emitRemoveJumpToNextInst()
+{
+#ifdef TARGET_XARCH
+ if (!emitContainsRemovableJmpCandidates)
+ {
+ return;
+ }
+
+ JITDUMP("*************** In emitRemoveJumpToNextInst()\n");
+#ifdef DEBUG
+ if (EMIT_INSTLIST_VERBOSE)
+ {
+ JITDUMP("\nInstruction group list before unconditional jump to next instruction removal:\n\n");
+ emitDispIGlist(true);
+ }
+ if (EMITVERBOSE)
+ {
+ emitDispJumpList();
+ }
+#endif // DEBUG
+
+ UNATIVE_OFFSET totalRemovedSize = 0;
+ instrDescJmp* jmp = emitJumpList;
+ instrDescJmp* previousJmp = nullptr;
+#if DEBUG
+ UNATIVE_OFFSET previousJumpIgNum = (UNATIVE_OFFSET)-1;
+ unsigned int previousJumpInsNum = -1;
+#endif // DEBUG
+
+ while (jmp)
+ {
+ insGroup* jmpGroup = jmp->idjIG;
+ instrDescJmp* nextJmp = jmp->idjNext;
+
+ if (jmp->idInsFmt() == IF_LABEL && emitIsUncondJump(jmp) && jmp->idjIsRemovableJmpCandidate)
+ {
+#if DEBUG
+ assert((jmpGroup->igFlags & IGF_HAS_ALIGN) == 0);
+ assert((jmpGroup->igNum > previousJumpIgNum) || (previousJumpIgNum == (UNATIVE_OFFSET)-1) ||
+ ((jmpGroup->igNum == previousJumpIgNum) && (jmp->idDebugOnlyInfo()->idNum > previousJumpInsNum)));
+ previousJumpIgNum = jmpGroup->igNum;
+ previousJumpInsNum = jmp->idDebugOnlyInfo()->idNum;
+#endif // DEBUG
+
+ // target group is not bound yet so use the cookie to fetch it
+ insGroup* targetGroup = (insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel);
+
+ assert(targetGroup != nullptr);
+
+ if ((jmpGroup->igNext == targetGroup) && ((jmpGroup->igFlags & IGF_HAS_REMOVABLE_JMP) != 0))
+ {
+ // the last instruction in the group is the jmp we're looking for
+ // and it jumps to the next instruction group so we don't need it
+ CLANG_FORMAT_COMMENT_ANCHOR
+
+#ifdef DEBUG
+ unsigned instructionCount = jmpGroup->igInsCnt;
+ assert(instructionCount > 0);
+ instrDesc* id = nullptr;
+ {
+ BYTE* dataPtr = jmpGroup->igData;
+ while (instructionCount > 0)
+ {
+ id = (instrDesc*)dataPtr;
+ dataPtr += emitSizeOfInsDsc(id);
+ instructionCount -= 1;
+ }
+ }
+ assert(id != nullptr);
+ if (jmp != id)
+ {
+ printf("jmp != id, dumping context information\n");
+ printf("method: %s\n", emitComp->impInlineRoot()->info.compMethodName);
+ printf(" jmp: %u: ", jmp->idDebugOnlyInfo()->idNum);
+ emitDispIns(jmp, false, true, false, 0, nullptr, 0, jmpGroup);
+ printf(" id: %u: ", id->idDebugOnlyInfo()->idNum);
+ emitDispIns(id, false, true, false, 0, nullptr, 0, jmpGroup);
+ printf("jump group:\n");
+ emitDispIG(jmpGroup, nullptr, true);
+ printf("target group:\n");
+ emitDispIG(targetGroup, nullptr, false);
+ assert(jmp == id);
+ }
+#endif // DEBUG
+
+ JITDUMP("IG%02u IN%04x is the last instruction in the group and jumps to the next instruction group "
+ "IG%02u %s, removing.\n",
+ jmpGroup->igNum, jmp->idDebugOnlyInfo()->idNum, targetGroup->igNum,
+ emitLabelString(targetGroup));
+
+ // Unlink the jump from emitJumpList while keeping the previousJmp the same.
+ if (previousJmp != nullptr)
+ {
+ previousJmp->idjNext = jmp->idjNext;
+ if (jmp == emitJumpLast)
+ {
+ emitJumpLast = previousJmp;
+ }
+ }
+ else
+ {
+ assert(jmp == emitJumpList);
+ emitJumpList = jmp->idjNext;
+ }
+
+ UNATIVE_OFFSET codeSize = jmp->idCodeSize();
+ jmp->idCodeSize(0);
+
+ jmpGroup->igSize -= (unsigned short)codeSize;
+ jmpGroup->igFlags |= IGF_UPD_ISZ;
+
+ emitTotalCodeSize -= codeSize;
+ totalRemovedSize += codeSize;
+ }
+ else
+ {
+ // Update the previousJmp
+ previousJmp = jmp;
+#if DEBUG
+ if (targetGroup == nullptr)
+ {
+ JITDUMP("IG%02u IN%04x jump target is not set!, keeping.\n", jmpGroup->igNum,
+ jmp->idDebugOnlyInfo()->idNum);
+ }
+ else if ((jmpGroup->igFlags & IGF_HAS_ALIGN) != 0)
+ {
+ JITDUMP("IG%02u IN%04x containing instruction group has alignment, keeping.\n", jmpGroup->igNum,
+ jmp->idDebugOnlyInfo()->idNum);
+ }
+ else if (jmpGroup->igNext != targetGroup)
+ {
+ JITDUMP("IG%02u IN%04x does not jump to the next instruction group, keeping.\n", jmpGroup->igNum,
+ jmp->idDebugOnlyInfo()->idNum);
+ }
+ else if ((jmpGroup->igFlags & IGF_HAS_REMOVABLE_JMP) == 0)
+ {
+ JITDUMP("IG%02u IN%04x containing instruction group is not marked with IGF_HAS_REMOVABLE_JMP, "
+ "keeping.\n",
+ jmpGroup->igNum, jmp->idDebugOnlyInfo()->idNum);
+ }
+#endif // DEBUG
+ }
+ }
+ else
+ {
+ // Update the previousJmp
+ previousJmp = jmp;
+ }
+
+ if (totalRemovedSize > 0)
+ {
+ insGroup* adjOffIG = jmpGroup->igNext;
+ insGroup* adjOffUptoIG = nextJmp != nullptr ? nextJmp->idjIG : emitIGlast;
+ while ((adjOffIG != nullptr) && (adjOffIG->igNum <= adjOffUptoIG->igNum))
+ {
+ JITDUMP("Adjusted offset of IG%02u from %04X to %04X\n", adjOffIG->igNum, adjOffIG->igOffs,
+ (adjOffIG->igOffs - totalRemovedSize));
+ adjOffIG->igOffs -= totalRemovedSize;
+ adjOffIG = adjOffIG->igNext;
+ }
+ }
+
+ jmp = nextJmp;
+ }
+
+#ifdef DEBUG
+ if (totalRemovedSize > 0)
+ {
+ emitCheckIGoffsets();
+
+ if (EMIT_INSTLIST_VERBOSE)
+ {
+ printf("\nInstruction group list after unconditional jump to next instruction removal:\n\n");
+ emitDispIGlist(false);
+ }
+ if (EMITVERBOSE)
+ {
+ emitDispJumpList();
+ }
+
+ JITDUMP("emitRemoveJumpToNextInst removed %u bytes of unconditional jumps\n", totalRemovedSize);
+ }
+ else
+ {
+ JITDUMP("emitRemoveJumpToNextInst removed no unconditional jumps\n");
+ }
+#endif // DEBUG
+#endif // TARGET_XARCH
+}
+
/*****************************************************************************
* Bind targets of relative jumps to choose the smallest possible encoding.
* X86 and AMD64 have a small and large encoding.
@@ -4126,6 +4369,10 @@ void emitter::emitJumpDistBind()
printf("\nInstruction list before jump distance binding:\n\n");
emitDispIGlist(true);
}
+ if (EMITVERBOSE)
+ {
+ emitDispJumpList();
+ }
#endif
instrDescJmp* jmp;
@@ -6617,7 +6864,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
#ifdef DEBUG
if (emitComp->opts.disAsm || emitComp->verbose)
{
- printf("\t\t\t\t\t\t;; size=%d bbWeight=%s PerfScore %.2f", ig->igSize, refCntWtd2str(ig->igWeight),
+ printf("\t\t\t\t\t\t;; size=%d bbWeight=%s PerfScore %.2f", (cp - bp), refCntWtd2str(ig->igWeight),
ig->igPerfScore);
}
*instrCount += ig->igInsCnt;
@@ -6638,10 +6885,13 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
{
// The allocated chunk is bigger than used, fill in unused space in it.
unsigned unusedSize = allocatedHotCodeSize - emitCurCodeOffs(cp);
+ BYTE* cpRW = cp + writeableOffset;
for (unsigned i = 0; i < unusedSize; ++i)
{
- *cp++ = DEFAULT_CODE_BUFFER_INIT;
+ *cpRW++ = DEFAULT_CODE_BUFFER_INIT;
}
+
+ cp = cpRW - writeableOffset;
assert(allocatedHotCodeSize == emitCurCodeOffs(cp));
}
}
diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h
index 18d57d13790..fc90bd96d69 100644
--- a/src/coreclr/jit/emit.h
+++ b/src/coreclr/jit/emit.h
@@ -279,6 +279,7 @@ struct insGroup
// IG, or, if this IG contains with an unconditional branch, some subsequent IG.
#define IGF_REMOVED_ALIGN 0x0800 // IG was marked as having an alignment instruction(s), but was later unmarked
// without updating the IG's size/offsets.
+#define IGF_HAS_REMOVABLE_JMP 0x1000 // this group ends with an unconditional jump which is a candidate for removal
// Mask of IGF_* flags that should be propagated to new blocks when they are created.
// This allows prologs and epilogs to be any number of IGs, but still be
@@ -1534,13 +1535,21 @@ protected:
BYTE* idjAddr; // address of jump ins (for patching)
} idjTemp;
- unsigned idjOffs : 30; // Before jump emission, this is the byte offset within IG of the jump instruction.
- // After emission, for forward jumps, this is the target offset -- in bytes from the
- // beginning of the function -- of the target instruction of the jump, used to
- // determine if this jump needs to be patched.
- unsigned idjShort : 1; // is the jump known to be a short one?
- unsigned idjKeepLong : 1; // should the jump be kept long? (used for
- // hot to cold and cold to hot jumps)
+ // Before jump emission, this is the byte offset within IG of the jump instruction.
+ // After emission, for forward jumps, this is the target offset -- in bytes from the
+ // beginning of the function -- of the target instruction of the jump, used to
+ // determine if this jump needs to be patched.
+ unsigned idjOffs :
+#if defined(TARGET_XARCH)
+ 29;
+ // indicates that the jump was added at the end of a BBJ_ALWAYS basic block and is
+ // a candidate for being removed if it jumps to the next instruction
+ unsigned idjIsRemovableJmpCandidate : 1;
+#else
+ 30;
+#endif
+ unsigned idjShort : 1; // is the jump known to be a short one?
+ unsigned idjKeepLong : 1; // should the jump be kept long? (used for hot to cold and cold to hot jumps)
};
#if FEATURE_LOOP_ALIGN
@@ -1723,6 +1732,7 @@ protected:
void emitDispIG(insGroup* ig, insGroup* igPrev = nullptr, bool verbose = false);
void emitDispIGlist(bool verbose = false);
void emitDispGCinfo();
+ void emitDispJumpList();
void emitDispClsVar(CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, bool reloc = false);
void emitDispFrameRef(int varx, int disp, int offs, bool asmfm);
void emitDispInsAddr(BYTE* code);
@@ -2001,6 +2011,8 @@ private:
instrDescJmp* emitJumpList; // list of local jumps in method
instrDescJmp* emitJumpLast; // last of local jumps in method
void emitJumpDistBind(); // Bind all the local jumps in method
+ bool emitContainsRemovableJmpCandidates;
+ void emitRemoveJumpToNextInst(); // try to remove unconditional jumps to the next instruction
#if FEATURE_LOOP_ALIGN
instrDescAlign* emitCurIGAlignList; // list of align instructions in current IG
@@ -2132,6 +2144,12 @@ private:
void emitEnableGC();
#endif // !defined(JIT32_GCENCODER)
+#if defined(TARGET_XARCH)
+ static bool emitAlignInstHasNoCode(instrDesc* id);
+ static bool emitInstHasNoCode(instrDesc* id);
+ static bool emitJmpInstHasNoCode(instrDesc* id);
+#endif
+
void emitGenIG(insGroup* ig);
insGroup* emitSavIG(bool emitAdd = false);
void emitNxtIG(bool extend = false);
diff --git a/src/coreclr/jit/emitarm.h b/src/coreclr/jit/emitarm.h
index 9dd2c175190..09133a1d88f 100644
--- a/src/coreclr/jit/emitarm.h
+++ b/src/coreclr/jit/emitarm.h
@@ -193,6 +193,12 @@ inline static unsigned getBitWidth(emitAttr size)
}
/************************************************************************/
+/* Output target-independent instructions */
+/************************************************************************/
+
+void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
+
+/************************************************************************/
/* The public entry points to output instructions */
/************************************************************************/
diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h
index 0279b3360e7..8970c15b3c0 100644
--- a/src/coreclr/jit/emitarm64.h
+++ b/src/coreclr/jit/emitarm64.h
@@ -706,6 +706,12 @@ inline static ssize_t computeRelPageAddr(size_t dstAddr, size_t srcAddr)
}
/************************************************************************/
+/* Output target-independent instructions */
+/************************************************************************/
+
+void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
+
+/************************************************************************/
/* The public entry points to output instructions */
/************************************************************************/
diff --git a/src/coreclr/jit/emitpub.h b/src/coreclr/jit/emitpub.h
index 02ab3bb879d..6fc2a787074 100644
--- a/src/coreclr/jit/emitpub.h
+++ b/src/coreclr/jit/emitpub.h
@@ -73,12 +73,6 @@ const char* emitOffsetToLabel(unsigned offs);
#endif // DEBUG
/************************************************************************/
-/* Output target-independent instructions */
-/************************************************************************/
-
-void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
-
-/************************************************************************/
/* Emit initialized data sections */
/************************************************************************/
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index a2f486d80cc..707c8fc25f7 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -2059,19 +2059,47 @@ const emitJumpKind emitReverseJumpKinds[] = {
return emitReverseJumpKinds[jumpKind];
}
-/*****************************************************************************
- * The size for these instructions is less than EA_4BYTE,
- * but the target register need not be byte-addressable
- */
+//------------------------------------------------------------------------
+// emitAlignInstHasNoCode: Returns true if the 'id' is an align instruction
+// that was later removed and hence has codeSize==0.
+//
+// Arguments:
+// id -- The instruction to check
+//
+/* static */ bool emitter::emitAlignInstHasNoCode(instrDesc* id)
+{
+ return (id->idIns() == INS_align) && (id->idCodeSize() == 0);
+}
-inline bool emitInstHasNoCode(instruction ins)
+//------------------------------------------------------------------------
+// emitJmpInstHasNoCode: Returns true if the 'id' is a jump instruction
+// that was later removed and hence has codeSize==0.
+//
+// Arguments:
+// id -- The instruction to check
+//
+/* static */ bool emitter::emitJmpInstHasNoCode(instrDesc* id)
{
- if (ins == INS_align)
- {
- return true;
- }
+ bool result = (id->idIns() == INS_jmp) && (id->idCodeSize() == 0);
- return false;
+ // A zero size jump instruction can only be the one that is marked
+ // as removable candidate.
+ assert(!result || ((instrDescJmp*)id)->idjIsRemovableJmpCandidate);
+
+ return result;
+}
+
+//------------------------------------------------------------------------
+// emitInstHasNoCode: Returns true if the 'id' is an instruction
+// that was later removed and hence has codeSize==0.
+// Currently it is one of `align` or `jmp`.
+//
+// Arguments:
+// id -- The instruction to check
+//
+/* static */ bool emitter::emitInstHasNoCode(instrDesc* id)
+{
+ return emitAlignInstHasNoCode(id) || emitJmpInstHasNoCode(id);
}
/*****************************************************************************
@@ -7464,7 +7492,10 @@ void emitter::emitSetShortJump(instrDescJmp* id)
* to jump: positive is forward, negative is backward.
*/
-void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount /* = 0 */)
+void emitter::emitIns_J(instruction ins,
+ BasicBlock* dst,
+ int instrCount /* = 0 */,
+ bool isRemovableJmpCandidate /* = false */)
{
UNATIVE_OFFSET sz;
instrDescJmp* id = emitNewInstrJmp();
@@ -7493,7 +7524,9 @@ void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount /* = 0
}
#endif // DEBUG
- id->idjShort = 0;
+ emitContainsRemovableJmpCandidates |= isRemovableJmpCandidate;
+ id->idjIsRemovableJmpCandidate = isRemovableJmpCandidate ? 1 : 0;
+ id->idjShort = 0;
if (dst != nullptr)
{
/* Assume the jump will be long */
@@ -9000,7 +9033,7 @@ void emitter::emitDispIns(
/* By now the size better be set to something */
- assert(id->idCodeSize() || emitInstHasNoCode(ins));
+ assert(id->idCodeSize() || emitInstHasNoCode(id));
/* Figure out the operand size */
@@ -13190,7 +13223,6 @@ BYTE* emitter::emitOutputIV(BYTE* dst, instrDesc* id)
* This function also handles non-jumps that have jump-like characteristics, like RIP-relative LEA of a label that
* needs to get bound to an actual address and processed by branch shortening.
*/
-
BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i)
{
unsigned srcOffs;
@@ -13665,11 +13697,18 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_RWR_LABEL:
case IF_SWR_LABEL:
assert(id->idGCref() == GCT_NONE);
- assert(id->idIsBound());
+ assert(id->idIsBound() || emitJmpInstHasNoCode(id));
// TODO-XArch-Cleanup: handle IF_RWR_LABEL in emitOutputLJ() or change it to emitOutputAM()?
- dst = emitOutputLJ(ig, dst, id);
- sz = (id->idInsFmt() == IF_SWR_LABEL ? sizeof(instrDescLbl) : sizeof(instrDescJmp));
+ if (id->idCodeSize() != 0)
+ {
+ dst = emitOutputLJ(ig, dst, id);
+ }
+ else
+ {
+ assert(((instrDescJmp*)id)->idjIsRemovableJmpCandidate);
+ }
+ sz = (id->idInsFmt() == IF_SWR_LABEL ? sizeof(instrDescLbl) : sizeof(instrDescJmp));
break;
case IF_METHOD:
@@ -14685,13 +14724,12 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
assert((int)emitCurStackLvl >= 0);
- // Only epilog "instructions" and some pseudo-instrs
- // are allowed not to generate any code
+ // Only epilog "instructions", some pseudo-instrs and blocks that ends with a jump to the next block
- assert(*dp != dst || emitInstHasNoCode(ins));
+ assert(*dp != dst || emitInstHasNoCode(id));
#ifdef DEBUG
- if (emitComp->opts.disAsm || emitComp->verbose)
+ if ((emitComp->opts.disAsm || emitComp->verbose) && !emitJmpInstHasNoCode(id))
{
emitDispIns(id, false, dspOffs, true, emitCurCodeOffs(*dp), *dp, (dst - *dp));
}
@@ -15462,6 +15500,20 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
break;
case INS_jmp:
+ if (emitInstHasNoCode(id))
+ {
+ // a removed jmp to the next instruction
+ result.insThroughput = PERFSCORE_THROUGHPUT_ZERO;
+ result.insLatency = PERFSCORE_LATENCY_ZERO;
+ }
+ else
+ {
+ // branch to a constant address
+ result.insThroughput = PERFSCORE_THROUGHPUT_2C;
+ result.insLatency = PERFSCORE_LATENCY_BRANCH_DIRECT;
+ }
+ break;
+
case INS_l_jmp:
// branch to a constant address
result.insThroughput = PERFSCORE_THROUGHPUT_2C;
diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h
index 2f218cfcb0d..754632bb1c0 100644
--- a/src/coreclr/jit/emitxarch.h
+++ b/src/coreclr/jit/emitxarch.h
@@ -302,6 +302,12 @@ inline emitAttr emitDecodeScale(unsigned ensz)
}
/************************************************************************/
+/* Output target-independent instructions */
+/************************************************************************/
+
+void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0, bool isRemovableJmpCandidate = false);
+
+/************************************************************************/
/* The public entry points to output instructions */
/************************************************************************/
diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp
index 228e01cbf5a..d0d4ae647ec 100644
--- a/src/coreclr/jit/fgopt.cpp
+++ b/src/coreclr/jit/fgopt.cpp
@@ -654,6 +654,7 @@ bool Compiler::fgRemoveDeadBlocks()
JITDUMP("\n*************** In fgRemoveDeadBlocks()");
jitstd::list<BasicBlock*> worklist(jitstd::allocator<void>(getAllocator(CMK_Reachability)));
+
worklist.push_back(fgFirstBB);
// Do not remove handler blocks
@@ -713,16 +714,43 @@ bool Compiler::fgRemoveDeadBlocks()
}
}
+ // Track if there is any unreachable block. Even if it is marked with
+ // BBF_DONT_REMOVE, fgRemoveUnreachableBlocks() still removes the code
+ // inside the block. So this variable tracks if we ever found such blocks
+ // or not.
+ bool hasUnreachableBlock = false;
+
// A block is unreachable if no path was found from
// any of the fgFirstBB, handler, filter or BBJ_ALWAYS (Arm) blocks.
auto isBlockRemovable = [&](BasicBlock* block) -> bool {
- return !BlockSetOps::IsMember(this, visitedBlocks, block->bbNum);
+ bool isVisited = BlockSetOps::IsMember(this, visitedBlocks, block->bbNum);
+ bool isRemovable = (!isVisited || block->bbRefs == 0);
+
+#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
+ isRemovable &=
+ !block->isBBCallAlwaysPairTail(); // can't remove the BBJ_ALWAYS of a BBJ_CALLFINALLY / BBJ_ALWAYS pair
+#endif
+ hasUnreachableBlock |= isRemovable;
+
+ return isRemovable;
};
- bool changed = fgRemoveUnreachableBlocks(isBlockRemovable);
+ bool changed = false;
+ unsigned iterationCount = 1;
+ do
+ {
+ JITDUMP("\nRemoving unreachable blocks for fgRemoveDeadBlocks iteration #%u\n", iterationCount);
+
+ // Just to be paranoid, avoid infinite loops; fall back to minopts.
+ if (iterationCount++ > 10)
+ {
+ noway_assert(!"Too many unreachable block removal loops");
+ }
+ changed = fgRemoveUnreachableBlocks(isBlockRemovable);
+ } while (changed);
#ifdef DEBUG
- if (verbose && changed)
+ if (verbose && hasUnreachableBlock)
{
printf("\nAfter dead block removal:\n");
fgDispBasicBlocks(verboseTrees);
@@ -732,7 +760,7 @@ bool Compiler::fgRemoveDeadBlocks()
fgVerifyHandlerTab();
fgDebugCheckBBlist(false);
#endif // DEBUG
- return changed;
+ return hasUnreachableBlock;
}
//-------------------------------------------------------------
diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp
index 0f70f0d619d..da1bcd79595 100644
--- a/src/coreclr/jit/flowgraph.cpp
+++ b/src/coreclr/jit/flowgraph.cpp
@@ -4152,10 +4152,9 @@ void Compiler::fgSetBlockOrder(BasicBlock* block)
}
break;
- case GT_INDEX:
case GT_INDEX_ADDR:
- // These two call CORINFO_HELP_RNGCHKFAIL for Debug code
- if (tree->gtFlags & GTF_INX_RNGCHK)
+ // This calls CORINFO_HELP_RNGCHKFAIL for Debug code.
+ if (tree->AsIndexAddr()->IsBoundsChecked())
{
return Compiler::WALK_ABORT;
}
diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index 85217814eb2..a42a7293403 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -256,7 +256,6 @@ void GenTree::InitNodeSize()
GenTree::s_gtNodeSizes[GT_CAST] = TREE_NODE_SZ_LARGE;
GenTree::s_gtNodeSizes[GT_FTN_ADDR] = TREE_NODE_SZ_LARGE;
GenTree::s_gtNodeSizes[GT_BOX] = TREE_NODE_SZ_LARGE;
- GenTree::s_gtNodeSizes[GT_INDEX] = TREE_NODE_SZ_LARGE;
GenTree::s_gtNodeSizes[GT_INDEX_ADDR] = TREE_NODE_SZ_LARGE;
GenTree::s_gtNodeSizes[GT_BOUNDS_CHECK] = TREE_NODE_SZ_SMALL;
GenTree::s_gtNodeSizes[GT_ARR_ELEM] = TREE_NODE_SZ_LARGE;
@@ -316,7 +315,6 @@ void GenTree::InitNodeSize()
static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node
- static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeIndexAddr) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_SMALL);
@@ -2495,12 +2493,6 @@ AGAIN:
return false;
}
break;
- case GT_INDEX:
- if (op1->AsIndex()->gtIndElemSize != op2->AsIndex()->gtIndElemSize)
- {
- return false;
- }
- break;
case GT_INDEX_ADDR:
if (op1->AsIndexAddr()->gtElemSize != op2->AsIndexAddr()->gtElemSize)
{
@@ -2856,10 +2848,7 @@ AGAIN:
}
case TYP_SIMD8:
- case TYP_DOUBLE:
- case TYP_LONG:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
add = genTreeHashAdd(ulo32(add), vecCon->gtSimd8Val.u32[1]);
add = genTreeHashAdd(ulo32(add), vecCon->gtSimd8Val.u32[0]);
break;
@@ -2873,7 +2862,6 @@ AGAIN:
}
add = genTreeHashAdd(ulo32(add), vecCon->GetSimdBaseType());
- add = genTreeHashAdd(ulo32(add), vecCon->GetSimdSize());
break;
}
@@ -2921,9 +2909,6 @@ AGAIN:
case GT_CAST:
hash ^= tree->AsCast()->gtCastType;
break;
- case GT_INDEX:
- hash += tree->AsIndex()->gtIndElemSize;
- break;
case GT_INDEX_ADDR:
hash += tree->AsIndexAddr()->gtElemSize;
break;
@@ -2993,7 +2978,6 @@ AGAIN:
// For the ones below no extra argument matters for comparison.
case GT_ARR_INDEX:
case GT_QMARK:
- case GT_INDEX:
case GT_INDEX_ADDR:
break;
@@ -3465,9 +3449,6 @@ unsigned Compiler::gtSetCallArgsOrder(CallArgs* args, bool lateArgs, int* callCo
//------------------------------------------------------------------------
// gtSetMultiOpOrder: Calculate the costs for a MultiOp.
//
-// Currently this function just preserves the previous behavior.
-// TODO-List-Cleanup: implement proper costing for these trees.
-//
// Arguments:
// multiOp - The MultiOp tree in question
//
@@ -3477,12 +3458,11 @@ unsigned Compiler::gtSetCallArgsOrder(CallArgs* args, bool lateArgs, int* callCo
//
unsigned Compiler::gtSetMultiOpOrder(GenTreeMultiOp* multiOp)
{
- // These default costs preserve previous behavior.
- // TODO-CQ: investigate opportunities for tuning them.
+ // Most HWI nodes are simple arithmetic operations.
+ //
int costEx = 1;
int costSz = 1;
unsigned level = 0;
- unsigned lvl2 = 0;
#if defined(FEATURE_HW_INTRINSICS)
if (multiOp->OperIs(GT_HWINTRINSIC))
@@ -3540,109 +3520,69 @@ unsigned Compiler::gtSetMultiOpOrder(GenTreeMultiOp* multiOp)
}
#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS)
- // This code is here to preserve previous behavior.
- switch (multiOp->GetOperandCount())
+ // The binary case is special because of GTF_REVERSE_OPS.
+ if (multiOp->GetOperandCount() == 2)
{
- case 0:
- // This is a constant HWIntrinsic, we already have correct costs.
- break;
+ unsigned lvl2 = 0;
- case 1:
- // A "unary" case.
+ // This way we have "level" be the complexity of the
+ // first tree to be evaluated, and "lvl2" - the second.
+ if (multiOp->IsReverseOp())
+ {
+ level = gtSetEvalOrder(multiOp->Op(2));
+ lvl2 = gtSetEvalOrder(multiOp->Op(1));
+ }
+ else
+ {
level = gtSetEvalOrder(multiOp->Op(1));
- costEx += multiOp->Op(1)->GetCostEx();
- costSz += multiOp->Op(1)->GetCostSz();
- break;
-
- case 2:
- // A "binary" case.
+ lvl2 = gtSetEvalOrder(multiOp->Op(2));
+ }
- // This way we have "level" be the complexity of the
- // first tree to be evaluated, and "lvl2" - the second.
- if (multiOp->IsReverseOp())
- {
- level = gtSetEvalOrder(multiOp->Op(2));
- lvl2 = gtSetEvalOrder(multiOp->Op(1));
- }
- else
- {
- level = gtSetEvalOrder(multiOp->Op(1));
- lvl2 = gtSetEvalOrder(multiOp->Op(2));
- }
+ // We want the more complex tree to be evaluated first.
+ if (level < lvl2)
+ {
+ bool canSwap = multiOp->IsReverseOp() ? gtCanSwapOrder(multiOp->Op(2), multiOp->Op(1))
+ : gtCanSwapOrder(multiOp->Op(1), multiOp->Op(2));
- // We want the more complex tree to be evaluated first.
- if (level < lvl2)
+ if (canSwap)
{
- bool canSwap = multiOp->IsReverseOp() ? gtCanSwapOrder(multiOp->Op(2), multiOp->Op(1))
- : gtCanSwapOrder(multiOp->Op(1), multiOp->Op(2));
-
- if (canSwap)
+ if (multiOp->IsReverseOp())
{
- if (multiOp->IsReverseOp())
- {
- multiOp->ClearReverseOp();
- }
- else
- {
- multiOp->SetReverseOp();
- }
-
- std::swap(level, lvl2);
+ multiOp->ClearReverseOp();
+ }
+ else
+ {
+ multiOp->SetReverseOp();
}
- }
- if (level < 1)
- {
- level = lvl2;
+ std::swap(level, lvl2);
}
- else if (level == lvl2)
- {
- level += 1;
- }
-
- costEx += (multiOp->Op(1)->GetCostEx() + multiOp->Op(2)->GetCostEx());
- costSz += (multiOp->Op(1)->GetCostSz() + multiOp->Op(2)->GetCostSz());
- break;
-
- default:
- // The former "ArgList" case... we'll be emulating it here.
- // The old implementation pushed the nodes on the list, in pre-order.
- // Then it popped and costed them in "reverse order", so that's what
- // we'll be doing here as well.
+ }
- unsigned nxtlvl = 0;
- for (size_t i = multiOp->GetOperandCount(); i >= 1; i--)
- {
- GenTree* op = multiOp->Op(i);
- unsigned lvl = gtSetEvalOrder(op);
+ if (level < 1)
+ {
+ level = lvl2;
+ }
+ else if (level == lvl2)
+ {
+ level += 1;
+ }
- if (lvl < 1)
- {
- level = nxtlvl;
- }
- else if (lvl == nxtlvl)
- {
- level = lvl + 1;
- }
- else
- {
- level = lvl;
- }
+ costEx += (multiOp->Op(1)->GetCostEx() + multiOp->Op(2)->GetCostEx());
+ costSz += (multiOp->Op(1)->GetCostSz() + multiOp->Op(2)->GetCostSz());
+ }
+ else
+ {
+ for (size_t i = multiOp->GetOperandCount(); i >= 1; i--)
+ {
+ GenTree* op = multiOp->Op(i);
+ unsigned lvl = gtSetEvalOrder(op);
- costEx += op->GetCostEx();
- costSz += op->GetCostSz();
+ level = max(lvl, level + 1);
- // Preserving previous behavior...
- CLANG_FORMAT_COMMENT_ANCHOR;
-#ifndef TARGET_XARCH
- if (op->GetCostSz() != 0)
- {
- costSz += 1;
- }
-#endif
- nxtlvl = level;
- }
- break;
+ costEx += op->GetCostEx();
+ costSz += op->GetCostSz();
+ }
}
multiOp->SetCosts(costEx, costSz);
@@ -4575,17 +4515,21 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
{
level = 0;
#if defined(TARGET_XARCH)
- /* We use fldz and fld1 to load 0.0 and 1.0, but all other */
- /* floating point constants are loaded using an indirection */
if (tree->IsFloatPositiveZero())
{
+ // We generate `xorp* tgtReg, tgtReg` which is 3-5 bytes
+ // but which can be elided by the instruction decoder.
+
costEx = 1;
- costSz = 1;
+ costSz = 2;
}
else
{
+ // We generate `movs* tgtReg, [mem]` which is 4-6 bytes
+ // and which has the same cost as an indirection.
+
costEx = IND_COST_EX;
- costSz = 4;
+ costSz = 2;
}
#elif defined(TARGET_ARM)
var_types targetType = tree->TypeGet();
@@ -4603,13 +4547,18 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
#elif defined(TARGET_ARM64)
if (tree->IsFloatPositiveZero() || emitter::emitIns_valid_imm_for_fmov(tree->AsDblCon()->gtDconVal))
{
+ // Zero and certain other immediates can be specially created with a single instruction
+ // These can be cheaply reconstituted but still take up 4-bytes of native codegen
+
costEx = 1;
- costSz = 1;
+ costSz = 2;
}
else
{
+ // We load the constant from memory and so will take the same cost as GT_IND
+
costEx = IND_COST_EX;
- costSz = 4;
+ costSz = 2;
}
#elif defined(TARGET_LOONGARCH64)
// TODO-LoongArch64-CQ: tune the costs.
@@ -4623,9 +4572,25 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
case GT_CNS_VEC:
{
- costEx = IND_COST_EX;
- costSz = 4;
- level = 0;
+ level = 0;
+
+ if (tree->AsVecCon()->IsAllBitsSet() || tree->AsVecCon()->IsZero())
+ {
+ // We generate `cmpeq* tgtReg, tgtReg`, which is 4-5 bytes, for AllBitsSet
+ // and generate `xorp* tgtReg, tgtReg`, which is 3-5 bytes, for Zero
+ // both of which can be elided by the instruction decoder.
+
+ costEx = 1;
+ costSz = 2;
+ }
+ else
+ {
+ // We generate `movup* tgtReg, [mem]` which is 4-6 bytes
+ // and which has the same cost as an indirection.
+
+ costEx = IND_COST_EX;
+ costSz = 2;
+ }
break;
}
@@ -4972,16 +4937,12 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
costSz += 1;
}
+#ifdef TARGET_ARM
if (isflt)
{
- if (tree->TypeGet() == TYP_DOUBLE)
- {
- costEx += 1;
- }
-#ifdef TARGET_ARM
costSz += 2;
-#endif // TARGET_ARM
}
+#endif // TARGET_ARM
// Can we form an addressing mode with this indirection?
// TODO-CQ: Consider changing this to op1->gtEffectiveVal() to take into account
@@ -6424,7 +6385,6 @@ bool GenTree::OperMayThrow(Compiler* comp)
case GT_ARR_OFFSET:
case GT_LCLHEAP:
case GT_CKFINITE:
- case GT_INDEX:
case GT_INDEX_ADDR:
return true;
@@ -6928,7 +6888,7 @@ GenTree* Compiler::gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle)
GenTreeVecCon* Compiler::gtNewVconNode(var_types type, CorInfoType simdBaseJitType)
{
- GenTreeVecCon* vecCon = new (this, GT_CNS_VEC) GenTreeVecCon(type, simdBaseJitType, genTypeSize(type));
+ GenTreeVecCon* vecCon = new (this, GT_CNS_VEC) GenTreeVecCon(type, simdBaseJitType);
return vecCon;
}
@@ -7353,15 +7313,15 @@ void Compiler::gtSetObjGcInfo(GenTreeObj* objNode)
}
//------------------------------------------------------------------------
-// gtNewStructVal: Return a node that represents a struct value
+// gtNewStructVal: Return a node that represents a struct or block value
//
// Arguments:
// layout - The struct's layout
// addr - The address of the struct
//
// Return Value:
-// An "OBJ" node, or "LCL_VAR" node if "addr" points to a local with
-// a layout compatible with "layout".
+// An "OBJ/BLK" node, or "LCL_VAR" node if "addr" points to a local
+// with a layout compatible with "layout".
//
GenTree* Compiler::gtNewStructVal(ClassLayout* layout, GenTree* addr)
{
@@ -7380,7 +7340,17 @@ GenTree* Compiler::gtNewStructVal(ClassLayout* layout, GenTree* addr)
}
}
- return gtNewObjNode(layout, addr);
+ GenTreeBlk* blkNode;
+ if (layout->IsBlockLayout())
+ {
+ blkNode = new (this, GT_BLK) GenTreeBlk(GT_BLK, layout->GetType(), addr, layout);
+ }
+ else
+ {
+ blkNode = gtNewObjNode(layout, addr);
+ }
+
+ return blkNode;
}
//------------------------------------------------------------------------
@@ -7392,31 +7362,13 @@ GenTree* Compiler::gtNewStructVal(ClassLayout* layout, GenTree* addr)
//
// Return Value:
// A block, object or local node that represents the block value pointed to by 'addr'.
-
+//
GenTree* Compiler::gtNewBlockVal(GenTree* addr, unsigned size)
{
- // By default we treat this as an opaque struct type with known size.
- var_types blkType = TYP_STRUCT;
- if (addr->gtOper == GT_ADDR)
- {
- GenTree* val = addr->gtGetOp1();
-#if FEATURE_SIMD
- if (varTypeIsSIMD(val) && (genTypeSize(val) == size))
- {
- blkType = val->TypeGet();
- }
-#endif // FEATURE_SIMD
- if (varTypeIsStruct(val) && val->OperIs(GT_LCL_VAR))
- {
- LclVarDsc* varDsc = lvaGetDesc(val->AsLclVarCommon());
- unsigned varSize = varTypeIsStruct(varDsc) ? varDsc->lvExactSize : genTypeSize(varDsc);
- if (varSize == size)
- {
- return val;
- }
- }
- }
- return new (this, GT_BLK) GenTreeBlk(GT_BLK, blkType, addr, typGetBlkLayout(size));
+ ClassLayout* layout = typGetBlkLayout(size);
+ GenTree* blkNode = gtNewStructVal(layout, addr);
+
+ return blkNode;
}
// Creates a new assignment node for a CpObj.
@@ -8314,15 +8266,6 @@ GenTree* Compiler::gtCloneExpr(
tree->AsCast()->gtCastType DEBUGARG(/*largeNode*/ TRUE));
break;
- case GT_INDEX:
- {
- GenTreeIndex* asInd = tree->AsIndex();
- copy = new (this, GT_INDEX)
- GenTreeIndex(asInd->TypeGet(), asInd->Arr(), asInd->Index(), asInd->gtIndElemSize);
- copy->AsIndex()->gtStructElemClass = asInd->gtStructElemClass;
- }
- break;
-
case GT_INDEX_ADDR:
{
GenTreeIndexAddr* asIndAddr = tree->AsIndexAddr();
@@ -10198,8 +10141,6 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_
}
FALLTHROUGH;
- case GT_INDEX:
- case GT_INDEX_ADDR:
case GT_FIELD:
if (tree->gtFlags & GTF_IND_VOLATILE)
{
@@ -10495,19 +10436,6 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_
{
layout = tree->AsLclFld()->GetLayout();
}
- else if (tree->OperIs(GT_INDEX))
- {
- GenTreeIndex* asInd = tree->AsIndex();
- CORINFO_CLASS_HANDLE clsHnd = asInd->gtStructElemClass;
- if (clsHnd != nullptr)
- {
- // We could create a layout with `typGetObjLayout(asInd->gtStructElemClass)` but we
- // don't want to affect the layout table.
- const unsigned classSize = info.compCompHnd->getClassSize(clsHnd);
- const char16_t* shortClassName = eeGetShortClassName(clsHnd);
- printf("<%S, %u>", shortClassName, classSize);
- }
- }
if (layout != nullptr)
{
@@ -10515,15 +10443,21 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_
}
}
- if (tree->OperIs(GT_ARR_ADDR))
+ if (tree->OperIs(GT_INDEX_ADDR, GT_ARR_ADDR))
{
- if (tree->AsArrAddr()->GetElemClassHandle() != NO_CLASS_HANDLE)
+ var_types elemType =
+ tree->OperIs(GT_INDEX_ADDR) ? tree->AsIndexAddr()->gtElemType : tree->AsArrAddr()->GetElemType();
+
+ CORINFO_CLASS_HANDLE elemClsHnd = tree->OperIs(GT_INDEX_ADDR) ? tree->AsIndexAddr()->gtStructElemClass
+ : tree->AsArrAddr()->GetElemClassHandle();
+
+ if (varTypeIsStruct(elemType) && (elemClsHnd != NO_CLASS_HANDLE))
{
- printf("%S[]", eeGetShortClassName(tree->AsArrAddr()->GetElemClassHandle()));
+ printf("%S[]", eeGetShortClassName(elemClsHnd));
}
else
{
- printf("%s[]", varTypeName(tree->AsArrAddr()->GetElemType()));
+ printf("%s[]", varTypeName(elemType));
}
}
@@ -11131,11 +11065,8 @@ void Compiler::gtDispConst(GenTree* tree)
switch (vecCon->TypeGet())
{
#if defined(FEATURE_SIMD)
- case TYP_LONG:
- case TYP_DOUBLE:
case TYP_SIMD8:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
simd8_t simdVal = vecCon->gtSimd8Val;
printf("<0x%08x, 0x%08x>", simdVal.u32[0], simdVal.u32[1]);
break;
@@ -13516,31 +13447,25 @@ GenTree* Compiler::gtFoldBoxNullable(GenTree* tree)
return tree;
}
- JITDUMP("\nAttempting to optimize BOX_NULLABLE(&x) %s null [%06u]\n", GenTree::OpName(oper), dspTreeID(tree));
+ JITDUMP("\nReplacing BOX_NULLABLE(&x) %s null [%06u] with x.hasValue\n", GenTree::OpName(oper), dspTreeID(tree));
- // Get the address of the struct being boxed
- GenTree* const arg = call->gtArgs.GetArgByIndex(1)->GetNode();
+ GenTree* nullableHndNode = call->gtArgs.GetArgByIndex(0)->GetNode();
+ CORINFO_CLASS_HANDLE nullableClassHnd = gtGetHelperArgClassHandle(nullableHndNode);
+ CORINFO_FIELD_HANDLE hasValueFieldHnd = info.compCompHnd->getFieldInClass(nullableClassHnd, 0);
- if (arg->OperIs(GT_ADDR))
- {
- CORINFO_CLASS_HANDLE nullableHnd = gtGetStructHandle(arg->AsOp()->gtOp1);
- CORINFO_FIELD_HANDLE fieldHnd = info.compCompHnd->getFieldInClass(nullableHnd, 0);
-
- // Replace the box with an access of the nullable 'hasValue' field.
- JITDUMP("\nSuccess: replacing BOX_NULLABLE(&x) [%06u] with x.hasValue\n", dspTreeID(op));
- GenTree* newOp = gtNewFieldRef(TYP_BOOL, fieldHnd, arg, 0);
+ GenTree* srcAddr = call->gtArgs.GetArgByIndex(1)->GetNode();
+ GenTree* fieldNode = gtNewFieldRef(TYP_BOOL, hasValueFieldHnd, srcAddr, OFFSETOF__CORINFO_NullableOfT__hasValue);
- if (op == op1)
- {
- tree->AsOp()->gtOp1 = newOp;
- }
- else
- {
- tree->AsOp()->gtOp2 = newOp;
- }
-
- cons->gtType = TYP_INT;
+ if (op == op1)
+ {
+ tree->AsOp()->gtOp1 = fieldNode;
}
+ else
+ {
+ tree->AsOp()->gtOp2 = fieldNode;
+ }
+
+ cons->gtType = TYP_INT;
return tree;
}
@@ -15145,6 +15070,48 @@ INTEGRAL_OVF:
#endif
//------------------------------------------------------------------------
+// gtFoldIndirConst: Attempt to fold an "IND(addr)" expression to a constant.
+//
+// Currently handles the case of "addr" being "INDEX_ADDR(CNS_STR, CONST)".
+//
+// Arguments:
+// indir - The IND node to attempt to fold
+//
+// Return Value:
+// The new constant node if the folding was successful, "nullptr" otherwise.
+//
+GenTree* Compiler::gtFoldIndirConst(GenTreeIndir* indir)
+{
+ assert(opts.OptimizationEnabled() && !optValnumCSE_phase);
+ assert(indir->OperIs(GT_IND));
+
+ GenTree* addr = indir->Addr();
+
+ if (indir->TypeIs(TYP_USHORT) && addr->OperIs(GT_INDEX_ADDR) && addr->AsIndexAddr()->Arr()->OperIs(GT_CNS_STR))
+ {
+ GenTreeStrCon* stringNode = addr->AsIndexAddr()->Arr()->AsStrCon();
+ GenTree* indexNode = addr->AsIndexAddr()->Index();
+ if (!stringNode->IsStringEmptyField() && indexNode->IsCnsIntOrI())
+ {
+ int cnsIndex = static_cast<int>(indexNode->AsIntConCommon()->IconValue());
+ if (cnsIndex >= 0)
+ {
+ const int maxStrSize = 1024;
+ char16_t str[maxStrSize];
+ int length =
+ info.compCompHnd->getStringLiteral(stringNode->gtScpHnd, stringNode->gtSconCPX, str, maxStrSize);
+ if (cnsIndex < length)
+ {
+ return gtNewIconNode(str[cnsIndex]);
+ }
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+//------------------------------------------------------------------------
// gtNewTempAssign: Create an assignment of the given value to a temp.
//
// Arguments:
@@ -15747,6 +15714,15 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
PushSideEffects(node);
return Compiler::WALK_SKIP_SUBTREES;
}
+
+ // TODO-ADDR: remove this quirk added to avoid diffs.
+ if (node->OperIs(GT_IND) && node->AsIndir()->Addr()->OperIs(GT_INDEX_ADDR) &&
+ !m_compiler->fgGlobalMorph)
+ {
+ JITDUMP("Keep the GT_INDEX_ADDR and GT_IND together:\n");
+ PushSideEffects(node);
+ return Compiler::WALK_SKIP_SUBTREES;
+ }
}
// Generally all GT_CALL nodes are considered to have side-effects.
@@ -17209,9 +17185,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
case GT_RET_EXPR:
structHnd = tree->AsRetExpr()->gtRetClsHnd;
break;
- case GT_INDEX:
- structHnd = tree->AsIndex()->gtStructElemClass;
- break;
case GT_FIELD:
info.compCompHnd->getFieldType(tree->AsField()->gtFldHnd, &structHnd);
break;
@@ -17262,25 +17235,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
if (addr->OperIs(GT_ARR_ADDR))
{
structHnd = addr->AsArrAddr()->GetElemClassHandle();
- break;
- }
-
- FieldSeqNode* fieldSeq = nullptr;
- if ((addr->OperGet() == GT_ADD) && addr->gtGetOp2()->OperIs(GT_CNS_INT))
- {
- fieldSeq = addr->gtGetOp2()->AsIntCon()->gtFieldSeq;
- }
- else
- {
- GetZeroOffsetFieldMap()->Lookup(addr, &fieldSeq);
- }
-
- if ((fieldSeq != nullptr) && (fieldSeq != FieldSeqStore::NotAField()))
- {
- fieldSeq = fieldSeq->GetTail();
-
- // Note we may have a primitive here (and correctly fail to obtain the handle)
- eeGetFieldType(fieldSeq->GetFieldHandle(), &structHnd);
}
}
break;
@@ -17551,13 +17505,19 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
objClass = lvaTable[objLcl].lvClassHnd;
*pIsExact = lvaTable[objLcl].lvClassIsExact;
}
- else if (base->OperGet() == GT_ARR_ELEM)
+ else if (base->OperIs(GT_INDEX_ADDR, GT_ARR_ELEM))
{
// indir(arr_elem(...)) -> array element type
- GenTree* array = base->AsArrElem()->gtArrObj;
+ if (base->OperIs(GT_INDEX_ADDR))
+ {
+ objClass = gtGetArrayElementClassHandle(base->AsIndexAddr()->Arr());
+ }
+ else
+ {
+ objClass = gtGetArrayElementClassHandle(base->AsArrElem()->gtArrObj);
+ }
- objClass = gtGetArrayElementClassHandle(array);
*pIsExact = false;
*pIsNonNull = false;
}
@@ -17613,16 +17573,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
break;
}
- case GT_INDEX:
- {
- GenTree* array = obj->AsIndex()->Arr();
-
- objClass = gtGetArrayElementClassHandle(array);
- *pIsExact = false;
- *pIsNonNull = false;
- break;
- }
-
default:
{
break;
@@ -23109,6 +23059,29 @@ uint16_t GenTreeLclVarCommon::GetLclOffs() const
}
}
+//------------------------------------------------------------------------
+// GetLayout: get the struct layout for a local node of struct type.
+//
+// Arguments:
+// compiler - the compiler instance
+//
+// Return Value:
+// If "this" is a local field node, the layout stored in the node,
+// otherwise the layout of local itself.
+//
+ClassLayout* GenTreeLclVarCommon::GetLayout(Compiler* compiler) const
+{
+ assert(varTypeIsStruct(TypeGet()));
+
+ if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR))
+ {
+ return compiler->lvaGetDesc(GetLclNum())->GetLayout();
+ }
+
+ assert(OperIs(GT_LCL_FLD, GT_STORE_LCL_FLD));
+ return AsLclFld()->GetLayout();
+}
+
#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS)
//------------------------------------------------------------------------
// GetResultOpNumForFMA: check if the result is written into one of the operands.
diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h
index 34ef15e8ebd..9aff6df4bed 100644
--- a/src/coreclr/jit/gentree.h
+++ b/src/coreclr/jit/gentree.h
@@ -505,9 +505,8 @@ enum GenTreeFlags : unsigned int
GTF_FLD_INITCLASS = 0x20000000, // GT_FIELD -- field access requires preceding class/static init helper
GTF_FLD_TGT_HEAP = 0x10000000, // GT_FIELD -- same as GTF_IND_TGT_HEAP
- GTF_INX_RNGCHK = 0x80000000, // GT_INDEX/GT_INDEX_ADDR -- the array reference should be range-checked.
- GTF_INX_STRING_LAYOUT = 0x40000000, // GT_INDEX -- this uses the special string array layout
- GTF_INX_NOFAULT = 0x20000000, // GT_INDEX -- the INDEX does not throw an exception (morph to GTF_IND_NONFAULTING)
+ GTF_INX_RNGCHK = 0x80000000, // GT_INDEX_ADDR -- this array address should be range-checked
+ GTF_INX_ADDR_NONNULL = 0x40000000, // GT_INDEX_ADDR -- this array address is not null
GTF_IND_TGT_NOT_HEAP = 0x80000000, // GT_IND -- the target is not on the heap
GTF_IND_VOLATILE = 0x40000000, // GT_IND -- the load or store must use volatile sematics (this is a nop on X86)
@@ -2078,6 +2077,17 @@ public:
gtFlags |= sourceFlags;
}
+ void AddAllEffectsFlags(GenTree* firstSource, GenTree* secondSource)
+ {
+ AddAllEffectsFlags((firstSource->gtFlags | secondSource->gtFlags) & GTF_ALL_EFFECT);
+ }
+
+ void AddAllEffectsFlags(GenTreeFlags sourceFlags)
+ {
+ assert((sourceFlags & ~GTF_ALL_EFFECT) == 0);
+ gtFlags |= sourceFlags;
+ }
+
inline bool IsCnsIntOrI() const;
inline bool IsIntegralConst() const;
@@ -3270,7 +3280,6 @@ private:
// size should be `gtType` and the handle should be looked up at callsites where required
unsigned char gtSimdBaseJitType; // SIMD vector base JIT type
- unsigned char gtSimdSize; // SIMD vector size in bytes
public:
CorInfoType GetSimdBaseJitType() const
@@ -3286,17 +3295,6 @@ public:
var_types GetSimdBaseType() const;
- unsigned char GetSimdSize() const
- {
- return gtSimdSize;
- }
-
- void SetSimdSize(unsigned simdSize)
- {
- gtSimdSize = (unsigned char)simdSize;
- assert(gtSimdSize == simdSize);
- }
-
#if defined(FEATURE_HW_INTRINSICS)
static bool IsHWIntrinsicCreateConstant(GenTreeHWIntrinsic* node, simd32_t& simd32Val);
@@ -3308,11 +3306,8 @@ public:
switch (gtType)
{
#if defined(FEATURE_SIMD)
- case TYP_LONG:
- case TYP_DOUBLE:
case TYP_SIMD8:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
return (gtSimd8Val.u64[0] == 0xFFFFFFFFFFFFFFFF);
}
@@ -3353,11 +3348,8 @@ public:
switch (gtType)
{
#if defined(FEATURE_SIMD)
- case TYP_LONG:
- case TYP_DOUBLE:
case TYP_SIMD8:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
return (left->gtSimd8Val.u64[0] == right->gtSimd8Val.u64[0]);
}
@@ -3395,11 +3387,8 @@ public:
switch (gtType)
{
#if defined(FEATURE_SIMD)
- case TYP_LONG:
- case TYP_DOUBLE:
case TYP_SIMD8:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
return (gtSimd8Val.u64[0] == 0x0000000000000000);
}
@@ -3428,14 +3417,11 @@ public:
}
}
- GenTreeVecCon(var_types type, CorInfoType simdBaseJitType, unsigned simdSize)
- : GenTree(GT_CNS_VEC, type)
- , gtSimdBaseJitType((unsigned char)simdBaseJitType)
- , gtSimdSize((unsigned char)simdSize)
+ GenTreeVecCon(var_types type, CorInfoType simdBaseJitType)
+ : GenTree(GT_CNS_VEC, type), gtSimdBaseJitType((unsigned char)simdBaseJitType)
{
assert(varTypeIsSIMD(type));
assert(gtSimdBaseJitType == simdBaseJitType);
- assert(gtSimdSize == simdSize);
}
#if DEBUGGABLE_GENTREE
@@ -3479,6 +3465,8 @@ public:
uint16_t GetLclOffs() const;
+ ClassLayout* GetLayout(Compiler* compiler) const;
+
unsigned GetSsaNum() const
{
return _gtSsaNum;
@@ -6253,50 +6241,9 @@ private:
};
#endif // FEATURE_HW_INTRINSICS
-/* gtIndex -- array access */
-
-struct GenTreeIndex : public GenTreeOp
-{
- GenTree*& Arr()
- {
- return gtOp1;
- }
- GenTree*& Index()
- {
- return gtOp2;
- }
-
- unsigned gtIndElemSize; // size of elements in the array
- CORINFO_CLASS_HANDLE gtStructElemClass; // If the element type is a struct, this is the struct type.
-
- GenTreeIndex(var_types type, GenTree* arr, GenTree* ind, unsigned indElemSize)
- : GenTreeOp(GT_INDEX, type, arr, ind)
- , gtIndElemSize(indElemSize)
- , gtStructElemClass(nullptr) // We always initialize this after construction.
- {
-#ifdef DEBUG
- if (JitConfig.JitSkipArrayBoundCheck() == 1)
- {
- // Skip bounds check
- }
- else
-#endif
- {
- // Do bounds check
- gtFlags |= GTF_INX_RNGCHK;
- }
-
- gtFlags |= GTF_EXCEPT | GTF_GLOB_REF;
- }
-#if DEBUGGABLE_GENTREE
- GenTreeIndex() : GenTreeOp()
- {
- }
-#endif
-};
-
-// gtIndexAddr: given an array object and an index, checks that the index is within the bounds of the array if
-// necessary and produces the address of the value at that index of the array.
+// GenTreeIndexAddr: Given an array object and an index, checks that the index is within the bounds of the array if
+// necessary and produces the address of the value at that index of the array.
+//
struct GenTreeIndexAddr : public GenTreeOp
{
GenTree*& Arr()
@@ -6332,6 +6279,7 @@ struct GenTreeIndexAddr : public GenTreeOp
, gtLenOffset(lenOffset)
, gtElemOffset(elemOffset)
{
+ assert(!varTypeIsStruct(elemType) || (structElemClass != NO_CLASS_HANDLE));
#ifdef DEBUG
if (JitConfig.JitSkipArrayBoundCheck() == 1)
{
@@ -6360,7 +6308,7 @@ struct GenTreeIndexAddr : public GenTreeOp
bool IsNotNull() const
{
- return IsBoundsChecked();
+ return IsBoundsChecked() || ((gtFlags & GTF_INX_ADDR_NONNULL) != 0);
}
};
@@ -6385,10 +6333,6 @@ public:
assert(addr->TypeIs(TYP_BYREF));
assert(((elemType == TYP_STRUCT) && (elemClassHandle != NO_CLASS_HANDLE)) ||
(elemClassHandle == NO_CLASS_HANDLE));
-
- // We will only consider "addr" for CSE. This is more profitable and precise
- // because ARR_ADDR can get its VN "polluted" by zero-offset field sequences.
- SetDoNotCSE();
}
#if DEBUGGABLE_GENTREE
@@ -6471,8 +6415,8 @@ struct GenTreeBoundsChk : public GenTreeOp
SpecialCodeKind gtThrowKind; // Kind of throw block to branch to on failure
// Store some information about the array element type that was in the GT_INDEX node before morphing.
- // Note that this information is also stored in the m_arrayInfoMap of the morphed IND node (that
- // is marked with GTF_IND_ARR_INDEX), but that can be hard to find.
+ // Note that this information is also stored in the ARR_ADDR node of the morphed tree, but that can
+ // be hard to find.
var_types gtInxType; // Save the GT_INDEX type
GenTreeBoundsChk(GenTree* index, GenTree* length, SpecialCodeKind kind)
@@ -8509,7 +8453,6 @@ inline GenTree* GenTree::gtGetOp1() const
case GT_RSZ:
case GT_ROL:
case GT_ROR:
- case GT_INDEX:
case GT_ASG:
case GT_EQ:
case GT_NE:
@@ -8520,6 +8463,7 @@ inline GenTree* GenTree::gtGetOp1() const
case GT_COMMA:
case GT_QMARK:
case GT_COLON:
+ case GT_INDEX_ADDR:
case GT_MKREFANY:
return true;
default:
diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h
index abc8faef2d7..a089124825f 100644
--- a/src/coreclr/jit/gtlist.h
+++ b/src/coreclr/jit/gtlist.h
@@ -148,11 +148,9 @@ GTNODE(COMMA , GenTreeOp ,0,GTK_BINOP|DBK_NOTLIR)
GTNODE(QMARK , GenTreeQmark ,0,GTK_BINOP|GTK_EXOP|DBK_NOTLIR)
GTNODE(COLON , GenTreeColon ,0,GTK_BINOP|DBK_NOTLIR)
-GTNODE(INDEX , GenTreeIndex ,0,GTK_BINOP|GTK_EXOP|DBK_NOTLIR) // SZ-array-element.
-GTNODE(INDEX_ADDR , GenTreeIndexAddr ,0,GTK_BINOP|GTK_EXOP) // Addr of SZ-array-element; used when aiming to minimize compile times.
-
+GTNODE(INDEX_ADDR , GenTreeIndexAddr ,0,GTK_BINOP|GTK_EXOP) // Address of SZ-array-element.
GTNODE(MKREFANY , GenTreeOp ,0,GTK_BINOP|DBK_NOTLIR)
-GTNODE(LEA , GenTreeAddrMode ,0,GTK_BINOP|GTK_EXOP)
+GTNODE(LEA , GenTreeAddrMode ,0,GTK_BINOP|GTK_EXOP|DBK_NOTHIR)
#if !defined(TARGET_64BIT)
// A GT_LONG node simply represents the long value produced by the concatenation
diff --git a/src/coreclr/jit/gtstructs.h b/src/coreclr/jit/gtstructs.h
index 1c4c554a052..038164cb2f7 100644
--- a/src/coreclr/jit/gtstructs.h
+++ b/src/coreclr/jit/gtstructs.h
@@ -72,7 +72,6 @@ GTSTRUCT_1(FieldList , GT_FIELD_LIST)
GTSTRUCT_1(Colon , GT_COLON)
GTSTRUCT_1(FptrVal , GT_FTN_ADDR)
GTSTRUCT_1(Intrinsic , GT_INTRINSIC)
-GTSTRUCT_1(Index , GT_INDEX)
GTSTRUCT_1(IndexAddr , GT_INDEX_ADDR)
#if defined(FEATURE_HW_INTRINSICS) && defined(FEATURE_SIMD)
GTSTRUCT_N(MultiOp , GT_SIMD, GT_HWINTRINSIC)
diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp
index 7c333303e48..0885892bcd6 100644
--- a/src/coreclr/jit/hwintrinsic.cpp
+++ b/src/coreclr/jit/hwintrinsic.cpp
@@ -314,6 +314,21 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp,
return NI_Throw_PlatformNotSupportedException;
}
+#if defined(TARGET_XARCH)
+ if ((isa == InstructionSet_Vector128) || (isa == InstructionSet_Vector256))
+#elif defined(TARGET_ARM64)
+ if ((isa == InstructionSet_Vector64) || (isa == InstructionSet_Vector128))
+#endif
+ {
+ if (!comp->IsBaselineSimdIsaSupported())
+ {
+ // Special case: For Vector64/128/256 we currently don't accelerate any of the methods when SSE/SSE2
+ // aren't supported since IsHardwareAccelerated reports false. To simplify the importation logic we'll
+ // just return illegal here and let it fallback to the software path instead.
+ return NI_Illegal;
+ }
+ }
+
for (int i = 0; i < (NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START - 1); i++)
{
const HWIntrinsicInfo& intrinsicInfo = hwIntrinsicInfoArray[i];
diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp
index edb2786459d..16d028215a1 100644
--- a/src/coreclr/jit/hwintrinsicarm64.cpp
+++ b/src/coreclr/jit/hwintrinsicarm64.cpp
@@ -325,11 +325,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
assert(category != HW_Category_Scalar);
assert(!HWIntrinsicInfo::isScalarIsa(HWIntrinsicInfo::lookupIsa(intrinsic)));
- if (!IsBaselineSimdIsaSupported())
- {
- return nullptr;
- }
-
assert(numArgs >= 0);
var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp
index 7b2155f9b48..177824bab03 100644
--- a/src/coreclr/jit/hwintrinsicxarch.cpp
+++ b/src/coreclr/jit/hwintrinsicxarch.cpp
@@ -550,11 +550,6 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic,
GenTree* op3 = nullptr;
GenTree* op4 = nullptr;
- if (!IsBaselineSimdIsaSupported())
- {
- return nullptr;
- }
-
CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsic);
if ((isa == InstructionSet_Vector256) && !compExactlyDependsOn(InstructionSet_AVX))
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 564d0ee845a..8065b8f5612 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -1137,7 +1137,7 @@ GenTree* Compiler::impAssignStruct(GenTree* dest,
}
assert(dest->gtOper == GT_LCL_VAR || dest->gtOper == GT_RETURN || dest->gtOper == GT_FIELD ||
- dest->gtOper == GT_IND || dest->gtOper == GT_OBJ || dest->gtOper == GT_INDEX);
+ dest->gtOper == GT_IND || dest->gtOper == GT_OBJ);
// Return a NOP if this is a self-assignment.
if (dest->OperGet() == GT_LCL_VAR && src->OperGet() == GT_LCL_VAR &&
@@ -1409,11 +1409,6 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr,
assert(src->AsObj()->GetLayout()->GetClassHandle() == structHnd);
}
}
- else if (src->gtOper == GT_INDEX)
- {
- asgType = impNormStructType(structHnd);
- assert(src->AsIndex()->gtStructElemClass == structHnd);
- }
else if (src->gtOper == GT_MKREFANY)
{
// Since we are assigning the result of a GT_MKREFANY,
@@ -1493,9 +1488,9 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr,
if ((dest == nullptr) && (destAddr->OperGet() == GT_ADDR))
{
GenTree* destNode = destAddr->gtGetOp1();
- // If the actual destination is a local, a GT_INDEX or a block node, or is a node that
- // will be morphed, don't insert an OBJ(ADDR) if it already has the right type.
- if (destNode->OperIs(GT_LCL_VAR, GT_INDEX) || destNode->OperIsBlk())
+ // If the actual destination is a local, or a block node,
+ // don't insert an OBJ(ADDR) if it already has the right type.
+ if (destNode->OperIs(GT_LCL_VAR) || destNode->OperIsBlk())
{
var_types destType = destNode->TypeGet();
// If one or both types are TYP_STRUCT (one may not yet be normalized), they are compatible
@@ -1706,7 +1701,7 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoTyp
// it is either:
// - a known struct type (non-TYP_STRUCT, e.g. TYP_SIMD8)
// - an OBJ or a MKREFANY node, or
-// - a node (e.g. GT_INDEX) that will be morphed.
+// - a node (e.g. GT_FIELD) that will be morphed.
// If the node is a CALL or RET_EXPR, a copy will be made to a new temp.
//
GenTree* Compiler::impNormStructVal(GenTree* structVal,
@@ -1745,13 +1740,6 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal,
makeTemp = true;
break;
- case GT_INDEX:
- // This will be transformed to an OBJ later.
- alreadyNormalized = true;
- structVal->AsIndex()->gtStructElemClass = structHnd;
- structVal->AsIndex()->gtIndElemSize = info.compCompHnd->getClassSize(structHnd);
- break;
-
case GT_FIELD:
// Wrap it in a GT_OBJ, if needed.
structVal->gtType = structType;
@@ -3910,10 +3898,11 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
case NI_System_String_get_Chars:
{
- GenTree* op2 = impPopStack().val;
- GenTree* op1 = impPopStack().val;
- retNode = gtNewIndexRef(TYP_USHORT, op1, op2);
- retNode->gtFlags |= GTF_INX_STRING_LAYOUT;
+ GenTree* op2 = impPopStack().val;
+ GenTree* op1 = impPopStack().val;
+ GenTree* addr = gtNewIndexAddr(op1, op2, TYP_USHORT, NO_CLASS_HANDLE, OFFSETOF__CORINFO_String__chars,
+ OFFSETOF__CORINFO_String__stringLen);
+ retNode = gtNewIndexIndir(addr->AsIndexAddr());
break;
}
@@ -12867,7 +12856,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
}
CORINFO_CLASS_HANDLE clsHnd = DUMMY_INIT(NULL);
- CORINFO_CLASS_HANDLE ldelemClsHnd = DUMMY_INIT(NULL);
+ CORINFO_CLASS_HANDLE ldelemClsHnd = NO_CLASS_HANDLE;
CORINFO_CLASS_HANDLE stelemClsHnd = DUMMY_INIT(NULL);
var_types lclTyp, ovflType = TYP_UNKNOWN;
@@ -12936,7 +12925,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
CORINFO_SIG_INFO sig;
IL_OFFSET jmpAddr;
bool ovfl, unordered, callNode;
- bool ldstruct;
CORINFO_CLASS_HANDLE tokenType;
union {
@@ -13634,13 +13622,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)
case CEE_LDELEM_I:
lclTyp = TYP_I_IMPL;
goto ARR_LD;
-
- // Should be UINT, but since no platform widens 4->8 bytes it doesn't matter
- // and treating it as TYP_INT avoids other asserts.
case CEE_LDELEM_U4:
lclTyp = TYP_INT;
goto ARR_LD;
-
case CEE_LDELEM_I4:
lclTyp = TYP_INT;
goto ARR_LD;
@@ -13666,84 +13650,32 @@ void Compiler::impImportBlockCode(BasicBlock* block)
ARR_LD:
ARR_LD_POST_VERIFY:
- /* Pull the index value and array address */
- op2 = impPopStack().val;
- op1 = impPopStack().val;
- assertImp(op1->gtType == TYP_REF);
+ op2 = impPopStack().val; // index
+ op1 = impPopStack().val; // array
+ assertImp(op1->TypeIs(TYP_REF));
- /* Check for null pointer - in the inliner case we simply abort */
-
- if (compIsForInlining())
+ // Check for null pointer - in the inliner case we simply abort.
+ if (compIsForInlining() && op1->IsCnsIntOrI())
{
- if (op1->gtOper == GT_CNS_INT)
- {
- compInlineResult->NoteFatal(InlineObservation::CALLEE_HAS_NULL_FOR_LDELEM);
- return;
- }
+ compInlineResult->NoteFatal(InlineObservation::CALLEE_HAS_NULL_FOR_LDELEM);
+ return;
}
- /* Mark the block as containing an index expression */
+ // Mark the block as containing an index expression.
- if (op1->gtOper == GT_LCL_VAR)
+ if (op1->OperIs(GT_LCL_VAR) && op2->OperIs(GT_LCL_VAR, GT_CNS_INT, GT_ADD))
{
- if (op2->gtOper == GT_LCL_VAR || op2->gtOper == GT_CNS_INT || op2->gtOper == GT_ADD)
- {
- block->bbFlags |= BBF_HAS_IDX_LEN;
- optMethodFlags |= OMF_HAS_ARRAYREF;
- }
+ block->bbFlags |= BBF_HAS_IDX_LEN;
+ optMethodFlags |= OMF_HAS_ARRAYREF;
}
- /* Create the index node and push it on the stack */
-
- op1 = gtNewIndexRef(lclTyp, op1, op2);
-
- ldstruct = (opcode == CEE_LDELEM && lclTyp == TYP_STRUCT);
+ op1 = gtNewArrayIndexAddr(op1, op2, lclTyp, ldelemClsHnd);
- if ((opcode == CEE_LDELEMA) || ldstruct ||
- (ldelemClsHnd != DUMMY_INIT(NULL) && eeIsValueClass(ldelemClsHnd)))
+ if (opcode != CEE_LDELEMA)
{
- assert(ldelemClsHnd != DUMMY_INIT(NULL));
-
- // remember the element size
- if (lclTyp == TYP_REF)
- {
- op1->AsIndex()->gtIndElemSize = TARGET_POINTER_SIZE;
- }
- else
- {
- // If ldElemClass is precisely a primitive type, use that, otherwise, preserve the struct type.
- if (info.compCompHnd->getTypeForPrimitiveValueClass(ldelemClsHnd) == CORINFO_TYPE_UNDEF)
- {
- op1->AsIndex()->gtStructElemClass = ldelemClsHnd;
- }
- assert(lclTyp != TYP_STRUCT || op1->AsIndex()->gtStructElemClass != nullptr);
- if (lclTyp == TYP_STRUCT)
- {
- size = info.compCompHnd->getClassSize(ldelemClsHnd);
- op1->AsIndex()->gtIndElemSize = size;
- op1->gtType = lclTyp;
- }
- }
-
- if ((opcode == CEE_LDELEMA) || ldstruct)
- {
- // wrap it in a &
- lclTyp = TYP_BYREF;
-
- op1 = gtNewOperNode(GT_ADDR, lclTyp, op1);
- }
- else
- {
- assert(lclTyp != TYP_STRUCT);
- }
+ op1 = gtNewIndexIndir(op1->AsIndexAddr());
}
- if (ldstruct)
- {
- // Create an OBJ for the result
- op1 = gtNewObjNode(ldelemClsHnd, op1);
- op1->gtFlags |= GTF_EXCEPT;
- }
impPushOnStack(op1, tiRetVal);
break;
@@ -13768,7 +13700,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
{
CorInfoType jitTyp = info.compCompHnd->asCorInfoType(stelemClsHnd);
lclTyp = JITtype2varType(jitTyp);
- goto ARR_ST_POST_VERIFY;
+ goto ARR_ST;
}
case CEE_STELEM_REF:
@@ -13785,7 +13717,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
if (impCanSkipCovariantStoreCheck(value, array))
{
lclTyp = TYP_REF;
- goto ARR_ST_POST_VERIFY;
+ goto ARR_ST;
}
}
@@ -13819,7 +13751,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
goto ARR_ST;
ARR_ST:
- ARR_ST_POST_VERIFY:
+ // TODO-Review: this comment is no longer correct.
/* The strict order of evaluation is LHS-operands, RHS-operands,
range-check, and then assignment. However, codegen currently
does the range-check before evaluation the RHS-operands. So to
@@ -13831,45 +13763,29 @@ void Compiler::impImportBlockCode(BasicBlock* block)
"Strict ordering of exceptions for Array store"));
}
- /* Pull the new value from the stack */
+ // Pull the new value from the stack.
op2 = impPopStack().val;
+ impBashVarAddrsToI(op2);
- /* Pull the index value */
+ // Pull the index value.
op1 = impPopStack().val;
- /* Pull the array address */
+ // Pull the array address.
op3 = impPopStack().val;
-
- assertImp(op3->gtType == TYP_REF);
- if (op2->IsLocalAddrExpr() != nullptr)
- {
- op2->gtType = TYP_I_IMPL;
- }
+ assertImp(op3->TypeIs(TYP_REF));
// Mark the block as containing an index expression
-
- if (op3->gtOper == GT_LCL_VAR)
+ if (op3->OperIs(GT_LCL_VAR) && op1->OperIs(GT_LCL_VAR, GT_CNS_INT, GT_ADD))
{
- if (op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_CNS_INT || op1->gtOper == GT_ADD)
- {
- block->bbFlags |= BBF_HAS_IDX_LEN;
- optMethodFlags |= OMF_HAS_ARRAYREF;
- }
+ block->bbFlags |= BBF_HAS_IDX_LEN;
+ optMethodFlags |= OMF_HAS_ARRAYREF;
}
- /* Create the index node */
-
- op1 = gtNewIndexRef(lclTyp, op3, op1);
+ // Create the index node.
+ op1 = gtNewArrayIndexAddr(op3, op1, lclTyp, stelemClsHnd);
+ op1 = gtNewIndexIndir(op1->AsIndexAddr());
- /* Create the assignment node and append it */
-
- if (lclTyp == TYP_STRUCT)
- {
- assert(stelemClsHnd != DUMMY_INIT(NULL));
-
- op1->AsIndex()->gtStructElemClass = stelemClsHnd;
- op1->AsIndex()->gtIndElemSize = info.compCompHnd->getClassSize(stelemClsHnd);
- }
+ // Create the assignment node and append it.
if (varTypeIsStruct(op1))
{
op1 = impAssignStruct(op1, op2, stelemClsHnd, (unsigned)CHECK_SPILL_ALL);
@@ -13879,11 +13795,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
op2 = impImplicitR4orR8Cast(op2, op1->TypeGet());
op1 = gtNewAssignNode(op1, op2);
}
-
- /* Mark the expression as containing an assignment */
-
- op1->gtFlags |= GTF_ASG;
-
goto SPILL_APPEND;
case CEE_ADD:
@@ -22640,14 +22551,14 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array)
assert(opts.OptimizationEnabled());
// Check for assignment to same array, ie. arrLcl[i] = arrLcl[j]
- if (value->OperIs(GT_INDEX) && array->OperIs(GT_LCL_VAR))
+ if (value->OperIs(GT_IND) && value->AsIndir()->Addr()->OperIs(GT_INDEX_ADDR) && array->OperIs(GT_LCL_VAR))
{
- GenTree* valueIndex = value->AsIndex()->Arr();
- if (valueIndex->OperIs(GT_LCL_VAR))
+ GenTree* valueArray = value->AsIndir()->Addr()->AsIndexAddr()->Arr();
+ if (valueArray->OperIs(GT_LCL_VAR))
{
- unsigned valueLcl = valueIndex->AsLclVar()->GetLclNum();
- unsigned arrayLcl = array->AsLclVar()->GetLclNum();
- if ((valueLcl == arrayLcl) && !lvaGetDesc(arrayLcl)->IsAddressExposed())
+ unsigned valueArrayLcl = valueArray->AsLclVar()->GetLclNum();
+ unsigned arrayLcl = array->AsLclVar()->GetLclNum();
+ if ((valueArrayLcl == arrayLcl) && !lvaGetDesc(arrayLcl)->IsAddressExposed())
{
JITDUMP("\nstelem of ref from same array: skipping covariant store check\n");
return true;
diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp
index 4a3ab3e41ba..9843482bbef 100644
--- a/src/coreclr/jit/instr.cpp
+++ b/src/coreclr/jit/instr.cpp
@@ -258,32 +258,6 @@ bool CodeGenInterface::instIsFP(instruction ins)
/*****************************************************************************
*
- * Generate a jump instruction.
- */
-
-void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock)
-{
-#if !FEATURE_FIXED_OUT_ARGS
- // On the x86 we are pushing (and changing the stack level), but on x64 and other archs we have
- // a fixed outgoing args area that we store into and we never change the stack level when calling methods.
- //
- // Thus only on x86 do we need to assert that the stack level at the target block matches the current stack level.
- //
- CLANG_FORMAT_COMMENT_ANCHOR;
-
-#ifdef UNIX_X86_ABI
- // bbTgtStkDepth is a (pure) argument count (stack alignment padding should be excluded).
- assert((tgtBlock->bbTgtStkDepth * sizeof(int) == (genStackLevel - curNestedAlignment)) || isFramePointerUsed());
-#else
- assert((tgtBlock->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed());
-#endif
-#endif // !FEATURE_FIXED_OUT_ARGS
-
- GetEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock);
-}
-
-/*****************************************************************************
- *
* Generate a set instruction.
*/
@@ -843,11 +817,8 @@ CodeGen::OperandDesc CodeGen::genOperandDesc(GenTree* op)
switch (op->TypeGet())
{
#if defined(FEATURE_SIMD)
- case TYP_LONG:
- case TYP_DOUBLE:
case TYP_SIMD8:
{
- // TODO-1stClassStructs: do not retype SIMD nodes
simd8_t constValue = op->AsVecCon()->gtSimd8Val;
return OperandDesc(emit->emitSimd8Const(constValue));
}
diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h
index 29e977cf1d8..dbf4b6069fc 100644
--- a/src/coreclr/jit/jitconfigvalues.h
+++ b/src/coreclr/jit/jitconfigvalues.h
@@ -196,11 +196,6 @@ CONFIG_INTEGER(JitDumpInlinePhases, W("JitDumpInlinePhases"), 1) // Dump inline
CONFIG_METHODSET(JitEHDump, W("JitEHDump")) // Dump the EH table for the method, as reported to the VM
CONFIG_METHODSET(JitExclude, W("JitExclude"))
CONFIG_INTEGER(JitFakeProcedureSplitting, W("JitFakeProcedureSplitting"), 0) // Do code splitting independent of VM.
- // For now, this disables unwind info for
- // cold sections, breaking stack walks.
- // Set COMPlus_GCgen0size=1000000 to avoid
- // running the GC, which requires
- // stack-walking.
CONFIG_METHODSET(JitForceProcedureSplitting, W("JitForceProcedureSplitting"))
CONFIG_METHODSET(JitGCDump, W("JitGCDump"))
CONFIG_METHODSET(JitDebugDump, W("JitDebugDump"))
diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp
index 4fd10a2cd75..25074f88274 100644
--- a/src/coreclr/jit/lclmorph.cpp
+++ b/src/coreclr/jit/lclmorph.cpp
@@ -608,17 +608,27 @@ private:
bool hasHiddenStructArg = false;
if (m_compiler->opts.compJitOptimizeStructHiddenBuffer)
{
- if (varTypeIsStruct(varDsc) && varDsc->lvIsTemp)
+ // We will only attempt this optimization for locals that are:
+ // a) Not susceptible to liveness bugs (see "lvaSetHiddenBufferStructArg").
+ // b) Do not later turn into indirections.
+ //
+ bool isSuitableLocal =
+ varTypeIsStruct(varDsc) && varDsc->lvIsTemp && !m_compiler->lvaIsImplicitByRefLocal(val.LclNum());
+#ifdef TARGET_X86
+ if (m_compiler->lvaIsArgAccessedViaVarArgsCookie(val.LclNum()))
{
- if ((callTree != nullptr) && callTree->gtArgs.HasRetBuffer() &&
- (val.Node() == callTree->gtArgs.GetRetBufferArg()->GetNode()))
- {
- assert(!exposeParentLcl);
+ isSuitableLocal = false;
+ }
+#endif // TARGET_X86
- m_compiler->lvaSetHiddenBufferStructArg(val.LclNum());
- hasHiddenStructArg = true;
- callTree->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG_LCLOPT;
- }
+ if (isSuitableLocal && (callTree != nullptr) && callTree->gtArgs.HasRetBuffer() &&
+ (val.Node() == callTree->gtArgs.GetRetBufferArg()->GetNode()))
+ {
+ assert(!exposeParentLcl);
+
+ m_compiler->lvaSetHiddenBufferStructArg(val.LclNum());
+ hasHiddenStructArg = true;
+ callTree->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG_LCLOPT;
}
}
@@ -786,17 +796,12 @@ private:
}
// The LHS may be a LCL_VAR/LCL_FLD, these are not indirections so we need to handle them here.
- // It can also be a GT_INDEX, this is an indirection but it never applies to lclvar addresses
- // so it needs to be handled here as well.
-
switch (indir->OperGet())
{
case GT_LCL_VAR:
return m_compiler->lvaGetDesc(indir->AsLclVar())->lvExactSize;
case GT_LCL_FLD:
return genTypeSize(indir->TypeGet());
- case GT_INDEX:
- return indir->AsIndex()->gtIndElemSize;
default:
break;
}
@@ -838,15 +843,6 @@ private:
return;
}
-#ifdef TARGET_X86
- if (m_compiler->info.compIsVarArgs && varDsc->lvIsParam && !varDsc->lvIsRegArg)
- {
- // TODO-ADDR: For now we ignore all stack parameters of varargs methods,
- // fgMorphStackArgForVarArgs does not handle LCL_VAR|FLD_ADDR nodes.
- return;
- }
-#endif
-
GenTree* addr = val.Node();
if (val.Offset() > UINT16_MAX)
@@ -1029,15 +1025,6 @@ private:
return IndirTransform::None;
}
-#ifdef TARGET_X86
- if (m_compiler->info.compIsVarArgs && varDsc->lvIsParam && !varDsc->lvIsRegArg)
- {
- // TODO-ADDR: For now we ignore all stack parameters of varargs methods,
- // fgMorphStackArgForVarArgs does not handle LCL_FLD nodes.
- return IndirTransform::None;
- }
-#endif
-
// As we are only handling non-promoted STRUCT locals right now, the only
// possible transformation for non-STRUCT indirect uses is LCL_FLD.
if (!varTypeIsStruct(indir))
@@ -1063,11 +1050,10 @@ private:
return IndirTransform::None;
}
- if ((user == nullptr) || !user->OperIs(GT_ASG))
+ if ((user == nullptr) || !user->OperIs(GT_ASG, GT_RETURN))
{
- // TODO-ADDR: Skip TYP_STRUCT indirs for now, unless they're used by an ASG.
- // At least call args will require extra work because currently they must be
- // wrapped in OBJ nodes so we can't replace those with local nodes.
+ // TODO-ADDR: call args require extra work because currently they must
+ // be wrapped in OBJ nodes so we can't replace those with local nodes.
return IndirTransform::None;
}
@@ -1113,26 +1099,26 @@ private:
// Current matrix of matches/users/types:
//
- // |------------|------|---------|--------|
- // | STRUCT | CALL | ASG | RETURN |
- // |------------|------|---------|--------|
- // | Exact | None | LCL_VAR | None |
- // | Compatible | None | LCL_VAR | None |
- // | Partial | None | OBJ | None |
- // |------------|------|---------|--------|
+ // |------------|------|---------|---------|
+ // | STRUCT | CALL | ASG | RETURN |
+ // |------------|------|---------|---------|
+ // | Exact | None | LCL_VAR | LCL_VAR |
+ // | Compatible | None | LCL_VAR | LCL_VAR |
+ // | Partial | None | OBJ | LCL_FLD |
+ // |------------|------|---------|---------|
//
- // |------------|------|---------|--------|----------|
- // | SIMD | CALL | ASG | RETURN | HWI/SIMD |
- // |------------|------|---------|--------|----------|
- // | Exact | None | None | None | None |
- // | Compatible | None | None | None | None |
- // | Partial | None | None | None | None |
- // |------------|------|---------|--------|----------|
+ // |------------|------|---------|---------|----------|
+ // | SIMD | CALL | ASG | RETURN | HWI/SIMD |
+ // |------------|------|---------|---------|----------|
+ // | Exact | None | None | None | None |
+ // | Compatible | None | None | None | None |
+ // | Partial | None | None | None | None |
+ // |------------|------|---------|---------|----------|
//
// TODO-ADDR: delete all the "None" entries and always
// transform local nodes into LCL_VAR or LCL_FLD.
- assert(user->OperIs(GT_ASG) && indir->TypeIs(TYP_STRUCT));
+ assert(indir->TypeIs(TYP_STRUCT) && user->OperIs(GT_ASG, GT_RETURN));
*pStructLayout = indirLayout;
@@ -1141,7 +1127,12 @@ private:
return IndirTransform::LclVar;
}
- return IndirTransform::ObjAddrLclFld;
+ if (user->OperIs(GT_ASG))
+ {
+ return IndirTransform::ObjAddrLclFld;
+ }
+
+ return IndirTransform::LclFld;
}
//------------------------------------------------------------------------
diff --git a/src/coreclr/jit/liveness.cpp b/src/coreclr/jit/liveness.cpp
index c540c484cff..17ebbed2590 100644
--- a/src/coreclr/jit/liveness.cpp
+++ b/src/coreclr/jit/liveness.cpp
@@ -260,7 +260,6 @@ void Compiler::fgPerNodeLocalVarLiveness(GenTree* tree)
// These should have been morphed away to become GT_INDs:
case GT_FIELD:
- case GT_INDEX:
unreached();
break;
diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp
index 1713db4979f..b78396e5564 100644
--- a/src/coreclr/jit/loopcloning.cpp
+++ b/src/coreclr/jit/loopcloning.cpp
@@ -58,8 +58,7 @@ void ArrIndex::PrintBoundsCheckNodes(unsigned dim /* = -1 */)
// the "type" member
//
// Notes:
-// This tree produces GT_INDEX node, the caller is supposed to morph it appropriately
-// so it can be codegen'ed.
+// This tree produces a GT_IND(GT_INDEX_ADDR) node, the caller is supposed to morph it.
//
GenTree* LC_Array::ToGenTree(Compiler* comp, BasicBlock* bb)
{
@@ -71,13 +70,15 @@ GenTree* LC_Array::ToGenTree(Compiler* comp, BasicBlock* bb)
int rank = GetDimRank();
for (int i = 0; i < rank; ++i)
{
- arr = comp->gtNewIndexRef(TYP_REF, arr, comp->gtNewLclvNode(arrIndex->indLcls[i],
- comp->lvaTable[arrIndex->indLcls[i]].lvType));
+ GenTree* idx = comp->gtNewLclvNode(arrIndex->indLcls[i], comp->lvaTable[arrIndex->indLcls[i]].lvType);
+ GenTree* arrAddr = comp->gtNewArrayIndexAddr(arr, idx, TYP_REF, NO_CLASS_HANDLE);
// Clear the range check flag and mark the index as non-faulting: we guarantee that all necessary range
// checking has already been done by the time this array index expression is invoked.
- arr->gtFlags &= ~(GTF_INX_RNGCHK | GTF_EXCEPT);
- arr->gtFlags |= GTF_INX_NOFAULT;
+ arrAddr->gtFlags &= ~GTF_INX_RNGCHK;
+ arrAddr->gtFlags |= GTF_INX_ADDR_NONNULL;
+
+ arr = comp->gtNewIndexIndir(arrAddr->AsIndexAddr());
}
// If asked for arrlen invoke arr length operator.
if (oper == ArrLen)
@@ -2186,7 +2187,7 @@ bool Compiler::optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum)
//
// Arguments:
// tree the tree to be checked if it is the array [] operation.
-// result the extracted GT_INDEX information is updated in result.
+// result the extracted GT_INDEX_ADDR information is updated in result.
// lhsNum for the root level (function is recursive) callers should pass BAD_VAR_NUM.
// topLevelIsFinal OUT: set to `true` if see a non-TYP_REF element type array.
//
@@ -2196,8 +2197,8 @@ bool Compiler::optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum)
// dimension of [] encountered.
//
// Operation:
-// Given a "tree" extract the GT_INDEX node in "result" as ArrIndex. In morph
-// we have converted a GT_INDEX tree into a scaled index base offset expression.
+// Given a "tree" extract the GT_INDEX_ADDR node in "result" as ArrIndex. In morph
+// we have converted a GT_INDEX_ADDR tree into a scaled index base offset expression.
// However, we don't actually bother to parse the morphed tree. All we care about is
// the bounds check node: it contains the array base and element index. The other side
// of the COMMA node can vary between array of primitive type and array of struct. There's
@@ -2306,7 +2307,7 @@ bool Compiler::optExtractArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsN
//
// Arguments:
// tree the tree to be checked if it is an array [][][] operation.
-// result OUT: the extracted GT_INDEX information.
+// result OUT: the extracted GT_INDEX_ADDR information.
// lhsNum var number of array object we're looking for.
// topLevelIsFinal OUT: set to `true` if we reached a non-TYP_REF element type array.
//
@@ -2333,7 +2334,7 @@ bool Compiler::optReconstructArrIndexHelp(GenTree* tree, ArrIndex* result, unsig
GenTree* lhs = before->gtGetOp1();
GenTree* rhs = before->gtGetOp2();
- // "rhs" should contain an GT_INDEX
+ // "rhs" should contain an index expression.
if (!lhs->IsLocal() || !optReconstructArrIndexHelp(rhs, result, lhsNum, topLevelIsFinal))
{
return false;
diff --git a/src/coreclr/jit/loopcloning.h b/src/coreclr/jit/loopcloning.h
index 13bd2fa5e09..8120e82a14c 100644
--- a/src/coreclr/jit/loopcloning.h
+++ b/src/coreclr/jit/loopcloning.h
@@ -70,7 +70,7 @@ exception occurs.
block, stmt, tree information) to do the optimization later.
a) This involves checking if the loop is well-formed with respect to
the optimization being performed.
- b) In array bounds check case, reconstructing the morphed GT_INDEX
+ b) In array bounds check case, reconstructing the morphed GT_INDEX_ADDR
nodes back to their array representation.
i) The array index is stored in the "context" variable with
additional block, tree, stmt info.
@@ -195,7 +195,7 @@ class Compiler;
*
* Represents an array access and associated bounds checks.
* Array access is required to have the array and indices in local variables.
- * This struct is constructed using a GT_INDEX node that is broken into
+ * This struct is constructed using a GT_INDEX_ADDR node that is broken into
* its sub trees.
*
*/
diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp
index c9d7e783a60..98bd11f0fd2 100644
--- a/src/coreclr/jit/lower.cpp
+++ b/src/coreclr/jit/lower.cpp
@@ -3686,6 +3686,10 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret)
LowerRetSingleRegStructLclVar(ret);
break;
+ case GT_LCL_FLD:
+ retVal->ChangeType(nativeReturnType);
+ break;
+
#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS)
#ifdef FEATURE_SIMD
case GT_SIMD:
@@ -3706,16 +3710,6 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret)
break;
#endif // FEATURE_SIMD || FEATURE_HW_INTRINSICS
- case GT_LCL_FLD:
- {
-#ifdef DEBUG
- LclVarDsc* varDsc = comp->lvaGetDesc(retVal->AsLclFld());
- assert(varDsc->lvDoNotEnregister);
-#endif
- retVal->ChangeType(nativeReturnType);
- }
- break;
-
default:
assert(varTypeIsEnregisterable(retVal));
if (varTypeUsesFloatReg(ret) != varTypeUsesFloatReg(retVal))
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index 48b88f100d4..6898650f523 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -2033,8 +2033,8 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call
}
noway_assert(cloned != nullptr);
- GenTree* newArg = new (comp, GT_ADDR)
- GenTreeAddrMode(TYP_BYREF, cloned, nullptr, 0, comp->eeGetEEInfo()->offsetOfWrapperDelegateIndirectCell);
+ GenTree* offsetNode = comp->gtNewIconNode(comp->eeGetEEInfo()->offsetOfWrapperDelegateIndirectCell, TYP_I_IMPL);
+ GenTree* newArg = comp->gtNewOperNode(GT_ADD, TYP_BYREF, cloned, offsetNode);
// Append newArg as the last arg
PushBack(comp, NewCallArg::Primitive(newArg).WellKnown(WellKnownArg::WrapperDelegateCell));
@@ -3314,6 +3314,18 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
makeOutArgCopy = true;
}
+ // If the arg may go into registers (both fully or split)
+ // then we cannot handle passing it from an arbitrary
+ // source if it would require passing a 3 byte chunk.
+ // Placing 3 bytes into a register requires multiple loads/shifts/or.
+ // In theory we could more easily support it for split args
+ // as those load registers fully always, but currently we
+ // do not.
+ if ((arg.AbiInfo.NumRegs > 0) && ((passingSize % REGSIZE_BYTES) == 3))
+ {
+ makeOutArgCopy = true;
+ }
+
if (structSize < TARGET_POINTER_SIZE)
{
makeOutArgCopy = true;
@@ -3404,11 +3416,24 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
argObj->gtType = structBaseType;
}
}
- else
+ else if (argObj->OperIs(GT_LCL_FLD, GT_IND))
{
- // Not a GT_LCL_VAR, so we can just change the type on the node
+ // We can just change the type on the node
argObj->gtType = structBaseType;
}
+ else
+ {
+#ifdef FEATURE_SIMD
+ // We leave the SIMD8 <-> LONG (Windows x64) case to lowering. For SIMD8 <-> DOUBLE (Unix x64),
+ // we do not need to do anything as both types already use floating-point registers.
+ assert((argObj->TypeIs(TYP_SIMD8) &&
+ ((structBaseType == TYP_LONG) || (structBaseType == TYP_DOUBLE))) ||
+ argObj->TypeIs(structBaseType));
+#else // !FEATURE_SIMD
+ unreached();
+#endif // !FEATURE_SIMD
+ }
+
assert(varTypeIsEnregisterable(argObj->TypeGet()) ||
(makeOutArgCopy && varTypeIsEnregisterable(structBaseType)));
}
@@ -3779,30 +3804,33 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg)
GenTree* argValue = argNode; // normally argValue will be arg, but see right below
unsigned structSize = 0;
- if (argNode->TypeGet() != TYP_STRUCT)
- {
- structSize = genTypeSize(argNode->TypeGet());
- }
- else if (argNode->OperGet() == GT_OBJ)
+ if (argNode->OperGet() == GT_OBJ)
{
- GenTreeObj* argObj = argNode->AsObj();
- const ClassLayout* objLayout = argObj->GetLayout();
- structSize = objLayout->GetSize();
+ GenTreeObj* argObj = argNode->AsObj();
+ ClassLayout* objLayout = argObj->GetLayout();
+ structSize = objLayout->GetSize();
// If we have a GT_OBJ of a GT_ADDR then we set argValue to the child node of the GT_ADDR.
- GenTree* op1 = argObj->gtOp1;
- if (op1->OperGet() == GT_ADDR)
+ // TODO-ADDR: always perform this transformation in local morph and delete this code.
+ GenTree* addr = argObj->Addr();
+ if (addr->OperGet() == GT_ADDR)
{
- GenTree* underlyingTree = op1->AsOp()->gtOp1;
+ GenTree* location = addr->AsOp()->gtOp1;
- // Only update to the same type.
- if (underlyingTree->OperIs(GT_LCL_VAR))
+ if (location->OperIsLocalRead())
{
- const LclVarDsc* varDsc = lvaGetDesc(underlyingTree->AsLclVar());
- if (ClassLayout::AreCompatible(varDsc->GetLayout(), objLayout))
+ if (!location->OperIs(GT_LCL_VAR) ||
+ !ClassLayout::AreCompatible(lvaGetDesc(location->AsLclVarCommon())->GetLayout(), objLayout))
{
- argValue = underlyingTree;
+ unsigned lclOffset = location->AsLclVarCommon()->GetLclOffs();
+
+ location->ChangeType(argObj->TypeGet());
+ location->SetOper(GT_LCL_FLD);
+ location->AsLclFld()->SetLclOffs(lclOffset);
+ location->AsLclFld()->SetLayout(objLayout);
}
+
+ argValue = location;
}
}
}
@@ -3811,6 +3839,10 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg)
LclVarDsc* varDsc = lvaGetDesc(argNode->AsLclVarCommon());
structSize = varDsc->lvExactSize;
}
+ else if (!argNode->TypeIs(TYP_STRUCT))
+ {
+ structSize = genTypeSize(argNode);
+ }
else
{
structSize = info.compCompHnd->getClassSize(objClass);
@@ -3898,7 +3930,7 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg)
break;
#endif // (TARGET_ARM64) || (UNIX_AMD64_ABI) || (TARGET_LOONGARCH64)
default:
- noway_assert(!"NYI: odd sized struct in fgMorphMultiregStructArg");
+ noway_assert(!"Cannot load odd sized last element from arbitrary source");
break;
}
}
@@ -4507,102 +4539,43 @@ BasicBlock* Compiler::fgSetRngChkTargetInner(SpecialCodeKind kind, bool delay)
return nullptr;
}
-/*****************************************************************************
- *
- * Expand a GT_INDEX node and fully morph the child operands
- *
- * The orginal GT_INDEX node is bashed into the GT_IND node that accesses
- * the array element. We expand the GT_INDEX node into a larger tree that
- * evaluates the array base and index. The simplest expansion is a GT_COMMA
- * with a GT_BOUNDS_CHECK and a GT_IND with a GTF_INX_RNGCHK flag.
- * For complex array or index expressions one or more GT_COMMA assignments
- * are inserted so that we only evaluate the array or index expressions once.
- *
- * The fully expanded tree is then morphed. This causes gtFoldExpr to
- * perform local constant prop and reorder the constants in the tree and
- * fold them.
- *
- * We then parse the resulting array element expression in order to locate
- * and label the constants and variables that occur in the tree.
- */
-
-const int MAX_ARR_COMPLEXITY = 4;
-const int MAX_INDEX_COMPLEXITY = 4;
-
-GenTree* Compiler::fgMorphArrayIndex(GenTree* tree)
+//------------------------------------------------------------------------
+// fgMorphIndexAddr: Expand a GT_INDEX_ADDR node and fully morph the child operands.
+//
+// We expand the GT_INDEX_ADDR node into a larger tree that evaluates the array
+// base and index. The simplest expansion is a GT_COMMA with a GT_BOUNDS_CHECK.
+// For complex array or index expressions one or more GT_COMMA assignments
+// are inserted so that we only evaluate the array or index expressions once.
+//
+// The fully expanded tree is then morphed. This causes gtFoldExpr to
+// perform local constant prop and reorder the constants in the tree and
+// fold them.
+//
+// Arguments:
+// indexAddr - The INDEX_ADRR tree to morph
+//
+// Return Value:
+// The resulting tree.
+//
+GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr)
{
- noway_assert(tree->gtOper == GT_INDEX);
- GenTreeIndex* asIndex = tree->AsIndex();
- var_types elemTyp = asIndex->TypeGet();
- unsigned elemSize = asIndex->gtIndElemSize;
- CORINFO_CLASS_HANDLE elemStructType = asIndex->gtStructElemClass;
+ const int MAX_ARR_COMPLEXITY = 4;
+ const int MAX_INDEX_COMPLEXITY = 4;
- noway_assert(elemTyp != TYP_STRUCT || elemStructType != NO_CLASS_HANDLE);
-
- // Fold "cns_str"[cns_index] to ushort constant
- // NOTE: don't do it for empty string, the operation will fail anyway
- if (opts.OptimizationEnabled() && asIndex->Arr()->OperIs(GT_CNS_STR) &&
- !asIndex->Arr()->AsStrCon()->IsStringEmptyField() && asIndex->Index()->IsIntCnsFitsInI32())
- {
- const int cnsIndex = static_cast<int>(asIndex->Index()->AsIntConCommon()->IconValue());
- if (cnsIndex >= 0)
- {
- const int maxStrSize = 1024;
- char16_t str[maxStrSize];
- int length = info.compCompHnd->getStringLiteral(asIndex->Arr()->AsStrCon()->gtScpHnd,
- asIndex->Arr()->AsStrCon()->gtSconCPX, str, maxStrSize);
- if ((cnsIndex < length))
- {
- GenTree* cnsCharNode = gtNewIconNode(str[cnsIndex], TYP_INT);
- INDEBUG(cnsCharNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
- return cnsCharNode;
- }
- }
- }
+ var_types elemTyp = indexAddr->gtElemType;
+ unsigned elemSize = indexAddr->gtElemSize;
+ uint8_t elemOffs = static_cast<uint8_t>(indexAddr->gtElemOffset);
+ CORINFO_CLASS_HANDLE elemStructType = indexAddr->gtStructElemClass;
-#ifdef FEATURE_SIMD
- if (varTypeIsStruct(elemTyp) && structSizeMightRepresentSIMDType(elemSize))
- {
- // If this is a SIMD type, this is the point at which we lose the type information,
- // so we need to set the correct type on the GT_IND.
- // (We don't care about the base type here, so we only check, but don't retain, the return value).
- unsigned simdElemSize = 0;
- if (getBaseJitTypeAndSizeOfSIMDType(elemStructType, &simdElemSize) != CORINFO_TYPE_UNDEF)
- {
- assert(simdElemSize == elemSize);
- elemTyp = getSIMDTypeForSize(elemSize);
- // This is the new type of the node.
- tree->gtType = elemTyp;
- // Now set elemStructType to null so that we don't confuse value numbering.
- elemStructType = NO_CLASS_HANDLE;
- }
- }
-#endif // FEATURE_SIMD
+ noway_assert(!varTypeIsStruct(elemTyp) || (elemStructType != NO_CLASS_HANDLE));
- // Set up the array length's offset into lenOffs
- // And the first element's offset into elemOffs
- ssize_t lenOffs;
- uint8_t elemOffs;
- if (tree->gtFlags & GTF_INX_STRING_LAYOUT)
- {
- lenOffs = OFFSETOF__CORINFO_String__stringLen;
- elemOffs = OFFSETOF__CORINFO_String__chars;
- tree->gtFlags &= ~GTF_INX_STRING_LAYOUT; // Clear this flag as it is used for GTF_IND_VOLATILE
- }
- else
- {
- // We have a standard array
- lenOffs = OFFSETOF__CORINFO_Array__length;
- elemOffs = OFFSETOF__CORINFO_Array__data;
- }
-
- // In minopts, we expand GT_INDEX to GT_IND(GT_INDEX_ADDR) in order to minimize the size of the IR. As minopts
+ // In minopts, we will not be expanding GT_INDEX_ADDR in order to minimize the size of the IR. As minopts
// compilation time is roughly proportional to the size of the IR, this helps keep compilation times down.
// Furthermore, this representation typically saves on code size in minopts w.r.t. the complete expansion
// performed when optimizing, as it does not require LclVar nodes (which are always stack loads/stores in
// minopts).
//
- // When we *are* optimizing, we fully expand GT_INDEX to:
+ // When we *are* optimizing, we fully expand GT_INDEX_ADDR to:
// 1. Evaluate the array address expression and store the result in a temp if the expression is complex or
// side-effecting.
// 2. Evaluate the array index expression and store the result in a temp if the expression is complex or
@@ -4612,63 +4585,46 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree)
// GT_ADD(GT_ADD(array, firstElementOffset), GT_MUL(index, elementSize)) OR
// GT_ADD(GT_ADD(array, GT_ADD(GT_MUL(index, elementSize), firstElementOffset)))
// 5. Wrap the address in a GT_ADD_ADDR (the information saved there will later be used by VN).
- // 6. Dereference the address with a GT_IND.
//
// This expansion explicitly exposes the bounds check and the address calculation to the optimizer, which allows
// for more straightforward bounds-check removal, CSE, etc.
if (opts.MinOpts())
{
- GenTree* const array = fgMorphTree(asIndex->Arr());
- GenTree* const index = fgMorphTree(asIndex->Index());
-
- GenTreeIndexAddr* const indexAddr = new (this, GT_INDEX_ADDR)
- GenTreeIndexAddr(array, index, elemTyp, elemStructType, elemSize, static_cast<unsigned>(lenOffs), elemOffs);
- indexAddr->gtFlags |= (array->gtFlags | index->gtFlags) & GTF_ALL_EFFECT;
+ indexAddr->Arr() = fgMorphTree(indexAddr->Arr());
+ indexAddr->Index() = fgMorphTree(indexAddr->Index());
+ indexAddr->AddAllEffectsFlags(indexAddr->Arr(), indexAddr->Index());
// Mark the indirection node as needing a range check if necessary.
// Note this will always be true unless JitSkipArrayBoundCheck() is used
- if ((indexAddr->gtFlags & GTF_INX_RNGCHK) != 0)
+ if (indexAddr->IsBoundsChecked())
{
fgSetRngChkTarget(indexAddr);
}
- if (!tree->TypeIs(TYP_STRUCT))
- {
- tree->ChangeOper(GT_IND);
- }
- else
- {
- DEBUG_DESTROY_NODE(tree);
- tree = gtNewObjNode(elemStructType, indexAddr);
- INDEBUG(tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
- }
- GenTreeIndir* const indir = tree->AsIndir();
- indir->Addr() = indexAddr;
- bool canCSE = indir->CanCSE();
- indir->gtFlags = indexAddr->gtFlags & GTF_ALL_EFFECT;
- if (!canCSE)
- {
- indir->SetDoNotCSE();
- }
-
- INDEBUG(indexAddr->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
-
- return indir;
+ return indexAddr;
}
- GenTree* arrRef = asIndex->Arr();
- GenTree* index = asIndex->Index();
+#ifdef FEATURE_SIMD
+ if (varTypeIsStruct(elemTyp) && structSizeMightRepresentSIMDType(elemSize))
+ {
+ elemTyp = impNormStructType(elemStructType);
+ }
+#endif // FEATURE_SIMD
- bool chkd = ((tree->gtFlags & GTF_INX_RNGCHK) != 0); // if false, range checking will be disabled
- bool indexNonFaulting = ((tree->gtFlags & GTF_INX_NOFAULT) != 0); // if true, mark GTF_IND_NONFAULTING
- bool nCSE = ((tree->gtFlags & GTF_DONT_CSE) != 0);
+ // TODO-CQ: support precise equivalence classes for SIMD-typed arrays in VN.
+ if (elemTyp != TYP_STRUCT)
+ {
+ elemStructType = NO_CLASS_HANDLE;
+ }
- GenTree* arrRefDefn = nullptr; // non-NULL if we need to allocate a temp for the arrRef expression
- GenTree* indexDefn = nullptr; // non-NULL if we need to allocate a temp for the index expression
- GenTree* bndsChk = nullptr;
+ GenTree* arrRef = indexAddr->Arr();
+ GenTree* index = indexAddr->Index();
+ GenTree* arrRefDefn = nullptr; // non-NULL if we need to allocate a temp for the arrRef expression
+ GenTree* indexDefn = nullptr; // non-NULL if we need to allocate a temp for the index expression
+ GenTreeBoundsChk* boundsCheck = nullptr;
// If we're doing range checking, introduce a GT_BOUNDS_CHECK node for the address.
- if (chkd)
+ if (indexAddr->IsBoundsChecked())
{
GenTree* arrRef2 = nullptr; // The second copy will be used in array address expression
GenTree* index2 = nullptr;
@@ -4684,7 +4640,7 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree)
// were mostly ameliorated by adding this condition.
//
// Likewise, allocate a temporary if the expression is a GT_LCL_FLD node. These used to be created
- // after fgMorphArrayIndex from GT_FIELD trees so this preserves the existing behavior. This is
+ // after fgMorphIndexAddr from GT_FIELD trees so this preserves the existing behavior. This is
// perhaps a decision that should be left to CSE but FX diffs show that it is slightly better to
// do this here.
@@ -4729,27 +4685,23 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree)
}
#endif // TARGET_64BIT
- GenTree* arrLen = gtNewArrLen(TYP_INT, arrRef, (int)lenOffs, compCurBB);
+ GenTree* arrLen = gtNewArrLen(TYP_INT, arrRef, (int)indexAddr->gtLenOffset, compCurBB);
if (bndsChkType != TYP_INT)
{
arrLen = gtNewCastNode(bndsChkType, arrLen, true, bndsChkType);
}
- GenTreeBoundsChk* arrBndsChk = new (this, GT_BOUNDS_CHECK) GenTreeBoundsChk(index, arrLen, SCK_RNGCHK_FAIL);
- arrBndsChk->gtInxType = elemTyp;
-
- bndsChk = arrBndsChk;
+ boundsCheck = new (this, GT_BOUNDS_CHECK) GenTreeBoundsChk(index, arrLen, SCK_RNGCHK_FAIL);
+ boundsCheck->gtInxType = elemTyp;
// Now we'll switch to using the second copies for arrRef and index
// to compute the address expression
-
arrRef = arrRef2;
index = index2;
}
// Create the "addr" which is "*(arrRef + ((index * elemSize) + elemOffs))"
-
GenTree* addr;
#ifdef TARGET_64BIT
@@ -4833,124 +4785,146 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree)
addr = gtNewOperNode(GT_ADD, TYP_BYREF, arrRef, addr);
}
+ // TODO-Throughout: bash the INDEX_ADDR to ARR_ADDR here instead of creating a new node.
addr = new (this, GT_ARR_ADDR) GenTreeArrAddr(addr, elemTyp, elemStructType, elemOffs);
- // Change the orginal GT_INDEX node into a GT_IND node
- tree->SetOper(GT_IND);
-
- // If the index node is a floating-point type, notify the compiler
- // we'll potentially use floating point registers at the time of codegen.
- if (varTypeUsesFloatReg(tree->gtType))
+ if (indexAddr->IsNotNull())
{
- this->compFloatingPointUsed = true;
- }
-
- // We've now consumed the GTF_INX_RNGCHK and GTF_INX_NOFAULT, and the node
- // is no longer a GT_INDEX node.
- tree->gtFlags &= ~(GTF_INX_RNGCHK | GTF_INX_NOFAULT);
-
- tree->AsOp()->gtOp1 = addr;
-
- // If there's a bounds check, the indir won't fault.
- if (bndsChk || indexNonFaulting)
- {
- tree->gtFlags |= GTF_IND_NONFAULTING;
addr->gtFlags |= GTF_ARR_ADDR_NONNULL;
}
- else
- {
- tree->gtFlags |= GTF_EXCEPT;
- }
- if (nCSE)
+ // Transfer the zero-offset annotation from INDEX_ADDR to ARR_ADDR...
+ FieldSeqNode* zeroOffsetFldSeq;
+ if (GetZeroOffsetFieldMap()->Lookup(indexAddr, &zeroOffsetFldSeq))
{
- tree->gtFlags |= GTF_DONT_CSE;
+ fgAddFieldSeqForZeroOffset(addr, zeroOffsetFldSeq);
}
- // Did we create a bndsChk tree?
- if (bndsChk)
- {
- // Use a GT_COMMA node to prepend the array bound check
- //
- tree = gtNewOperNode(GT_COMMA, elemTyp, bndsChk, tree);
+ GenTree* tree = addr;
- /* Mark the indirection node as needing a range check */
- fgSetRngChkTarget(bndsChk);
+ // Prepend the bounds check and the assignment trees that were created (if any).
+ if (boundsCheck != nullptr)
+ {
+ tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), boundsCheck, tree);
+ fgSetRngChkTarget(boundsCheck);
}
if (indexDefn != nullptr)
{
- // Use a GT_COMMA node to prepend the index assignment
- //
tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), indexDefn, tree);
}
+
if (arrRefDefn != nullptr)
{
- // Use a GT_COMMA node to prepend the arRef assignment
- //
tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), arrRefDefn, tree);
}
- JITDUMP("fgMorphArrayIndex (before remorph):\n")
+ JITDUMP("fgMorphIndexAddr (before remorph):\n")
DISPTREE(tree)
- GenTree* morphedTree = fgMorphTree(tree);
- DBEXEC(morphedTree != tree, morphedTree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED);
+ tree = fgMorphTree(tree);
+ DBEXEC(tree == indexAddr, tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED);
JITDUMP("fgMorphArrayIndex (after remorph):\n")
- DISPTREE(morphedTree)
+ DISPTREE(tree)
- return morphedTree;
+ return tree;
}
-#ifdef TARGET_X86
-/*****************************************************************************
- *
- * Wrap fixed stack arguments for varargs functions to go through varargs
- * cookie to access them, except for the cookie itself.
- *
- * Non-x86 platforms are allowed to access all arguments directly
- * so we don't need this code.
- *
- */
-GenTree* Compiler::fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs)
+//------------------------------------------------------------------------
+// fgMorphLocal: Fully morph a local node.
+//
+// Arguments:
+// lclNode - The node to morph
+//
+// Return Value:
+// The fully morphed tree.
+//
+GenTree* Compiler::fgMorphLocal(GenTreeLclVarCommon* lclNode)
{
- /* For the fixed stack arguments of a varargs function, we need to go
- through the varargs cookies to access them, except for the
- cookie itself */
+ assert(lclNode->OperIs(GT_LCL_VAR, GT_LCL_FLD) || lclNode->OperIsLocalAddr());
- LclVarDsc* varDsc = lvaGetDesc(lclNum);
+ GenTree* expandedTree = nullptr;
+#ifdef TARGET_X86
+ expandedTree = fgMorphExpandStackArgForVarArgs(lclNode);
+#endif // TARGET_X86
- if (varDsc->lvIsParam && !varDsc->lvIsRegArg && lclNum != lvaVarargsHandleArg)
+ if (expandedTree != nullptr)
{
- // Create a node representing the local pointing to the base of the args
- GenTree* ptrArg =
- gtNewOperNode(GT_SUB, TYP_I_IMPL, gtNewLclvNode(lvaVarargsBaseOfStkArgs, TYP_I_IMPL),
- gtNewIconNode(varDsc->GetStackOffset() -
- codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES - lclOffs));
+ return fgMorphTree(expandedTree);
+ }
- // Access the argument through the local
- GenTree* tree;
- if (varTypeIsStruct(varType))
- {
- CORINFO_CLASS_HANDLE typeHnd = varDsc->GetStructHnd();
- assert(typeHnd != nullptr);
- tree = gtNewObjNode(typeHnd, ptrArg);
- }
- else
- {
- tree = gtNewOperNode(GT_IND, varType, ptrArg);
- }
+ if (lclNode->OperIsLocalAddr())
+ {
+ // No further morphing necessary.
+ return lclNode;
+ }
- if (varDsc->IsAddressExposed())
- {
- tree->gtFlags |= GTF_GLOB_REF;
- }
+ assert(lclNode->OperIs(GT_LCL_VAR, GT_LCL_FLD));
+
+ if (lclNode->OperIs(GT_LCL_VAR))
+ {
+ return fgMorphLocalVar(lclNode, /* forceRemorph */ false);
+ }
+
+ if (lvaGetDesc(lclNode)->IsAddressExposed())
+ {
+ lclNode->gtFlags |= GTF_GLOB_REF;
+ }
+
+ return lclNode;
+}
- return fgMorphTree(tree);
+#ifdef TARGET_X86
+//------------------------------------------------------------------------
+// fgMorphExpandStackArgForVarArgs: Expand a stack arg node for varargs.
+//
+// Expands the node to use the varargs cookie as the base address, indirecting
+// off of it if necessary, similar to how implicit by-ref parameters are morphed
+// on non-x86 targets.
+//
+// Arguments:
+// lclNode - The local node to (possibly) morph
+//
+// Return Value:
+// The new tree for "lclNode", in which case the caller is expected to morph
+// it further, otherwise "nullptr".
+//
+GenTree* Compiler::fgMorphExpandStackArgForVarArgs(GenTreeLclVarCommon* lclNode)
+{
+ if (!lvaIsArgAccessedViaVarArgsCookie(lclNode->GetLclNum()))
+ {
+ return nullptr;
}
- return NULL;
+ LclVarDsc* varDsc = lvaGetDesc(lclNode);
+ GenTree* argsBaseAddr = gtNewLclvNode(lvaVarargsBaseOfStkArgs, TYP_I_IMPL);
+ ssize_t offset =
+ varDsc->GetStackOffset() - codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES - lclNode->GetLclOffs();
+ GenTree* offsetNode = gtNewIconNode(offset, TYP_I_IMPL);
+ GenTree* argAddr = gtNewOperNode(GT_SUB, TYP_I_IMPL, argsBaseAddr, offsetNode);
+
+ if (lclNode->OperIsLocalAddr())
+ {
+ return argAddr;
+ }
+
+ GenTree* argNode;
+ if (varTypeIsStruct(lclNode))
+ {
+ argNode = gtNewObjNode(lclNode->GetLayout(this), argAddr);
+ }
+ else
+ {
+ argNode = gtNewIndir(lclNode->TypeGet(), argAddr);
+ }
+
+ if (varDsc->IsAddressExposed())
+ {
+ argNode->gtFlags |= GTF_GLOB_REF;
+ }
+
+ return argNode;
}
#endif
@@ -4961,44 +4935,26 @@ GenTree* Compiler::fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType,
GenTree* Compiler::fgMorphLocalVar(GenTree* tree, bool forceRemorph)
{
- assert(tree->gtOper == GT_LCL_VAR);
+ assert(tree->OperIs(GT_LCL_VAR));
- unsigned lclNum = tree->AsLclVarCommon()->GetLclNum();
- var_types varType = lvaGetRealType(lclNum);
- LclVarDsc* varDsc = lvaGetDesc(lclNum);
+ LclVarDsc* varDsc = lvaGetDesc(tree->AsLclVarCommon());
if (varDsc->IsAddressExposed())
{
tree->gtFlags |= GTF_GLOB_REF;
}
-#ifdef TARGET_X86
- if (info.compIsVarArgs)
- {
- GenTree* newTree = fgMorphStackArgForVarArgs(lclNum, varType, 0);
- if (newTree != nullptr)
- {
- if (newTree->OperIsBlk() && ((tree->gtFlags & GTF_VAR_DEF) == 0))
- {
- newTree->SetOper(GT_IND);
- }
- return newTree;
- }
- }
-#endif // TARGET_X86
-
- /* If not during the global morphing phase bail */
-
+ // If not during the global morphing phase bail.
if (!fgGlobalMorph && !forceRemorph)
{
return tree;
}
- bool varAddr = (tree->gtFlags & GTF_DONT_CSE) != 0;
+ bool isLocation = (tree->gtFlags & GTF_DONT_CSE) != 0;
- noway_assert(!(tree->gtFlags & GTF_VAR_DEF) || varAddr); // GTF_VAR_DEF should always imply varAddr
+ noway_assert(!(tree->gtFlags & GTF_VAR_DEF) || isLocation); // GTF_VAR_DEF should always imply isLocation.
- if (!varAddr && varDsc->lvNormalizeOnLoad())
+ if (!isLocation && varDsc->lvNormalizeOnLoad())
{
// TYP_BOOL quirk: previously, the code in optAssertionIsSubrange did not handle TYP_BOOL.
// Now it does, but this leads to some regressions because we lose the uniform VNs for trees
@@ -5007,7 +4963,8 @@ GenTree* Compiler::fgMorphLocalVar(GenTree* tree, bool forceRemorph)
// This is a pretty fundamental problem with how normalize-on-load locals appear to the optimizer.
// This quirk preserves the previous behavior.
// TODO-CQ: fix the VNs for normalize-on-load locals and remove this quirk.
- bool isBoolQuirk = varType == TYP_BOOL;
+ var_types lclVarType = varDsc->TypeGet();
+ bool isBoolQuirk = lclVarType == TYP_BOOL;
// Assertion prop can tell us to omit adding a cast here. This is
// useful when the local is a small-typed parameter that is passed in a
@@ -5015,7 +4972,7 @@ GenTree* Compiler::fgMorphLocalVar(GenTree* tree, bool forceRemorph)
// be invalid, but the assertion guarantees us that we have normalized
// when we wrote it.
if (optLocalAssertionProp && !isBoolQuirk &&
- optAssertionIsSubrange(tree, IntegralRange::ForType(varType), apFull) != NO_ASSERTION_INDEX)
+ optAssertionIsSubrange(tree, IntegralRange::ForType(lclVarType), apFull) != NO_ASSERTION_INDEX)
{
// The previous assertion can guarantee us that if this node gets
// assigned a register, it will be normalized already. It is still
@@ -5034,7 +4991,7 @@ GenTree* Compiler::fgMorphLocalVar(GenTree* tree, bool forceRemorph)
tree->gtType = TYP_INT;
fgMorphTreeDone(tree);
- tree = gtNewCastNode(TYP_INT, tree, false, varType);
+ tree = gtNewCastNode(TYP_INT, tree, false, lclVarType);
fgMorphTreeDone(tree);
return tree;
}
@@ -5620,7 +5577,7 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
// If unsuccessful, the transformations done in anticipation of a
// possible inline are undone, and the candidate flag on the call
// is cleared.
-
+//
void Compiler::fgMorphCallInline(GenTreeCall* call, InlineResult* inlineResult)
{
bool inliningFailed = false;
@@ -5710,6 +5667,7 @@ void Compiler::fgMorphCallInline(GenTreeCall* call, InlineResult* inlineResult)
// If a context was created because we got to the importer then it is output by this function.
// If the inline succeeded, this context will already be marked as successful. If it failed and
// a context is returned, then it will not have been marked as success or failed.
+//
void Compiler::fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result, InlineContext** createdContext)
{
// Don't expect any surprises here.
@@ -5911,7 +5869,7 @@ void Compiler::fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result,
// -- Caller requires stack space and nCalleeArgs > nCallerArgs (Bug) --
// caller({ double, double, double, double, double, double }) // 48 byte stack
// callee(int, int) -- 2 int registers
-
+//
bool Compiler::fgCanFastTailCall(GenTreeCall* callee, const char** failReason)
{
#if FEATURE_FASTTAILCALL
@@ -6615,7 +6573,7 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call)
// On x86 we have a faster mechanism than the general one which we use
// in almost all cases. See fgCanTailCallViaJitHelper for more information.
- if (fgCanTailCallViaJitHelper())
+ if (fgCanTailCallViaJitHelper(call))
{
tailCallViaJitHelper = true;
}
@@ -8550,8 +8508,9 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call)
fgWalkTreePost(&value, resetMorphedFlag);
#endif // DEBUG
- GenTree* const arrIndexNode = gtNewIndexRef(TYP_REF, arr, index);
- GenTree* const arrStore = gtNewAssignNode(arrIndexNode, value);
+ GenTree* const arrIndexAddr = gtNewArrayIndexAddr(arr, index, TYP_REF, NO_CLASS_HANDLE);
+ GenTree* const arrIndex = gtNewIndexIndir(arrIndexAddr->AsIndexAddr());
+ GenTree* const arrStore = gtNewAssignNode(arrIndex, value);
GenTree* result = fgMorphTree(arrStore);
if (argSetup != nullptr)
@@ -8852,44 +8811,24 @@ GenTreeLclVar* Compiler::fgMorphTryFoldObjAsLclVar(GenTreeObj* obj, bool destroy
return nullptr;
}
-/*****************************************************************************
- *
- * Transform the given GTK_LEAF tree for code generation.
- */
-
+//------------------------------------------------------------------------
+// fgMorphLeaf: Fully morph a tree with no operands.
+//
+// Arguments:
+// tree - The tree to morph
+//
+// Return Value:
+// The fully morphed "tree".
+//
GenTree* Compiler::fgMorphLeaf(GenTree* tree)
{
- assert(tree->OperKind() & GTK_LEAF);
+ assert(tree->OperIsLeaf());
- if (tree->gtOper == GT_LCL_VAR)
+ if (tree->OperIsNonPhiLocal() || tree->OperIsLocalAddr())
{
- const bool forceRemorph = false;
- return fgMorphLocalVar(tree, forceRemorph);
+ tree = fgMorphLocal(tree->AsLclVarCommon());
}
- else if (tree->gtOper == GT_LCL_FLD)
- {
- if (lvaGetDesc(tree->AsLclFld())->IsAddressExposed())
- {
- tree->gtFlags |= GTF_GLOB_REF;
- }
-
-#ifdef TARGET_X86
- if (info.compIsVarArgs)
- {
- GenTree* newTree = fgMorphStackArgForVarArgs(tree->AsLclFld()->GetLclNum(), tree->TypeGet(),
- tree->AsLclFld()->GetLclOffs());
- if (newTree != nullptr)
- {
- if (newTree->OperIsBlk() && ((tree->gtFlags & GTF_VAR_DEF) == 0))
- {
- newTree->SetOper(GT_IND);
- }
- return newTree;
- }
- }
-#endif // TARGET_X86
- }
- else if (tree->gtOper == GT_FTN_ADDR)
+ else if (tree->OperIs(GT_FTN_ADDR))
{
GenTreeFptrVal* fptrValTree = tree->AsFptrVal();
@@ -9034,7 +8973,7 @@ GenTree* Compiler::fgMorphOneAsgBlockOp(GenTree* tree)
}
if (isCopyBlock && destLclVarTree == nullptr && !src->OperIs(GT_LCL_VAR))
{
- fgMorphBlockOperand(src, asgType, genTypeSize(asgType), false /*isBlkReqd*/);
+ fgMorphBlockOperand(src, asgType, nullptr, false /*isBlkReqd*/);
dest->gtFlags |= GTF_DONT_CSE;
return tree;
}
@@ -9256,13 +9195,9 @@ GenTree* Compiler::fgMorphOneAsgBlockOp(GenTree* tree)
if (dest->gtEffectiveVal()->OperIsIndir())
{
- // If we have no information about the destination, we have to assume it could
- // live anywhere (not just in the GC heap).
- // Mark the GT_IND node so that we use the correct write barrier helper in case
- // the field is a GC ref.
-
if (!fgIsIndirOfAddrOfLocal(dest))
{
+ // TODO-Bug: the GLOB_REF also needs to be set in case "src" is address-exposed.
dest->gtFlags |= GTF_GLOB_REF;
tree->gtFlags |= GTF_GLOB_REF;
}
@@ -9341,13 +9276,13 @@ GenTree* Compiler::fgMorphOneAsgBlockOp(GenTree* tree)
// Ensure that the dest is setup appropriately.
if (dest->gtEffectiveVal()->OperIsIndir())
{
- dest = fgMorphBlockOperand(dest, asgType, size, false /*isBlkReqd*/);
+ dest = fgMorphBlockOperand(dest, asgType, nullptr, false /*isBlkReqd*/);
}
// Ensure that the rhs is setup appropriately.
if (isCopyBlock)
{
- src = fgMorphBlockOperand(src, asgType, size, false /*isBlkReqd*/);
+ src = fgMorphBlockOperand(src, asgType, nullptr, false /*isBlkReqd*/);
}
// Set the lhs and rhs on the assignment.
@@ -9596,7 +9531,6 @@ GenTree* Compiler::fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE cl
{
case GT_LCL_FLD:
case GT_LCL_VAR:
- case GT_INDEX:
case GT_FIELD:
case GT_ARR_ELEM:
addr = gtNewOperNode(GT_ADDR, TYP_BYREF, tree);
@@ -9624,10 +9558,10 @@ GenTree* Compiler::fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE cl
// fgMorphBlockOperand: Canonicalize an operand of a block assignment
//
// Arguments:
-// tree - The block operand
-// asgType - The type of the assignment
-// blockWidth - The size of the block
-// isBlkReqd - true iff this operand must remain a block node
+// tree - The block operand
+// asgType - The type of the assignment
+// blockLayout - The struct layout of the block (for STRUCT "asgType"s)
+// isBlkReqd - true iff this operand must remain a block node
//
// Return Value:
// Returns the morphed block operand
@@ -9638,13 +9572,15 @@ GenTree* Compiler::fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE cl
// - Ensures that any COMMAs are above ADDR nodes.
// Although 'tree' WAS an operand of a block assignment, the assignment
// may have been retyped to be a scalar assignment.
-
-GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigned blockWidth, bool isBlkReqd)
+//
+GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, ClassLayout* blockLayout, bool isBlkReqd)
{
GenTree* effectiveVal = tree->gtEffectiveVal();
if (asgType != TYP_STRUCT)
{
+ unsigned blockWidth = genTypeSize(asgType);
+
if (effectiveVal->OperIsIndir())
{
if (!isBlkReqd)
@@ -9680,6 +9616,8 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne
}
else
{
+ assert(blockLayout != nullptr);
+
GenTreeIndir* indirTree = nullptr;
GenTreeLclVarCommon* lclNode = nullptr;
bool needsIndirection = true;
@@ -9703,7 +9641,7 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne
#ifdef DEBUG
GenTreeCall* call = effectiveVal->AsCall();
assert(call->TypeGet() == TYP_STRUCT);
- assert(blockWidth == info.compCompHnd->getClassSize(call->gtRetClsHnd));
+ assert(blockLayout->GetSize() == info.compCompHnd->getClassSize(call->gtRetClsHnd));
#endif
}
#ifdef TARGET_ARM64
@@ -9721,7 +9659,7 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne
if (lclNode != nullptr)
{
const LclVarDsc* varDsc = lvaGetDesc(lclNode);
- if (varTypeIsStruct(varDsc) && (varDsc->lvExactSize == blockWidth) && (varDsc->lvType == asgType))
+ if (varTypeIsStruct(varDsc) && ClassLayout::AreCompatible(varDsc->GetLayout(), blockLayout))
{
if (effectiveVal != lclNode)
{
@@ -9736,6 +9674,7 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne
effectiveVal->gtFlags |= (lclNode->gtFlags & GTF_ALL_EFFECT);
}
}
+
if (needsIndirection)
{
if ((indirTree != nullptr) && (indirTree->OperIsBlk() || !isBlkReqd))
@@ -9744,35 +9683,14 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne
}
else
{
- GenTree* newTree;
- GenTree* addr = gtNewOperNode(GT_ADDR, TYP_BYREF, effectiveVal);
- if (isBlkReqd)
- {
- CORINFO_CLASS_HANDLE clsHnd = gtGetStructHandleIfPresent(effectiveVal);
- if (clsHnd == NO_CLASS_HANDLE)
- {
- newTree = new (this, GT_BLK) GenTreeBlk(GT_BLK, TYP_STRUCT, addr, typGetBlkLayout(blockWidth));
- }
- else
- {
- newTree = gtNewObjNode(clsHnd, addr);
- gtSetObjGcInfo(newTree->AsObj());
- }
-
- gtUpdateNodeSideEffects(newTree);
- }
- else
- {
- newTree = gtNewIndir(asgType, addr);
- }
-
- effectiveVal = newTree;
+ effectiveVal = gtNewStructVal(blockLayout, gtNewOperNode(GT_ADDR, TYP_BYREF, effectiveVal));
+ gtUpdateNodeSideEffects(effectiveVal);
}
}
}
+
assert(effectiveVal->TypeIs(asgType) || (varTypeIsSIMD(asgType) && varTypeIsStruct(effectiveVal)));
- tree = effectiveVal;
- return tree;
+ return effectiveVal;
}
// insert conversions and normalize to make tree amenable to register
@@ -9912,7 +9830,7 @@ GenTree* Compiler::getSIMDStructFromField(GenTree* tree,
{
ret = obj;
GenTreeVecCon* vecCon = obj->AsVecCon();
- *simdSizeOut = vecCon->GetSimdSize();
+ *simdSizeOut = genTypeSize(vecCon);
*simdBaseJitTypeOut = vecCon->GetSimdBaseJitType();
}
}
@@ -10362,8 +10280,8 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
case GT_FIELD:
return fgMorphField(tree, mac);
- case GT_INDEX:
- return fgMorphArrayIndex(tree);
+ case GT_INDEX_ADDR:
+ return fgMorphIndexAddr(tree->AsIndexAddr());
case GT_CAST:
{
@@ -10448,6 +10366,19 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
}
break;
+ case GT_IND:
+ if (opts.OptimizationEnabled() && !optValnumCSE_phase)
+ {
+ GenTree* constNode = gtFoldIndirConst(tree->AsIndir());
+ if (constNode != nullptr)
+ {
+ assert(constNode->OperIsConst()); // No further morphing required.
+ INDEBUG(constNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
+ return constNode;
+ }
+ }
+ break;
+
case GT_DIV:
// Replace "val / dcon" with "val * (1.0 / dcon)" if dcon is a power of two.
// Powers of two within range are always exactly represented,
@@ -11689,12 +11620,7 @@ DONE_MORPHING_CHILDREN:
temp = op1->AsOp()->gtOp1; // X
- // In the test below, if they're both TYP_STRUCT, this of course does *not* mean that
- // they are the *same* struct type. In fact, they almost certainly aren't. If the
- // address has an associated field sequence, that identifies this case; go through
- // the "lcl_fld" path rather than this one.
- FieldSeqNode* addrFieldSeq = nullptr; // This is an unused out parameter below.
- if (typ == temp->TypeGet() && !GetZeroOffsetFieldMap()->Lookup(op1, &addrFieldSeq))
+ if ((typ == temp->TypeGet()) && (typ != TYP_STRUCT))
{
foldAndReturnTemp = true;
}
@@ -11760,20 +11686,6 @@ DONE_MORPHING_CHILDREN:
tree->gtType = typ = temp->TypeGet();
foldAndReturnTemp = true;
}
- else
- {
- // Assumes that when Lookup returns "false" it will leave "fieldSeq" unmodified (i.e.
- // nullptr)
- assert(fieldSeq == nullptr);
- bool b = GetZeroOffsetFieldMap()->Lookup(op1, &fieldSeq);
- assert(b || fieldSeq == nullptr);
-
- if ((fieldSeq != nullptr) && (temp->OperGet() == GT_LCL_FLD))
- {
- temp->gtType = typ;
- foldAndReturnTemp = true;
- }
- }
// Otherwise will will fold this into a GT_LCL_FLD below
// where we check (temp != nullptr)
}
@@ -12944,6 +12856,16 @@ GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add)
return add;
}
+
+ // Fold (~x + 1) to -x.
+ if (op1->OperIs(GT_NOT) && op2->IsIntegralConst(1))
+ {
+ op1->SetOper(GT_NEG);
+ op1->SetVNsFromNode(add);
+ DEBUG_DESTROY_NODE(op2);
+ DEBUG_DESTROY_NODE(add);
+ return op1;
+ }
}
return nullptr;
@@ -17506,12 +17428,8 @@ bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement*
{
setLclRelatedToSIMDIntrinsic(simdStructNode);
}
- GenTree* copyBlkAddr = copyBlkDst;
- if (copyBlkAddr->gtOper == GT_LEA)
- {
- copyBlkAddr = copyBlkAddr->AsAddrMode()->Base();
- }
- GenTreeLclVarCommon* localDst = copyBlkAddr->IsLocalAddrExpr();
+
+ GenTreeLclVarCommon* localDst = copyBlkDst->IsLocalAddrExpr();
if (localDst != nullptr)
{
setLclRelatedToSIMDIntrinsic(localDst);
@@ -17678,10 +17596,13 @@ bool Compiler::fgCheckStmtAfterTailCall()
// fgCanTailCallViaJitHelper: check whether we can use the faster tailcall
// JIT helper on x86.
//
+// Arguments:
+// call - the tailcall
+//
// Return Value:
// 'true' if we can; or 'false' if we should use the generic tailcall mechanism.
//
-bool Compiler::fgCanTailCallViaJitHelper()
+bool Compiler::fgCanTailCallViaJitHelper(GenTreeCall* call)
{
#if !defined(TARGET_X86) || defined(UNIX_X86_ABI)
// On anything except windows X86 we have no faster mechanism available.
@@ -17690,11 +17611,22 @@ bool Compiler::fgCanTailCallViaJitHelper()
// For R2R make sure we go through portable mechanism that the 'EE' side
// will properly turn into a runtime JIT.
if (opts.IsReadyToRun())
+ {
return false;
+ }
// The JIT helper does not properly handle the case where localloc was used.
if (compLocallocUsed)
+ {
return false;
+ }
+
+ // Delegate calls may go through VSD stub in rare cases. Those look at the
+ // call site so we cannot use the JIT helper.
+ if (call->IsDelegateInvoke())
+ {
+ return false;
+ }
return true;
#endif
diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp
index 539a86b0496..bfc32adb980 100644
--- a/src/coreclr/jit/morphblock.cpp
+++ b/src/coreclr/jit/morphblock.cpp
@@ -36,6 +36,7 @@ protected:
GenTree* m_src = nullptr;
unsigned m_blockSize = 0;
+ ClassLayout* m_blockLayout = nullptr;
unsigned m_dstLclNum = BAD_VAR_NUM;
GenTreeLclVarCommon* m_dstLclNode = nullptr;
LclVarDsc* m_dstVarDsc = nullptr;
@@ -196,31 +197,10 @@ void MorphInitBlockHelper::PrepareDst()
m_dstVarDsc = m_comp->lvaGetDesc(m_dstLclNode);
m_dstLclOffset = m_dstLclNode->GetLclOffs();
- if (m_dst->OperIs(GT_LCL_VAR))
+ if (m_dst->TypeIs(TYP_STRUCT))
{
- if (m_dstVarDsc->TypeGet() == TYP_STRUCT)
- {
-#ifdef DEBUG
- const bool isSizeMistmatch =
- (m_dstVarDsc->lvExactSize != m_comp->info.compCompHnd->getClassSize(m_dstVarDsc->GetStructHnd()));
- const bool isStackAllocCandidate =
- m_comp->compObjectStackAllocation() && !m_dstVarDsc->GetLayout()->IsValueClass();
- // There were cases where for temps lvExactSize did not correspond to the struct size
- // so we were using `getClassSize` result here, however, now this cases are gone and the only
- // scenario when `getClassSize` != `lvExactSize` it is a class object optimized to be on stack
- assert(!isSizeMistmatch || isStackAllocCandidate);
-#endif // DEBUG
- m_blockSize = m_dstVarDsc->lvExactSize;
- }
- else
- {
- m_blockSize = genTypeSize(m_dstVarDsc);
- }
- }
- else
- {
- assert(m_dst->OperIs(GT_LCL_FLD) && !m_dst->TypeIs(TYP_STRUCT));
- m_blockSize = m_dst->AsLclFld()->GetSize();
+ assert(m_dstVarDsc->GetLayout()->GetSize() == m_dstVarDsc->lvExactSize);
+ m_blockLayout = m_dstLclNode->GetLayout(m_comp);
}
}
else
@@ -239,7 +219,20 @@ void MorphInitBlockHelper::PrepareDst()
m_dstLclOffset = static_cast<unsigned>(dstLclOffset);
}
- m_blockSize = m_dst->AsIndir()->Size();
+ if (m_dst->TypeIs(TYP_STRUCT))
+ {
+ m_blockLayout = m_dst->AsBlk()->GetLayout();
+ }
+ }
+
+ if (m_dst->TypeIs(TYP_STRUCT))
+ {
+ m_blockSize = m_blockLayout->GetSize();
+ }
+ else
+ {
+ assert(m_blockLayout == nullptr);
+ m_blockSize = genTypeSize(m_dst);
}
if (m_dstLclNode != nullptr)
@@ -332,7 +325,7 @@ void MorphInitBlockHelper::MorphStructCases()
if (m_transformationDecision == BlockTransformation::Undefined)
{
// For an InitBlock we always require a block operand.
- m_dst = m_comp->fgMorphBlockOperand(m_dst, m_dst->TypeGet(), m_blockSize, true /*isBlkReqd*/);
+ m_dst = m_comp->fgMorphBlockOperand(m_dst, m_dst->TypeGet(), m_blockLayout, true /*isBlkReqd*/);
m_transformationDecision = BlockTransformation::StructBlock;
m_dst->gtFlags |= GTF_DONT_CSE;
m_result = m_asg;
@@ -906,11 +899,11 @@ void MorphCopyBlockHelper::MorphStructCases()
{
const var_types asgType = m_dst->TypeGet();
bool isBlkReqd = (asgType == TYP_STRUCT);
- m_dst = m_comp->fgMorphBlockOperand(m_dst, asgType, m_blockSize, isBlkReqd);
+ m_dst = m_comp->fgMorphBlockOperand(m_dst, asgType, m_blockLayout, isBlkReqd);
m_dst->gtFlags |= GTF_DONT_CSE;
m_asg->gtOp1 = m_dst;
- m_src = m_comp->fgMorphBlockOperand(m_src, asgType, m_blockSize, isBlkReqd);
+ m_src = m_comp->fgMorphBlockOperand(m_src, asgType, m_blockLayout, isBlkReqd);
m_asg->gtOp2 = m_src;
m_asg->SetAllEffectsFlags(m_dst, m_src);
@@ -991,7 +984,7 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField()
else if (m_dstDoFldAsg)
{
fieldCnt = m_dstVarDsc->lvFieldCnt;
- m_src = m_comp->fgMorphBlockOperand(m_src, m_asg->TypeGet(), m_blockSize, false /*isBlkReqd*/);
+ m_src = m_comp->fgMorphBlockOperand(m_src, m_asg->TypeGet(), m_blockLayout, false /*isBlkReqd*/);
m_srcUseLclFld = m_srcVarDsc != nullptr;
if (!m_srcUseLclFld && (m_srcAddr == nullptr))
@@ -1025,7 +1018,7 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField()
{
assert(m_srcDoFldAsg);
fieldCnt = m_srcVarDsc->lvFieldCnt;
- m_dst = m_comp->fgMorphBlockOperand(m_dst, m_dst->TypeGet(), m_blockSize, false /*isBlkReqd*/);
+ m_dst = m_comp->fgMorphBlockOperand(m_dst, m_dst->TypeGet(), m_blockLayout, false /*isBlkReqd*/);
m_dstUseLclFld = m_dstVarDsc != nullptr;
if (m_dst->OperIsBlk())
diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp
index 242a79e5b25..ca034a141db 100644
--- a/src/coreclr/jit/optimizer.cpp
+++ b/src/coreclr/jit/optimizer.cpp
@@ -917,7 +917,7 @@ bool Compiler::optCheckIterInLoopTest(unsigned loopInd, GenTree* test, unsigned
}
else
{
- JITDUMP("Limit var %V02u modifiable in " FMT_LP "\n", limitOp->AsLclVarCommon()->GetLclNum(), loopInd);
+ JITDUMP("Limit var V%02u modifiable in " FMT_LP "\n", limitOp->AsLclVarCommon()->GetLclNum(), loopInd);
}
}
else if (limitOp->gtOper == GT_ARR_LENGTH)
@@ -934,7 +934,7 @@ bool Compiler::optCheckIterInLoopTest(unsigned loopInd, GenTree* test, unsigned
}
else
{
- JITDUMP("Array limit var %V02u modifiable in " FMT_LP "\n", array->AsLclVarCommon()->GetLclNum(),
+ JITDUMP("Array limit var V%02u modifiable in " FMT_LP "\n", array->AsLclVarCommon()->GetLclNum(),
loopInd);
}
}
@@ -5958,60 +5958,26 @@ bool Compiler::optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefK
return true;
}
- switch (loop->lpAsgCall)
+ // If caller is worried about possible indirect effects, check
+ // what we know about the calls in the loop.
+ //
+ if (inds != 0)
{
- case CALLINT_ALL:
-
- /* Can't hoist if the call might have side effect on an indirection. */
-
- if (loop->lpAsgInds != VR_NONE)
- {
- return true;
- }
-
- break;
-
- case CALLINT_REF_INDIRS:
-
- /* Can't hoist if the call might have side effect on an ref indirection. */
-
- if (loop->lpAsgInds & VR_IND_REF)
- {
- return true;
- }
-
- break;
-
- case CALLINT_SCL_INDIRS:
-
- /* Can't hoist if the call might have side effect on an non-ref indirection. */
-
- if (loop->lpAsgInds & VR_IND_SCL)
- {
- return true;
- }
-
- break;
-
- case CALLINT_ALL_INDIRS:
-
- /* Can't hoist if the call might have side effect on any indirection. */
-
- if (loop->lpAsgInds & (VR_IND_REF | VR_IND_SCL))
- {
+ switch (loop->lpAsgCall)
+ {
+ case CALLINT_ALL:
return true;
- }
-
- break;
-
- case CALLINT_NONE:
-
- /* Other helpers kill nothing */
-
- break;
-
- default:
- noway_assert(!"Unexpected lpAsgCall value");
+ case CALLINT_REF_INDIRS:
+ return (inds & VR_IND_REF) != 0;
+ case CALLINT_SCL_INDIRS:
+ return (inds & VR_IND_SCL) != 0;
+ case CALLINT_ALL_INDIRS:
+ return (inds & (VR_IND_REF | VR_IND_SCL)) != 0;
+ case CALLINT_NONE:
+ return false;
+ default:
+ noway_assert(!"Unexpected lpAsgCall value");
+ }
}
return false;
diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp
index 27462c0a44e..e6b7e1a4d92 100644
--- a/src/coreclr/jit/rationalize.cpp
+++ b/src/coreclr/jit/rationalize.cpp
@@ -670,16 +670,6 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge
unsigned simdSize = simdNode->GetSimdSize();
var_types simdType = comp->getSIMDTypeForSize(simdSize);
- // TODO-1stClassStructs: This should be handled more generally for enregistered or promoted
- // structs that are passed or returned in a different register type than their enregistered
- // type(s).
- if (simdNode->gtType == TYP_I_IMPL && simdNode->GetSimdSize() == TARGET_POINTER_SIZE)
- {
- // This happens when it is consumed by a GT_RET_EXPR.
- // It can only be a Vector2f or Vector2i.
- assert(genTypeSize(simdNode->GetSimdBaseType()) == 4);
- simdNode->gtType = TYP_SIMD8;
- }
// Certain SIMD trees require rationalizing.
if (simdNode->AsSIMD()->GetSIMDIntrinsicId() == SIMDIntrinsicInitArray)
{
@@ -700,75 +690,10 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge
DISPTREERANGE(BlockRange(), use.Def());
JITDUMP("\n");
}
- else
- {
- // This code depends on the fact that NONE of the SIMD intrinsics take vector operands
- // of a different width. If that assumption changes, we will EITHER have to make these type
- // transformations during importation, and plumb the types all the way through the JIT,
- // OR add a lot of special handling here.
-
- // TODO-Review: the comment above seems outdated. TYP_SIMDs have been "plumbed through" the Jit.
- // It may be that this code is actually dead.
- for (GenTree* operand : simdNode->Operands())
- {
- if (operand->TypeIs(TYP_STRUCT))
- {
- operand->ChangeType(simdType);
- }
- }
- }
}
break;
#endif // FEATURE_SIMD
-#ifdef FEATURE_HW_INTRINSICS
- case GT_HWINTRINSIC:
- {
- GenTreeHWIntrinsic* hwIntrinsicNode = node->AsHWIntrinsic();
-
- if (!hwIntrinsicNode->isSIMD())
- {
- break;
- }
-
- // TODO-1stClassStructs: This should be handled more generally for enregistered or promoted
- // structs that are passed or returned in a different register type than their enregistered
- // type(s).
- if ((hwIntrinsicNode->gtType == TYP_I_IMPL) && (hwIntrinsicNode->GetSimdSize() == TARGET_POINTER_SIZE))
- {
-#ifdef TARGET_ARM64
- // Special case for GetElement/ToScalar because they take Vector64<T> and return T
- // and T can be long or ulong.
- if (!((hwIntrinsicNode->GetHWIntrinsicId() == NI_Vector64_GetElement) ||
- (hwIntrinsicNode->GetHWIntrinsicId() == NI_Vector64_ToScalar)))
-#endif
- {
- // This happens when it is consumed by a GT_RET_EXPR.
- // It can only be a Vector2f or Vector2i.
- assert(genTypeSize(hwIntrinsicNode->GetSimdBaseType()) == 4);
- hwIntrinsicNode->gtType = TYP_SIMD8;
- }
- }
- break;
- }
-#endif // FEATURE_HW_INTRINSICS
-
-#if defined(FEATURE_SIMD)
- case GT_CNS_VEC:
- {
- GenTreeVecCon* vecCon = node->AsVecCon();
-
- // TODO-1stClassStructs: do not retype SIMD nodes
-
- if ((vecCon->TypeIs(TYP_I_IMPL)) && (vecCon->GetSimdSize() == TARGET_POINTER_SIZE))
- {
- assert(genTypeSize(vecCon->GetSimdBaseType()) == 4);
- vecCon->gtType = TYP_SIMD8;
- }
- break;
- }
-#endif // FEATURE_SIMD
-
default:
// Check that we don't have nodes not allowed in HIR here.
assert((node->DebugOperKind() & DBK_NOTHIR) == 0);
diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp
index 45868e524f1..92706856a0d 100644
--- a/src/coreclr/jit/simd.cpp
+++ b/src/coreclr/jit/simd.cpp
@@ -1639,30 +1639,31 @@ bool Compiler::areLocalFieldsContiguous(GenTreeLclFld* first, GenTreeLclFld* sec
// TODO-CQ:
// Right this can only check array element with const number as index. In future,
// we should consider to allow this function to check the index using expression.
-
+//
bool Compiler::areArrayElementsContiguous(GenTree* op1, GenTree* op2)
{
- noway_assert(op1->gtOper == GT_INDEX);
- noway_assert(op2->gtOper == GT_INDEX);
- GenTreeIndex* op1Index = op1->AsIndex();
- GenTreeIndex* op2Index = op2->AsIndex();
+ assert(op1->OperIs(GT_IND) && op2->OperIs(GT_IND));
+ assert(!op1->TypeIs(TYP_STRUCT) && (op1->TypeGet() == op2->TypeGet()));
- GenTree* op1ArrayRef = op1Index->Arr();
- GenTree* op2ArrayRef = op2Index->Arr();
+ GenTreeIndexAddr* op1IndexAddr = op1->AsIndir()->Addr()->AsIndexAddr();
+ GenTreeIndexAddr* op2IndexAddr = op2->AsIndir()->Addr()->AsIndexAddr();
+
+ GenTree* op1ArrayRef = op1IndexAddr->Arr();
+ GenTree* op2ArrayRef = op2IndexAddr->Arr();
assert(op1ArrayRef->TypeGet() == TYP_REF);
assert(op2ArrayRef->TypeGet() == TYP_REF);
- GenTree* op1IndexNode = op1Index->Index();
- GenTree* op2IndexNode = op2Index->Index();
+ GenTree* op1IndexNode = op1IndexAddr->Index();
+ GenTree* op2IndexNode = op2IndexAddr->Index();
if ((op1IndexNode->OperGet() == GT_CNS_INT && op2IndexNode->OperGet() == GT_CNS_INT) &&
op1IndexNode->AsIntCon()->gtIconVal + 1 == op2IndexNode->AsIntCon()->gtIconVal)
{
- if (op1ArrayRef->OperGet() == GT_FIELD && op2ArrayRef->OperGet() == GT_FIELD &&
+ if (op1ArrayRef->OperIs(GT_FIELD) && op2ArrayRef->OperIs(GT_FIELD) &&
areFieldsParentsLocatedSame(op1ArrayRef, op2ArrayRef))
{
return true;
}
- else if (op1ArrayRef->OperIsLocal() && op2ArrayRef->OperIsLocal() &&
+ else if (op1ArrayRef->OperIs(GT_LCL_VAR) && op2ArrayRef->OperIs(GT_LCL_VAR) &&
op1ArrayRef->AsLclVarCommon()->GetLclNum() == op2ArrayRef->AsLclVarCommon()->GetLclNum())
{
return true;
@@ -1682,14 +1683,13 @@ bool Compiler::areArrayElementsContiguous(GenTree* op1, GenTree* op2)
// TODO-CQ:
// Right now this can only check field and array. In future we should add more cases.
//
-
bool Compiler::areArgumentsContiguous(GenTree* op1, GenTree* op2)
{
- if (op1->OperGet() == GT_INDEX && op2->OperGet() == GT_INDEX)
+ if (op1->OperIs(GT_IND) && op2->OperIs(GT_IND))
{
return areArrayElementsContiguous(op1, op2);
}
- else if (op1->OperGet() == GT_FIELD && op2->OperGet() == GT_FIELD)
+ else if (op1->OperIs(GT_FIELD) && op2->OperIs(GT_FIELD))
{
return areFieldsContiguous(op1, op2);
}
@@ -1701,7 +1701,7 @@ bool Compiler::areArgumentsContiguous(GenTree* op1, GenTree* op2)
}
//--------------------------------------------------------------------------------------------------------
-// createAddressNodeForSIMDInit: Generate the address node(GT_LEA) if we want to intialize vector2, vector3 or vector4
+// createAddressNodeForSIMDInit: Generate the address node if we want to intialize vector2, vector3 or vector4
// from first argument's address.
//
// Arguments:
@@ -1713,19 +1713,16 @@ bool Compiler::areArgumentsContiguous(GenTree* op1, GenTree* op2)
// return the address node.
//
// TODO-CQ:
-// 1. Currently just support for GT_FIELD and GT_INDEX, because we can only verify the GT_INDEX node or GT_Field
-// are located contiguously or not. In future we should support more cases.
-// 2. Though it happens to just work fine front-end phases are not aware of GT_LEA node. Therefore, convert these
-// to use GT_ADDR.
+// Currently just supports GT_FIELD and GT_IND(GT_INDEX_ADDR), because we can only verify those nodes
+// are located contiguously or not. In future we should support more cases.
+//
GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize)
{
- assert(tree->OperGet() == GT_FIELD || tree->OperGet() == GT_INDEX);
- GenTree* byrefNode = nullptr;
- GenTree* startIndex = nullptr;
- unsigned offset = 0;
- var_types baseType = tree->gtType;
+ GenTree* byrefNode = nullptr;
+ unsigned offset = 0;
+ var_types baseType = tree->gtType;
- if (tree->OperGet() == GT_FIELD)
+ if (tree->OperIs(GT_FIELD))
{
GenTree* objRef = tree->AsField()->GetFldObj();
if (objRef != nullptr && objRef->gtOper == GT_ADDR)
@@ -1753,23 +1750,25 @@ GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize
assert(byrefNode != nullptr);
offset = tree->AsField()->gtFldOffset;
}
- else if (tree->OperGet() == GT_INDEX)
+ else
{
+ assert(tree->OperIs(GT_IND) && tree->AsIndir()->Addr()->OperIs(GT_INDEX_ADDR));
- GenTree* index = tree->AsIndex()->Index();
- assert(index->OperGet() == GT_CNS_INT);
+ GenTreeIndexAddr* indexAddr = tree->AsIndir()->Addr()->AsIndexAddr();
+ GenTree* arrayRef = indexAddr->Arr();
+ GenTree* index = indexAddr->Index();
+ assert(index->IsCnsIntOrI());
GenTree* checkIndexExpr = nullptr;
- unsigned indexVal = (unsigned)(index->AsIntCon()->gtIconVal);
+ unsigned indexVal = (unsigned)index->AsIntCon()->gtIconVal;
offset = indexVal * genTypeSize(tree->TypeGet());
- GenTree* arrayRef = tree->AsIndex()->Arr();
// Generate the boundary check exception.
// The length for boundary check should be the maximum index number which should be
// (first argument's index number) + (how many array arguments we have) - 1
// = indexVal + arrayElementsCount - 1
unsigned arrayElementsCount = simdSize / genTypeSize(baseType);
- checkIndexExpr = new (this, GT_CNS_INT) GenTreeIntCon(TYP_INT, indexVal + arrayElementsCount - 1);
+ checkIndexExpr = gtNewIconNode(indexVal + arrayElementsCount - 1);
GenTreeArrLen* arrLen = gtNewArrLen(TYP_INT, arrayRef, (int)OFFSETOF__CORINFO_Array__length, compCurBB);
GenTreeBoundsChk* arrBndsChk =
new (this, GT_BOUNDS_CHECK) GenTreeBoundsChk(checkIndexExpr, arrLen, SCK_ARG_RNG_EXCPN);
@@ -1777,12 +1776,9 @@ GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize
offset += OFFSETOF__CORINFO_Array__data;
byrefNode = gtNewOperNode(GT_COMMA, arrayRef->TypeGet(), arrBndsChk, gtCloneExpr(arrayRef));
}
- else
- {
- unreached();
- }
- GenTree* address =
- new (this, GT_LEA) GenTreeAddrMode(TYP_BYREF, byrefNode, startIndex, genTypeSize(tree->TypeGet()), offset);
+
+ GenTree* address = gtNewOperNode(GT_ADD, TYP_BYREF, byrefNode, gtNewIconNode(offset, TYP_I_IMPL));
+
return address;
}
@@ -1793,7 +1789,7 @@ GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize
//
// Arguments:
// stmt - GenTree*. Input statement node.
-
+//
void Compiler::impMarkContiguousSIMDFieldAssignments(Statement* stmt)
{
if (opts.OptimizationDisabled())
@@ -2227,12 +2223,21 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE opcode,
assert(op1->TypeGet() == simdType);
// copy vector (op1) to array (op2) starting at index (op3)
- simdTree = op1;
+ simdTree = op1;
+ copyBlkDst = op2;
+ if (op3 != nullptr)
+ {
+#ifdef TARGET_64BIT
+ // Upcast the index: it is safe to use a zero-extending cast since we've bounds checked it above.
+ op3 = gtNewCastNode(TYP_I_IMPL, op3, /* fromUnsigned */ true, TYP_I_IMPL);
+#endif // !TARGET_64BIT
+ GenTree* elemSizeNode = gtNewIconNode(genTypeSize(simdBaseType), TYP_I_IMPL);
+ GenTree* indexOffs = gtNewOperNode(GT_MUL, TYP_I_IMPL, op3, elemSizeNode);
+ copyBlkDst = gtNewOperNode(GT_ADD, TYP_BYREF, copyBlkDst, indexOffs);
+ }
- // TODO-Cleanup: Though it happens to just work fine front-end phases are not aware of GT_LEA node.
- // Therefore, convert these to use GT_ADDR .
- copyBlkDst = new (this, GT_LEA)
- GenTreeAddrMode(TYP_BYREF, op2, op3, genTypeSize(simdBaseType), OFFSETOF__CORINFO_Array__data);
+ copyBlkDst = gtNewOperNode(GT_ADD, TYP_BYREF, copyBlkDst,
+ gtNewIconNode(OFFSETOF__CORINFO_Array__data, TYP_I_IMPL));
doCopyBlk = true;
}
}
diff --git a/src/coreclr/jit/unwindamd64.cpp b/src/coreclr/jit/unwindamd64.cpp
index caaf7c2dbe2..2c8e90fa5a9 100644
--- a/src/coreclr/jit/unwindamd64.cpp
+++ b/src/coreclr/jit/unwindamd64.cpp
@@ -656,11 +656,21 @@ void Compiler::unwindReserve()
//
void Compiler::unwindReserveFunc(FuncInfoDsc* func)
{
- unwindReserveFuncHelper(func, true);
-
- if (fgFirstColdBlock != nullptr)
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr))
{
- unwindReserveFuncHelper(func, false);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
+ unwindReserveFuncHelper(func, true);
+ }
+ else
+#endif // DEBUG
+ {
+ unwindReserveFuncHelper(func, true);
+
+ if (fgFirstColdBlock != nullptr)
+ {
+ unwindReserveFuncHelper(func, false);
+ }
}
}
@@ -880,12 +890,43 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode
static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
- unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != nullptr))
+ {
+ fakeUnwindEmitFuncHelper(func, pHotCode);
+ }
+ else
+#endif // DEBUG
+ {
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
+
+ if (pColdCode != nullptr)
+ {
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ }
+ }
+}
+
+#ifdef DEBUG
+void Compiler::fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode)
+{
+ assert(fgFirstColdBlock != nullptr);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
- if (pColdCode != nullptr)
+ const UNATIVE_OFFSET startOffset = 0;
+ const UNATIVE_OFFSET endOffset = info.compNativeCodeSize;
+ const DWORD unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
+ BYTE* pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot];
+
+ if (opts.dspUnwind)
{
- unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ DumpUnwindInfo(true, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock);
}
+
+ // Pass pColdCode = nullptr; VM allocs unwind info for combined hot/cold section
+ eeAllocUnwindInfo((BYTE*)pHotCode, nullptr, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
+ (CorJitFuncKind)func->funKind);
}
+#endif // DEBUG
#endif // TARGET_AMD64
diff --git a/src/coreclr/jit/unwindx86.cpp b/src/coreclr/jit/unwindx86.cpp
index 0cd88fd29ba..bd27e46cbef 100644
--- a/src/coreclr/jit/unwindx86.cpp
+++ b/src/coreclr/jit/unwindx86.cpp
@@ -113,11 +113,21 @@ void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
//
void Compiler::unwindReserveFunc(FuncInfoDsc* func)
{
- unwindReserveFuncHelper(func, true);
-
- if (fgFirstColdBlock != nullptr)
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr))
{
- unwindReserveFuncHelper(func, false);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
+ unwindReserveFuncHelper(func, true);
+ }
+ else
+#endif // DEBUG
+ {
+ unwindReserveFuncHelper(func, true);
+
+ if (fgFirstColdBlock != nullptr)
+ {
+ unwindReserveFuncHelper(func, false);
+ }
}
}
@@ -154,11 +164,20 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode
static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
- unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
-
- if (pColdCode != nullptr)
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != nullptr))
+ {
+ fakeUnwindEmitFuncHelper(func, pHotCode);
+ }
+ else
+#endif // DEBUG
{
- unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
+
+ if (pColdCode != nullptr)
+ {
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ }
}
}
@@ -256,4 +275,23 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo
eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, sizeof(UNWIND_INFO),
(BYTE*)&unwindInfo, (CorJitFuncKind)func->funKind);
}
+
+#ifdef DEBUG
+void Compiler::fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode)
+{
+ assert(fgFirstColdBlock != nullptr);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
+
+ const UNATIVE_OFFSET startOffset = 0;
+ const UNATIVE_OFFSET endOffset = info.compNativeCodeSize;
+
+ UNWIND_INFO unwindInfo;
+ unwindInfo.FunctionLength = (ULONG)(endOffset);
+
+ // Pass pColdCode = nullptr; VM allocs unwind info for combined hot/cold section
+ eeAllocUnwindInfo((BYTE*)pHotCode, nullptr, startOffset, endOffset, sizeof(UNWIND_INFO), (BYTE*)&unwindInfo,
+ (CorJitFuncKind)func->funKind);
+}
+#endif // DEBUG
+
#endif // FEATURE_EH_FUNCLETS
diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp
index 47a311ef2e1..be7fc14611f 100644
--- a/src/coreclr/jit/valuenum.cpp
+++ b/src/coreclr/jit/valuenum.cpp
@@ -7959,16 +7959,6 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree)
tree->gtVNPair.SetBoth(
vnStore->VNForHandle(ssize_t(tree->AsIntConCommon()->IconValue()), tree->GetIconHandleFlag()));
}
-#ifdef FEATURE_SIMD
- else if (tree->IsCnsVec())
- {
- // TODO-1stClassStructs: do not retype SIMD nodes
- assert(varTypeIsLong(typ));
-
- simd8_t simd8Val = tree->AsVecCon()->gtSimd8Val;
- tree->gtVNPair.SetBoth(vnStore->VNForSimd8Con(simd8Val));
- }
-#endif // FEATURE_SIMD
else if ((typ == TYP_LONG) || (typ == TYP_ULONG))
{
tree->gtVNPair.SetBoth(vnStore->VNForLongCon(INT64(tree->AsIntConCommon()->LngValue())));
@@ -8061,18 +8051,7 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree)
case TYP_DOUBLE:
{
-#ifdef FEATURE_SIMD
- if (tree->IsCnsVec())
- {
- // TODO-1stClassStructs: do not retype SIMD nodes
- simd8_t simd8Val = tree->AsVecCon()->gtSimd8Val;
- tree->gtVNPair.SetBoth(vnStore->VNForSimd8Con(simd8Val));
- }
- else
-#endif // FEATURE_SIMD
- {
- tree->gtVNPair.SetBoth(vnStore->VNForDoubleCon(tree->AsDblCon()->gtDconVal));
- }
+ tree->gtVNPair.SetBoth(vnStore->VNForDoubleCon(tree->AsDblCon()->gtDconVal));
break;
}
@@ -8806,17 +8785,6 @@ void Compiler::fgValueNumberTree(GenTree* tree)
{
assert(oper != GT_ASG); // We handled assignments earlier.
assert(GenTree::OperIsBinary(oper));
- // Standard binary operator.
- ValueNumPair op2VNPair;
- if (tree->AsOp()->gtOp2 == nullptr)
- {
- // Handle any GT_LEA nodes as they can have a nullptr for op2.
- op2VNPair.SetBoth(ValueNumStore::VNForNull());
- }
- else
- {
- op2VNPair = tree->AsOp()->gtOp2->gtVNPair;
- }
// Handle a few special cases: if we add a field offset constant to a PtrToXXX, we will get back a
// new
@@ -8828,7 +8796,7 @@ void Compiler::fgValueNumberTree(GenTree* tree)
ValueNumPair op2vnp;
ValueNumPair op2Xvnp;
- vnStore->VNPUnpackExc(op2VNPair, &op2vnp, &op2Xvnp);
+ vnStore->VNPUnpackExc(tree->AsOp()->gtOp2->gtVNPair, &op2vnp, &op2Xvnp);
ValueNumPair excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp);
ValueNum newVN = ValueNumStore::NoVN;
diff --git a/src/coreclr/jit/varset.h b/src/coreclr/jit/varset.h
index 88f86394376..c4cba1b5779 100644
--- a/src/coreclr/jit/varset.h
+++ b/src/coreclr/jit/varset.h
@@ -111,7 +111,7 @@ typedef BitSetOpsWithCounter<VARSET_TP,
typedef VarSetOpsRaw VarSetOps;
#endif
-#define ALLVARSET_REP BSUInt64
+#define ALLVARSET_REP BSShortLong
#if ALLVARSET_REP == BSUInt64
@@ -141,7 +141,8 @@ typedef BitSetOps</*BitSetType*/ BitSetShortLongRep,
typedef BitSetShortLongRep ALLVARSET_TP;
-const unsigned lclMAX_ALLSET_TRACKED = lclMAX_TRACKED;
+// default value for JitConfig.JitMaxLocalsToTrack()
+const unsigned lclMAX_ALLSET_TRACKED = 0x400;
#define ALLVARSET_REP_IS_CLASS 0
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
index 5ad1cf0d155..a5970704a52 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
@@ -86,15 +86,17 @@
</Target>
<Target Name="CopyNativeBinary" AfterTargets="Publish">
- <!-- override apphost with binary we generated during native compilation -->
+ <!-- replace apphost with binary we generated during native compilation -->
<Delete Files="$(PublishDir)\$(TargetName)$(NativeBinaryExt)" />
<Copy SourceFiles="$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)" DestinationFolder="$(PublishDir)" />
- </Target>
- <Target Name="CopyNativePdb" Condition="'$(DebugType)' != 'None' and '$(TargetOS)' == 'windows' and '$(NativeLib)' != 'Static'" AfterTargets="Publish">
- <!-- dotnet CLI produces managed debug symbols - substitute with those we generated during native compilation -->
+ <!-- dotnet CLI produces managed debug symbols, which we will delete and copy native symbols instead -->
<Delete Files="$(PublishDir)\$(TargetName).pdb" />
- <Copy SourceFiles="$(NativeOutputPath)$(TargetName).pdb" DestinationFolder="$(PublishDir)" />
+
+ <!-- replace native symbol file if it exists -->
+ <Delete Files="$(PublishDir)\$(TargetName)$(NativeBinaryExt)$(NativeSymbolExt)" />
+ <Copy SourceFiles="$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)$(NativeSymbolExt)" DestinationFolder="$(PublishDir)"
+ Condition="Exists('$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)$(NativeSymbolExt)')" />
</Target>
</Project>
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props
index 19f4d8604dd..b150bf6392c 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props
@@ -14,10 +14,13 @@ The .NET Foundation licenses this file to you under the MIT license.
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
- <CppCompilerAndLinker Condition="'$(CppCompilerAndLinker)' == ''">clang</CppCompilerAndLinker>
+ <CustomToolchainSpecified Condition="'$(CppCompilerAndLinker)' != ''">true</CustomToolchainSpecified>
+ <CppCompilerAndLinker Condition="'$(CustomToolchainSpecified)' != 'true'">clang</CppCompilerAndLinker>
+ <CppCompilerAndLinkerAlternative Condition="'$(CustomToolchainSpecified)' != 'true' and '$(TargetOS)' != 'OSX'">gcc</CppCompilerAndLinkerAlternative>
<CppCompiler>$(CppCompilerAndLinker)</CppCompiler>
<CppLinker>$(CppCompilerAndLinker)</CppLinker>
<CppLibCreator>ar</CppLibCreator>
+ <DsymUtilOptions Condition="'$(TargetOS)' == 'OSX'">--flat</DsymUtilOptions>
</PropertyGroup>
<Target Name="SetupOSSpecificProps" DependsOnTargets="$(IlcDynamicBuildPropertyDependencies)">
@@ -106,7 +109,42 @@ The .NET Foundation licenses this file to you under the MIT license.
<Exec Command="command -v $(CppLinker)" IgnoreExitCode="true" StandardOutputImportance="Low">
<Output TaskParameter="ExitCode" PropertyName="_WhereLinker" />
</Exec>
- <Error Condition="'$(_WhereLinker)' != '0' and '$(TargetOS)' == 'OSX'" Text="Platform linker ('$(CppLinker)') not found. Try installing Xcode to resolve the problem." />
- <Error Condition="'$(_WhereLinker)' != '0' and '$(TargetOS)' != 'OSX'" Text="Platform linker ('$(CppLinker)') not found. Try installing $(CppLinker) or the appropriate package for your platform to resolve the problem." />
+
+ <Exec Command="command -v $(CppCompilerAndLinkerAlternative)" Condition="'$(CppCompilerAndLinkerAlternative)' != '' and '$(_WhereLinker)' != '0'" IgnoreExitCode="true" StandardOutputImportance="Low">
+ <Output TaskParameter="ExitCode" PropertyName="_WhereLinkerAlt" />
+ </Exec>
+
+ <PropertyGroup Condition="'$(CppCompilerAndLinkerAlternative)' != '' and '$(_WhereLinker)' != '0' and '$(_WhereLinkerAlt)' == '0'">
+ <CppCompilerAndLinker>$(CppCompilerAndLinkerAlternative)</CppCompilerAndLinker>
+ <CppCompiler>$(CppCompilerAndLinker)</CppCompiler>
+ <CppLinker>$(CppCompilerAndLinker)</CppLinker>
+ <_WhereLinker>0</_WhereLinker>
+ </PropertyGroup>
+
+ <Error Condition="'$(_WhereLinker)' != '0' and '$(TargetOS)' == 'OSX'" Text="Platform linker ('$(CppLinker)') not found in PATH. Try installing Xcode to resolve the problem." />
+ <Error Condition="'$(_WhereLinker)' != '0' and '$(CppCompilerAndLinkerAlternative)' != ''"
+ Text="Platform linker ('$(CppLinker)' or '$(CppCompilerAndLinkerAlternative)') not found in PATH. Try installing appropriate package for $(CppLinker) or $(CppCompilerAndLinkerAlternative) to resolve the problem." />
+ <Error Condition="'$(_WhereLinker)' != '0' and '$(CppCompilerAndLinkerAlternative)' == '' and '$(TargetOS)' != 'OSX'"
+ Text="Requested linker ('$(CppLinker)') not found in PATH." />
+
+ <Exec Command="command -v objcopy" IgnoreExitCode="true" StandardOutputImportance="Low" Condition="'$(TargetOS)' != 'OSX' and '$(StripSymbols)' == 'true'">
+ <Output TaskParameter="ExitCode" PropertyName="_WhereSymbolStripper" />
+ </Exec>
+ <Error Condition="'$(_WhereSymbolStripper)' != '0' and '$(StripSymbols)' == 'true' and '$(TargetOS)' != 'OSX'"
+ Text="Symbol stripping tool ('objcopy') not found in PATH. Make sure 'objcopy' is available in PATH" />
+
+ <Exec Command="command -v dsymutil &amp;&amp; command -v strip" IgnoreExitCode="true" StandardOutputImportance="Low" Condition="'$(TargetOS)' == 'OSX' and '$(StripSymbols)' == 'true'">
+ <Output TaskParameter="ExitCode" PropertyName="_WhereSymbolStripper" />
+ </Exec>
+ <Error Condition="'$(_WhereSymbolStripper)' != '0' and '$(StripSymbols)' == 'true' and '$(TargetOS)' != 'OSX'"
+ Text="Symbol stripping tools ('dsymutil' and 'strip') not found in PATH. Make sure 'dsymutil' and 'strip' are available in PATH" />
+
+ <Exec Command="dsymutil --help" IgnoreExitCode="true" StandardOutputImportance="Low" Condition="'$(TargetOS)' == 'OSX' and '$(StripSymbols)' == 'true'">
+ <Output TaskParameter="ExitCode" PropertyName="_DsymUtilOutput" />
+ </Exec>
+
+ <PropertyGroup Condition="'$(TargetOS)' == 'OSX' and '$(StripSymbols)' == 'true' and $(_DsymUtilOutput.Contains('--minimize'))">
+ <DsymUtilOptions>$(DsymUtilOptions) --minimize</DsymUtilOptions>
+ </PropertyGroup>
</Target>
</Project>
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
index ef10a3e41d7..d5c08a768d9 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -70,6 +70,10 @@ The .NET Foundation licenses this file to you under the MIT license.
<NativeBinaryExt Condition="'$(IsNativeExecutable)' != 'true' and '$(TargetOS)' == 'windows' and $(NativeLib) == 'Static'">.lib</NativeBinaryExt>
<NativeBinaryExt Condition="'$(IsNativeExecutable)' != 'true' and '$(TargetOS)' != 'windows' and $(NativeLib) == 'Static'">.a</NativeBinaryExt>
+ <NativeSymbolExt Condition="'$(TargetOS)' == 'OSX'">.dwarf</NativeSymbolExt>
+ <NativeSymbolExt Condition="'$(TargetOS)' == 'windows'">.pdb</NativeSymbolExt>
+ <NativeSymbolExt Condition="'$(TargetOS)' != 'OSX' and '$(TargetOS)' != 'windows'">.dbg</NativeSymbolExt>
+
<ExportsFileExt Condition="'$(TargetOS)' == 'windows'">.def</ExportsFileExt>
<ExportsFileExt Condition="'$(TargetOS)' != 'windows'">.exports</ExportsFileExt>
@@ -341,6 +345,16 @@ The .NET Foundation licenses this file to you under the MIT license.
<Exec Command="$(CppLinker) @&quot;$(NativeIntermediateOutputPath)link.rsp&quot;" Condition="'$(TargetOS)' == 'windows' and '$(NativeLib)' != 'Static'" />
<WriteLinesToFile File="$(NativeIntermediateOutputPath)lib.rsp" Lines="@(CustomLibArg)" Overwrite="true" Encoding="utf-8" Condition="'$(TargetOS)' == 'windows' and '$(NativeLib)' == 'Static'" />
<Exec Command="$(CppLibCreator) @&quot;$(NativeIntermediateOutputPath)lib.rsp&quot;" Condition="'$(TargetOS)' == 'windows' and '$(NativeLib)' == 'Static'" />
+
+ <!-- strip symbols, see https://github.com/dotnet/runtime/blob/5d3288d/eng/native/functions.cmake#L374 -->
+ <Exec Condition="'$(StripSymbols)' == 'true' and '$(TargetOS)' != 'windows' and '$(TargetOS)' != 'OSX'"
+ Command="
+ objcopy --only-keep-debug &quot;$(NativeBinary)&quot; &quot;$(NativeBinary)$(NativeSymbolExt)&quot; &amp;&amp;
+ objcopy --strip-unneeded &quot;$(NativeBinary)&quot; &amp;&amp;
+ objcopy --add-gnu-debuglink=&quot;$(NativeBinary)$(NativeSymbolExt)&quot; &quot;$(NativeBinary)&quot;" />
+
+ <Exec Condition="'$(StripSymbols)' == 'true' and '$(TargetOS)' == 'OSX'" Command="dsymutil $(DsymUtilOptions) &quot;$(NativeBinary)&quot;" />
+ <Exec Condition="'$(StripSymbols)' == 'true' and '$(TargetOS)' == 'OSX'" Command="strip -no_code_signature_warning -S &quot;$(NativeBinary)&quot;" />
</Target>
<Target Name="CreateLib"
diff --git a/src/coreclr/nativeaot/Runtime/CommonMacros.h b/src/coreclr/nativeaot/Runtime/CommonMacros.h
index 46fdcea69da..97f3b32ef4c 100644
--- a/src/coreclr/nativeaot/Runtime/CommonMacros.h
+++ b/src/coreclr/nativeaot/Runtime/CommonMacros.h
@@ -250,4 +250,33 @@ typedef int32_t HRESULT;
#endif // !defined(_INC_WINDOWS)
#endif // __GCENV_BASE_INCLUDED__
+// PAL Numbers
+// Used to ensure cross-compiler compatibility when declaring large
+// integer constants. 64-bit integer constants should be wrapped in the
+// declarations listed here.
+//
+// Each of the #defines here is wrapped to avoid conflicts with pal.h.
+
+#if defined(_MSC_VER)
+
+// MSVC's way of declaring large integer constants
+// If you define these in one step, without the _HELPER macros, you
+// get extra whitespace when composing these with other concatenating macros.
+#ifndef I64
+#define I64_HELPER(x) x ## i64
+#define I64(x) I64_HELPER(x)
+#endif
+
+#else
+
+// GCC's way of declaring large integer constants
+// If you define these in one step, without the _HELPER macros, you
+// get extra whitespace when composing these with other concatenating macros.
+#ifndef I64
+#define I64_HELPER(x) x ## LL
+#define I64(x) I64_HELPER(x)
+#endif
+
+#endif
+
#endif // __COMMONMACROS_H__
diff --git a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp
index c5bc94ee09a..9ad553ce156 100644
--- a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp
+++ b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp
@@ -9,9 +9,29 @@
// Floating point and 64-bit integer math helpers.
//
+FORCEINLINE int64_t FastDbl2Lng(double val)
+{
+#ifdef TARGET_X86
+ return HCCALL1_V(JIT_Dbl2Lng, val);
+#else
+ return((__int64) val);
+#endif
+}
+
EXTERN_C NATIVEAOT_API uint64_t REDHAWK_CALLCONV RhpDbl2ULng(double val)
{
- return((uint64_t)val);
+ const double two63 = 2147483648.0 * 4294967296.0;
+ uint64_t ret;
+ if (val < two63)
+ {
+ ret = FastDbl2Lng(val);
+ }
+ else
+ {
+ // subtract 0x8000000000000000, do the convert then add it back again
+ ret = FastDbl2Lng(val - two63) + I64(0x8000000000000000);
+ }
+ return ret;
}
#undef min
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 1a733160dac..84956fa8e37 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
@@ -81,6 +81,9 @@
<Compile Include="$(CompilerCommonPath)\Internal\NativeFormat\NativeFormatReader.cs">
<Link>Common\src\Internal\NativeFormat\NativeFormatReader.cs</Link>
</Compile>
+ <Compile Include="$(CompilerCommonPath)\Internal\NativeFormat\NativeFormatReader.Primitives.cs">
+ <Link>Common\src\Internal\NativeFormat\NativeFormatReader.Primitives.cs</Link>
+ </Compile>
<Compile Include="$(CompilerCommonPath)\Internal\NativeFormat\NativeFormatReader.String.cs">
<Link>Common\src\Internal\NativeFormat\NativeFormatReader.String.cs</Link>
</Compile>
@@ -371,9 +374,6 @@
<Compile Include="$(AotCommonPath)\System\Runtime\CompilerServices\__BlockReflectionAttribute.cs">
<Link>System\Runtime\CompilerServices\__BlockReflectionAttribute.cs</Link>
</Compile>
- <Compile Include="$(CompilerCommonPath)\Internal\NativeFormat\NativeFormatReader.Primitives.cs">
- <Link>Internal\NativeFormat\NativeFormatReader.Primitives.cs</Link>
- </Compile>
<Compile Include="$(CompilerCommonPath)\Internal\Runtime\CanonTypeKind.cs">
<Link>Internal\Runtime\CanonTypeKind.cs</Link>
</Compile>
@@ -387,6 +387,17 @@
<Link>Internal\Runtime\LowLevelStringConverter.cs</Link>
</Compile>
</ItemGroup>
+ <!-- Native metadata reader -->
+ <PropertyGroup>
+ <MetadataCommonPath>$(CompilerCommonPath)\Internal\Metadata\NativeFormat</MetadataCommonPath>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MetadataCommonPath)\NativeFormatReaderCommonGen.cs" />
+ <Compile Include="$(MetadataCommonPath)\MdBinaryReader.cs" />
+ <Compile Include="$(MetadataCommonPath)\MdBinaryReaderGen.cs" />
+ <Compile Include="$(MetadataCommonPath)\NativeMetadataReader.cs" />
+ <Compile Include="$(MetadataCommonPath)\NativeFormatReaderGen.cs" />
+ </ItemGroup>
<!-- For now, link Runtime.Base into System.Private.CoreLib until there is proper multifile build -->
<PropertyGroup>
<InPlaceRuntime>true</InPlaceRuntime>
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs
index f277d1d1059..6d5e6e5f937 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs
@@ -5,8 +5,8 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime;
-using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
using Internal.Runtime.CompilerServices;
@@ -109,7 +109,6 @@ namespace System
}
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(MulticastDelegate? d1, MulticastDelegate? d2)
{
@@ -117,14 +116,12 @@ namespace System
// so it can become a simple test
if (d2 is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (d1 is null) ? true : false;
+ return d1 is null;
}
return ReferenceEquals(d2, d1) ? true : d2.Equals((object?)d1);
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(MulticastDelegate? d1, MulticastDelegate? d2)
{
@@ -134,8 +131,7 @@ namespace System
// so it can become a simple test
if (d2 is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (d1 is null) ? false : true;
+ return d1 is not null;
}
return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1);
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ITraceableTypeMember.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ITraceableTypeMember.cs
deleted file mode 100644
index c3a35e36a94..00000000000
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ITraceableTypeMember.cs
+++ /dev/null
@@ -1,18 +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.Reflection;
-using System.Diagnostics;
-
-namespace Internal.Reflection.Tracing
-{
- internal interface ITraceableTypeMember
- {
- // Returns the Name value *without recursing into the public Name implementation.*
- string MemberName { get; }
-
- // Returns the DeclaringType value *without recursing into the public DeclaringType implementation.*
- Type ContainingType { get; }
- }
-}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj
index 640fe1a215e..a770233c1cc 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj
@@ -8,7 +8,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" />
- <ProjectReference Include="..\..\System.Private.Reflection.Metadata\src\System.Private.Reflection.Metadata.csproj" />
<ProjectReference Include="..\..\System.Private.TypeLoader\src\System.Private.TypeLoader.csproj" />
</ItemGroup>
<ItemGroup>
@@ -104,7 +103,6 @@
<Compile Include="System\Reflection\Runtime\ParameterInfos\RuntimeSyntheticParameterInfo.cs" />
<Compile Include="System\Reflection\Runtime\PropertyInfos\NativeFormat\NativeFormatRuntimePropertyInfo.cs" />
<Compile Include="System\Reflection\Runtime\PropertyInfos\RuntimePropertyInfo.cs" />
- <Compile Include="System\Reflection\Runtime\Tracing\ReflectionEventSource.cs" />
<Compile Include="System\Reflection\Runtime\TypeInfos\NativeFormat\NativeFormatRuntimeNamedTypeInfo.cs" />
<Compile Include="System\Reflection\Runtime\TypeInfos\NativeFormat\NativeFormatRuntimeGenericParameterTypeInfo.cs" />
<Compile Include="System\Reflection\Runtime\TypeInfos\NativeFormat\NativeFormatRuntimeNamedTypeInfo.UnificationKey.cs" />
@@ -149,9 +147,6 @@
<Compile Include="Internal\Reflection\Core\Execution\ReflectionCoreExecution.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="Internal\Reflection\Tracing\ITraceableTypeMember.cs" />
- </ItemGroup>
- <ItemGroup>
<Compile Include="$(CommonPath)\System\NotImplemented.cs">
<Link>System\NotImplemented.cs</Link>
</Compile>
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs
index 7c5f1b5a926..a17434df3c7 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs
@@ -17,8 +17,6 @@ using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
using Internal.Metadata.NativeFormat;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.Assemblies.NativeFormat
{
internal partial class NativeFormatRuntimeAssembly
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs
index f082c7ce50c..018358a6318 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs
@@ -16,8 +16,6 @@ using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
using Internal.Metadata.NativeFormat;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.Assemblies.NativeFormat
{
internal partial class NativeFormatRuntimeAssembly
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs
index a6450efa380..81cf4e7a4c2 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs
@@ -21,7 +21,6 @@ using System.Collections.Generic;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
using Internal.Metadata.NativeFormat;
-using Internal.Reflection.Tracing;
namespace System.Reflection.Runtime.Assemblies.NativeFormat
{
@@ -37,11 +36,6 @@ namespace System.Reflection.Runtime.Assemblies.NativeFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.Assembly_CustomAttributes(this);
-#endif
-
foreach (QScopeDefinition scope in AllScopes)
{
foreach (CustomAttributeData cad in RuntimeCustomAttributeData.GetCustomAttributes(scope.Reader, scope.ScopeDefinition.CustomAttributes))
@@ -55,11 +49,6 @@ namespace System.Reflection.Runtime.Assemblies.NativeFormat
[RequiresUnreferencedCode("Types might be removed")]
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.Assembly_DefinedTypes(this);
-#endif
-
foreach (QScopeDefinition scope in AllScopes)
{
MetadataReader reader = scope.Reader;
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs
index 88b94430522..c2d2c47239b 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs
@@ -20,7 +20,6 @@ using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
using Internal.Reflection.Core.NonPortable;
-using Internal.Reflection.Tracing;
using System.Security;
namespace System.Reflection.Runtime.Assemblies
@@ -42,11 +41,6 @@ namespace System.Reflection.Runtime.Assemblies
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.Assembly_FullName(this);
-#endif
-
return GetName().FullName;
}
}
@@ -77,11 +71,6 @@ namespace System.Reflection.Runtime.Assemblies
[RequiresUnreferencedCode("Types might be removed")]
public sealed override Type GetType(string name, bool throwOnError, bool ignoreCase)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.Assembly_GetType(this, name);
-#endif
-
if (name == null)
throw new ArgumentNullException();
if (name.Length == 0)
@@ -124,10 +113,6 @@ namespace System.Reflection.Runtime.Assemblies
public sealed override AssemblyName GetName()
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.Assembly_GetName(this);
-#endif
return RuntimeAssemblyName.ToAssemblyName();
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs
index 555277bed09..867a447c8c0 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs
@@ -6,8 +6,6 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.CustomAttributes
{
//
@@ -23,11 +21,6 @@ namespace System.Reflection.Runtime.CustomAttributes
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.CustomAttributeData_ConstructorArguments(this);
-#endif
-
return new ReadOnlyCollection<CustomAttributeTypedArgument>(GetConstructorArguments(throwIfMissingMetadata: true));
}
}
@@ -38,11 +31,6 @@ namespace System.Reflection.Runtime.CustomAttributes
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.CustomAttributeData_NamedArguments(this);
-#endif
-
return new ReadOnlyCollection<CustomAttributeNamedArgument>(GetNamedArguments(throwIfMissingMetadata: true));
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs
index 60f842aad1a..9317d389e5a 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs
@@ -18,7 +18,6 @@ using Internal.Metadata.NativeFormat;
using NativeFormatMethodSemanticsAttributes = global::Internal.Metadata.NativeFormat.MethodSemanticsAttributes;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
namespace System.Reflection.Runtime.EventInfos.NativeFormat
{
@@ -98,11 +97,6 @@ namespace System.Reflection.Runtime.EventInfos.NativeFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.EventInfo_CustomAttributes(this);
-#endif
-
return RuntimeCustomAttributeData.GetCustomAttributes(_reader, _event.CustomAttributes);
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs
index c99e6307de9..bb46778ed15 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs
@@ -12,7 +12,6 @@ using System.Reflection.Runtime.ParameterInfos;
using System.Reflection.Runtime.CustomAttributes;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
namespace System.Reflection.Runtime.EventInfos
{
@@ -20,7 +19,7 @@ namespace System.Reflection.Runtime.EventInfos
// The runtime's implementation of EventInfo's
//
[DebuggerDisplay("{_debugName}")]
- internal abstract partial class RuntimeEventInfo : EventInfo, ITraceableTypeMember
+ internal abstract partial class RuntimeEventInfo : EventInfo
{
protected RuntimeEventInfo(RuntimeTypeInfo contextTypeInfo, RuntimeTypeInfo reflectedType)
{
@@ -32,11 +31,6 @@ namespace System.Reflection.Runtime.EventInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.EventInfo_AddMethod(this);
-#endif
-
MethodInfo adder = _lazyAdder;
if (adder == null)
{
@@ -54,11 +48,6 @@ namespace System.Reflection.Runtime.EventInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.EventInfo_DeclaringType(this);
-#endif
-
return ContextTypeInfo;
}
}
@@ -82,11 +71,6 @@ namespace System.Reflection.Runtime.EventInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.EventInfo_Name(this);
-#endif
-
return MetadataName;
}
}
@@ -103,11 +87,6 @@ namespace System.Reflection.Runtime.EventInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.EventInfo_RaiseMethod(this);
-#endif
-
return GetEventMethod(EventMethodSemantics.Fire);
}
}
@@ -116,11 +95,6 @@ namespace System.Reflection.Runtime.EventInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.EventInfo_RemoveMethod(this);
-#endif
-
MethodInfo remover = _lazyRemover;
if (remover == null)
{
@@ -144,22 +118,6 @@ namespace System.Reflection.Runtime.EventInfos
return runtimeParameterInfo.ParameterTypeString + " " + this.Name;
}
- string ITraceableTypeMember.MemberName
- {
- get
- {
- return MetadataName;
- }
- }
-
- Type ITraceableTypeMember.ContainingType
- {
- get
- {
- return ContextTypeInfo;
- }
- }
-
protected RuntimeEventInfo WithDebugName()
{
bool populateDebugNames = DeveloperExperienceState.DeveloperExperienceModeEnabled;
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs
index bb971d1aa65..40ad5cc3cf3 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs
@@ -20,7 +20,6 @@ using Internal.Metadata.NativeFormat;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
using Internal.Runtime.TypeLoader;
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs
index b6760051955..098f960d29d 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs
@@ -17,15 +17,13 @@ using System.Reflection.Runtime.BindingFlagSupport;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.FieldInfos
{
//
// The Runtime's implementation of fields.
//
[DebuggerDisplay("{_debugName}")]
- internal abstract partial class RuntimeFieldInfo : FieldInfo, ITraceableTypeMember
+ internal abstract partial class RuntimeFieldInfo : FieldInfo
{
//
// contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you
@@ -54,11 +52,6 @@ namespace System.Reflection.Runtime.FieldInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.FieldInfo_CustomAttributes(this);
-#endif
-
foreach (CustomAttributeData cad in TrueCustomAttributes)
yield return cad;
@@ -81,11 +74,6 @@ namespace System.Reflection.Runtime.FieldInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.FieldInfo_DeclaringType(this);
-#endif
-
return _contextTypeInfo;
}
}
@@ -110,11 +98,6 @@ namespace System.Reflection.Runtime.FieldInfos
public sealed override object GetValue(object obj)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.FieldInfo_GetValue(this, obj);
-#endif
-
FieldAccessor fieldAccessor = this.FieldAccessor;
return fieldAccessor.GetField(obj);
}
@@ -148,11 +131,6 @@ namespace System.Reflection.Runtime.FieldInfos
public sealed override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.FieldInfo_SetValue(this, obj, value);
-#endif
-
FieldAccessor fieldAccessor = this.FieldAccessor;
BinderBundle binderBundle = binder.ToBinderBundle(invokeAttr, culture);
fieldAccessor.SetField(obj, value, binderBundle);
@@ -167,14 +145,6 @@ namespace System.Reflection.Runtime.FieldInfos
fieldAccessor.SetFieldDirect(obj, value);
}
- Type ITraceableTypeMember.ContainingType
- {
- get
- {
- return _contextTypeInfo;
- }
- }
-
/// <summary>
/// Override to provide the metadata based name of a field. (Different from the Name
/// property in that it does not go into the reflection trace logic.)
@@ -185,19 +155,6 @@ namespace System.Reflection.Runtime.FieldInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.FieldInfo_Name(this);
-#endif
-
- return MetadataName;
- }
- }
-
- string ITraceableTypeMember.MemberName
- {
- get
- {
return MetadataName;
}
}
@@ -280,7 +237,7 @@ namespace System.Reflection.Runtime.FieldInfos
if (_debugName == null)
{
_debugName = "Constructing..."; // Protect against any inadvertent reentrancy.
- _debugName = ((ITraceableTypeMember)this).MemberName;
+ _debugName = MetadataName;
}
return this;
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs
index 7880071e01c..708e25cc990 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs
@@ -13,8 +13,6 @@ using System.Reflection.Runtime.ParameterInfos;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.MethodInfos
{
//
@@ -52,11 +50,6 @@ namespace System.Reflection.Runtime.MethodInfos
public sealed override ParameterInfo[] GetParameters()
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_GetParameters(this);
-#endif
-
RuntimeParameterInfo[] parameters = RuntimeParameters;
if (parameters.Length == 0)
return Array.Empty<ParameterInfo>();
@@ -78,10 +71,6 @@ namespace System.Reflection.Runtime.MethodInfos
[DebuggerGuidedStepThrough]
public sealed override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_Invoke(this, obj, parameters);
-#endif
if (parameters == null)
parameters = Array.Empty<object>();
MethodInvoker methodInvoker;
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs
index 27705d3a044..3d9fc962699 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs
@@ -14,7 +14,6 @@ using System.Reflection.Runtime.ParameterInfos;
using System.Reflection.Runtime.BindingFlagSupport;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
namespace System.Reflection.Runtime.MethodInfos
{
@@ -22,7 +21,7 @@ namespace System.Reflection.Runtime.MethodInfos
// Abstract base class for RuntimeNamedMethodInfo, RuntimeConstructedGenericMethodInfo.
//
[DebuggerDisplay("{_debugName}")]
- internal abstract partial class RuntimeMethodInfo : MethodInfo, ITraceableTypeMember
+ internal abstract partial class RuntimeMethodInfo : MethodInfo
{
protected RuntimeMethodInfo()
{
@@ -62,22 +61,12 @@ namespace System.Reflection.Runtime.MethodInfos
// V4.5 api - Creates open delegates over static or instance methods.
public sealed override Delegate CreateDelegate(Type delegateType)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodInfo_CreateDelegate(this, delegateType);
-#endif
-
return CreateDelegateWorker(delegateType, null, allowClosed: false);
}
// V4.5 api - Creates open or closed delegates over static or instance methods.
public sealed override Delegate CreateDelegate(Type delegateType, object target)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodInfo_CreateDelegate(this, delegateType, target);
-#endif
-
return CreateDelegateWorker(delegateType, target, allowClosed: true);
}
@@ -107,11 +96,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_DeclaringType(this);
-#endif
-
return this.RuntimeDeclaringType;
}
}
@@ -160,11 +144,6 @@ namespace System.Reflection.Runtime.MethodInfos
public sealed override ParameterInfo[] GetParameters()
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_GetParameters(this);
-#endif
-
RuntimeParameterInfo[] runtimeParameterInfos = RuntimeParameters;
if (runtimeParameterInfos.Length == 0)
return Array.Empty<ParameterInfo>();
@@ -184,10 +163,6 @@ namespace System.Reflection.Runtime.MethodInfos
[DebuggerGuidedStepThroughAttribute]
public sealed override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_Invoke(this, obj, parameters);
-#endif
if (parameters == null)
parameters = Array.Empty<object>();
MethodInvoker methodInvoker = this.MethodInvoker;
@@ -236,10 +211,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_Name(this);
-#endif
return this.RuntimeName;
}
}
@@ -250,11 +221,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodInfo_ReturnParameter(this);
-#endif
-
return this.RuntimeReturnParameter;
}
}
@@ -263,11 +229,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodInfo_ReturnType(this);
-#endif
-
return ReturnParameter.ParameterType;
}
}
@@ -276,22 +237,6 @@ namespace System.Reflection.Runtime.MethodInfos
public abstract override RuntimeMethodHandle MethodHandle { get; }
- Type ITraceableTypeMember.ContainingType
- {
- get
- {
- return this.RuntimeDeclaringType;
- }
- }
-
- string ITraceableTypeMember.MemberName
- {
- get
- {
- return this.RuntimeName;
- }
- }
-
internal abstract RuntimeTypeInfo RuntimeDeclaringType
{
get;
@@ -527,7 +472,7 @@ namespace System.Reflection.Runtime.MethodInfos
if (_debugName == null)
{
_debugName = "Constructing..."; // Protect against any inadvertent reentrancy.
- _debugName = ((ITraceableTypeMember)this).MemberName;
+ _debugName = RuntimeName;
}
return this;
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs
index 79c2810c94f..252c556e21d 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs
@@ -14,8 +14,6 @@ using System.Reflection.Runtime.CustomAttributes;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.MethodInfos
{
internal abstract class RuntimeNamedMethodInfo : RuntimeMethodInfo
@@ -77,11 +75,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_CustomAttributes(this);
-#endif
-
foreach (CustomAttributeData cad in _common.TrueCustomAttributes)
{
yield return cad;
@@ -130,11 +123,6 @@ namespace System.Reflection.Runtime.MethodInfos
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodInfo_MakeGenericMethod(this, typeArguments);
-#endif
-
if (typeArguments == null)
throw new ArgumentNullException(nameof(typeArguments));
if (GenericTypeParameters.Length == 0)
@@ -157,7 +145,7 @@ namespace System.Reflection.Runtime.MethodInfos
if (typeArguments.Length != GenericTypeParameters.Length)
throw new ArgumentException(SR.Format(SR.Argument_NotEnoughGenArguments, typeArguments.Length, GenericTypeParameters.Length));
RuntimeMethodInfo methodInfo = (RuntimeMethodInfo)RuntimeConstructedGenericMethodInfo.GetRuntimeConstructedGenericMethodInfo(this, genericTypeArguments);
- MethodInvoker methodInvoker = methodInfo.MethodInvoker; // For compatibility with other Make* apis, trigger any MissingMetadataExceptions now rather than later.
+ MethodInvoker _ = methodInfo.MethodInvoker; // For compatibility with other Make* apis, trigger any MissingMetadataExceptions now rather than later.
return methodInfo;
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs
index 7e3825048f3..030759f35f5 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs
@@ -12,8 +12,6 @@ using System.Reflection.Runtime.ParameterInfos;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.MethodInfos
{
//
@@ -65,11 +63,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_CustomAttributes(this);
-#endif
-
return _common.TrueCustomAttributes;
}
}
@@ -78,11 +71,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_DeclaringType(this);
-#endif
-
return _common.DeclaringType;
}
}
@@ -90,10 +78,6 @@ namespace System.Reflection.Runtime.MethodInfos
[DebuggerGuidedStepThrough]
public sealed override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.ConstructorInfo_Invoke(this, parameters);
-#endif
if (parameters == null)
parameters = Array.Empty<object>();
@@ -127,11 +111,6 @@ namespace System.Reflection.Runtime.MethodInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.MethodBase_Name(this);
-#endif
-
return _common.Name;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs
index 44c57781988..fc21a945f2e 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs
@@ -20,8 +20,6 @@ using System.Reflection.Runtime.CustomAttributes;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
@@ -73,11 +71,6 @@ namespace System.Reflection.Runtime.PropertyInfos.EcmaFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_CustomAttributes(this);
-#endif
-
return RuntimeCustomAttributeData.GetCustomAttributes(_reader, _property.GetCustomAttributes());
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs
index 775fd64616b..23d45271e63 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs
@@ -20,8 +20,6 @@ using System.Reflection.Runtime.CustomAttributes;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
using Internal.Metadata.NativeFormat;
using NativeFormatMethodSemanticsAttributes = global::Internal.Metadata.NativeFormat.MethodSemanticsAttributes;
@@ -73,11 +71,6 @@ namespace System.Reflection.Runtime.PropertyInfos.NativeFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_CustomAttributes(this);
-#endif
-
return RuntimeCustomAttributeData.GetCustomAttributes(_reader, _property.CustomAttributes);
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs
index 20f4d25aed0..32fb5ffa926 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs
@@ -17,16 +17,13 @@ using System.Reflection.Runtime.CustomAttributes;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
-
namespace System.Reflection.Runtime.PropertyInfos
{
//
// The runtime's implementation of PropertyInfo's
//
[DebuggerDisplay("{_debugName}")]
- internal abstract partial class RuntimePropertyInfo : PropertyInfo, ITraceableTypeMember
+ internal abstract partial class RuntimePropertyInfo : PropertyInfo
{
//
// propertyHandle - the "tkPropertyDef" that identifies the property.
@@ -73,11 +70,6 @@ namespace System.Reflection.Runtime.PropertyInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_DeclaringType(this);
-#endif
-
return ContextTypeInfo;
}
}
@@ -123,11 +115,6 @@ namespace System.Reflection.Runtime.PropertyInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_GetMethod(this);
-#endif
-
return Getter;
}
}
@@ -138,10 +125,6 @@ namespace System.Reflection.Runtime.PropertyInfos
public sealed override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_GetValue(this, obj, index);
-#endif
if (_lazyGetterInvoker == null)
{
if (!CanRead)
@@ -168,11 +151,6 @@ namespace System.Reflection.Runtime.PropertyInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_Name(this);
-#endif
-
return MetadataName;
}
}
@@ -181,11 +159,6 @@ namespace System.Reflection.Runtime.PropertyInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_PropertyType(this);
-#endif
-
Type propertyType = _lazyPropertyType;
if (propertyType == null)
{
@@ -209,21 +182,12 @@ namespace System.Reflection.Runtime.PropertyInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_SetMethod(this);
-#endif
-
return Setter;
}
}
public sealed override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_SetValue(this, obj, value, index);
-#endif
if (_lazySetterInvoker == null)
{
if (!CanWrite)
@@ -270,22 +234,6 @@ namespace System.Reflection.Runtime.PropertyInfos
return sb.ToString();
}
- string ITraceableTypeMember.MemberName
- {
- get
- {
- return MetadataName;
- }
- }
-
- Type ITraceableTypeMember.ContainingType
- {
- get
- {
- return ContextTypeInfo;
- }
- }
-
private RuntimeNamedMethodInfo Getter
{
get
@@ -386,11 +334,6 @@ namespace System.Reflection.Runtime.PropertyInfos
private object GetConstantValue(bool raw)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.PropertyInfo_GetConstantValue(this);
-#endif
-
object defaultValue;
if (!GetDefaultValueIfAny(raw, out defaultValue))
{
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Tracing/ReflectionEventSource.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Tracing/ReflectionEventSource.cs
deleted file mode 100644
index 706a4fd8a0b..00000000000
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Tracing/ReflectionEventSource.cs
+++ /dev/null
@@ -1,376 +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.Diagnostics.Tracing;
-
-namespace System.Reflection.Runtime.Tracing
-{
- [EventSource(Guid = "55B578AE-32B0-48F8-822F-B3245E6FA59C", Name = "System.Reflection.Runtime.Tracing")]
- internal sealed class ReflectionEventSource : EventSource
- {
- // Defines the singleton instance for the Resources ETW provider
- public static readonly ReflectionEventSource Log = new ReflectionEventSource();
-
- public static bool IsInitialized
- {
- get
- {
- return Log != null;
- }
- }
-
- private ReflectionEventSource() { }
-
-
- #region Reflection Event Handlers
- [Event(1)]
- public void TypeInfo_CustomAttributes(string typeName)
- {
- WriteEvent(1, typeName);
- }
-
- [Event(2)]
- public void TypeInfo_Name(string typeName)
- {
- WriteEvent(2, typeName);
- }
-
- [Event(3)]
- public void TypeInfo_BaseType(string typeName)
- {
- WriteEvent(3, typeName);
- }
-
- [Event(4)]
- public void TypeInfo_DeclaredConstructors(string typeName)
- {
- WriteEvent(4, typeName);
- }
-
- [Event(5)]
- public void TypeInfo_DeclaredEvents(string typeName)
- {
- WriteEvent(5, typeName);
- }
-
- [Event(6)]
- public void TypeInfo_DeclaredFields(string typeName)
- {
- WriteEvent(6, typeName);
- }
-
- [Event(7)]
- public void TypeInfo_DeclaredMembers(string typeName)
- {
- WriteEvent(7, typeName);
- }
-
- [Event(8)]
- public void TypeInfo_DeclaredMethods(string typeName)
- {
- WriteEvent(8, typeName);
- }
-
- [Event(9)]
- public void TypeInfo_DeclaredNestedTypes(string typeName)
- {
- WriteEvent(9, typeName);
- }
-
- [Event(10)]
- public void TypeInfo_DeclaredProperties(string typeName)
- {
- WriteEvent(10, typeName);
- }
-
- [Event(11)]
- public void TypeInfo_DeclaringMethod(string typeName)
- {
- WriteEvent(11, typeName);
- }
-
- [Event(12)]
- public void TypeInfo_FullName(string typeName)
- {
- WriteEvent(12, typeName);
- }
-
- [Event(13)]
- public void TypeInfo_Namespace(string typeName)
- {
- WriteEvent(13, typeName);
- }
-
- [Event(14)]
- public void TypeInfo_GetDeclaredEvent(string typeName, string eventName)
- {
- WriteEvent(14, typeName, eventName);
- }
-
- [Event(15)]
- public void TypeInfo_GetDeclaredField(string typeName, string fieldName)
- {
- WriteEvent(15, typeName, fieldName);
- }
-
- [Event(16)]
- public void TypeInfo_GetDeclaredMethod(string typeName, string methodName)
- {
- WriteEvent(16, typeName, methodName);
- }
-
- [Event(17)]
- public void TypeInfo_GetDeclaredProperty(string typeName, string propertyName)
- {
- WriteEvent(17, typeName, propertyName);
- }
-
- [Event(18)]
- public void TypeInfo_MakeArrayType(string typeName)
- {
- WriteEvent(18, typeName);
- }
-
- [Event(19)]
- public void TypeInfo_MakeByRefType(string typeName)
- {
- WriteEvent(19, typeName);
- }
-
- [Event(20)]
- public void TypeInfo_MakeGenericType(string typeName, string typeArguments)
- {
- WriteEvent(20, typeName, typeArguments);
- }
-
- [Event(21)]
- public void TypeInfo_MakePointerType(string typeName)
- {
- WriteEvent(21, typeName);
- }
-
- [Event(22)]
- public void Assembly_DefinedTypes(string assemblyName)
- {
- WriteEvent(22, assemblyName);
- }
-
- [Event(23)]
- public void Assembly_GetType(string assemblyName, string typeName)
- {
- WriteEvent(23, assemblyName, typeName);
- }
-
- [Event(24)]
- public void Assembly_CustomAttributes(string assemblyName)
- {
- WriteEvent(24, assemblyName);
- }
-
- [Event(25)]
- public void Assembly_FullName(string assemblyName)
- {
- WriteEvent(25, assemblyName);
- }
-
- [Event(26)]
- public void Assembly_GetName(string assemblyName)
- {
- WriteEvent(26, assemblyName);
- }
-
- [Event(27)]
- public void CustomAttributeData_ConstructorArguments(string caName)
- {
- WriteEvent(27, caName);
- }
-
- [Event(28)]
- public void CustomAttributeData_NamedArguments(string caName)
- {
- WriteEvent(28, caName);
- }
-
- [Event(29)]
- public void EventInfo_AddMethod(string typeName, string eventName)
- {
- WriteEvent(29, typeName, eventName);
- }
-
- [Event(30)]
- public void EventInfo_RaiseMethod(string typeName, string eventName)
- {
- WriteEvent(30, typeName, eventName);
- }
-
- [Event(31)]
- public void EventInfo_RemoveMethod(string typeName, string eventName)
- {
- WriteEvent(31, typeName, eventName);
- }
-
- [Event(32)]
- public void EventInfo_CustomAttributes(string typeName, string eventName)
- {
- WriteEvent(32, typeName, eventName);
- }
-
- [Event(33)]
- public void EventInfo_Name(string typeName, string eventName)
- {
- WriteEvent(33, typeName, eventName);
- }
-
- [Event(34)]
- public void EventInfo_DeclaringType(string typeName, string eventName)
- {
- WriteEvent(34, typeName, eventName);
- }
-
- [Event(35)]
- public void FieldInfo_SetValue(string typeName, string fieldName)
- {
- WriteEvent(35, typeName, fieldName);
- }
-
- [Event(36)]
- public void FieldInfo_GetValue(string typeName, string fieldName)
- {
- WriteEvent(36, typeName, fieldName);
- }
-
- [Event(37)]
- public void FieldInfo_CustomAttributes(string typeName, string fieldName)
- {
- WriteEvent(37, typeName, fieldName);
- }
-
- [Event(38)]
- public void FieldInfo_Name(string typeName, string fieldName)
- {
- WriteEvent(38, typeName, fieldName);
- }
-
- [Event(39)]
- public void FieldInfo_DeclaringType(string typeName, string fieldName)
- {
- WriteEvent(39, typeName, fieldName);
- }
-
- [Event(40)]
- public void MethodBase_CustomAttributes(string typeName, string methodName)
- {
- WriteEvent(40, typeName, methodName);
- }
-
- [Event(41)]
- public void MethodBase_Name(string typeName, string methodName)
- {
- WriteEvent(41, typeName, methodName);
- }
-
- [Event(42)]
- public void MethodBase_DeclaringType(string typeName, string methodName)
- {
- WriteEvent(42, typeName, methodName);
- }
-
- [Event(43)]
- public void MethodBase_GetParameters(string typeName, string methodName)
- {
- WriteEvent(43, typeName, methodName);
- }
-
- [Event(44)]
- public void MethodBase_Invoke(string typeName, string methodName)
- {
- WriteEvent(44, typeName, methodName);
- }
-
- [Event(45)]
- public void MethodInfo_ReturnParameter(string typeName, string methodName)
- {
- WriteEvent(45, typeName, methodName);
- }
-
- [Event(46)]
- public void MethodInfo_ReturnType(string typeName, string methodName)
- {
- WriteEvent(46, typeName, methodName);
- }
-
- [Event(47)]
- public void MethodInfo_MakeGenericMethod(string typeName, string methodName, string typeArguments)
- {
- WriteEvent(47, typeName, methodName, typeArguments);
- }
-
- [Event(48)]
- public void MethodInfo_CreateDelegate(string typeName, string methodName, string delegateTypeName)
- {
- WriteEvent(48, typeName, methodName, delegateTypeName);
- }
-
- [Event(49)]
- public void PropertyInfo_GetValue(string typeName, string propertyName)
- {
- WriteEvent(49, typeName, propertyName);
- }
-
- [Event(50)]
- public void PropertyInfo_SetValue(string typeName, string propertyName)
- {
- WriteEvent(50, typeName, propertyName);
- }
-
- [Event(51)]
- public void PropertyInfo_GetMethod(string typeName, string propertyName)
- {
- WriteEvent(51, typeName, propertyName);
- }
-
- [Event(52)]
- public void PropertyInfo_SetMethod(string typeName, string propertyName)
- {
- WriteEvent(52, typeName, propertyName);
- }
-
- [Event(53)]
- public void PropertyInfo_GetConstantValue(string typeName, string propertyName)
- {
- WriteEvent(53, typeName, propertyName);
- }
-
- [Event(54)]
- public void PropertyInfo_PropertyType(string typeName, string propertyName)
- {
- WriteEvent(54, typeName, propertyName);
- }
-
- [Event(55)]
- public void PropertyInfo_CustomAttributes(string typeName, string propertyName)
- {
- WriteEvent(55, typeName, propertyName);
- }
-
- [Event(56)]
- public void PropertyInfo_Name(string typeName, string propertyName)
- {
- WriteEvent(56, typeName, propertyName);
- }
-
- [Event(57)]
- public void PropertyInfo_DeclaringType(string typeName, string propertyName)
- {
- WriteEvent(57, typeName, propertyName);
- }
-
- [Event(58)]
- public void TypeInfo_AssemblyQualifiedName(string typeName)
- {
- WriteEvent(58, typeName);
- }
- #endregion
- }
-}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs
index 11fdded50fb..4144e4ae4d9 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs
@@ -11,8 +11,6 @@ using System.Reflection.Runtime.MethodInfos;
using System.Reflection.Runtime.TypeInfos;
using System.Reflection.Runtime.CustomAttributes;
-using Internal.Reflection.Tracing;
-
using Internal.Metadata.NativeFormat;
namespace System.Reflection.Runtime.TypeInfos.NativeFormat
@@ -31,11 +29,6 @@ namespace System.Reflection.Runtime.TypeInfos.NativeFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_CustomAttributes(this);
-#endif
-
return RuntimeCustomAttributeData.GetCustomAttributes(Reader, _genericParameter.CustomAttributes);
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs
index 7f55e2cd3a2..941483a2bd9 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs
@@ -10,8 +10,6 @@ using System.Reflection.Runtime.General;
using System.Reflection.Runtime.MethodInfos;
using System.Reflection.Runtime.TypeInfos;
-using Internal.Reflection.Tracing;
-
using Internal.Metadata.NativeFormat;
namespace System.Reflection.Runtime.TypeInfos.NativeFormat
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs
index c77d716fd5a..b9de30f5af2 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs
@@ -10,9 +10,6 @@ using System.Reflection.Runtime.General;
using System.Reflection.Runtime.MethodInfos;
using System.Reflection.Runtime.TypeInfos;
-
-using Internal.Reflection.Tracing;
-
using Internal.Metadata.NativeFormat;
namespace System.Reflection.Runtime.TypeInfos.NativeFormat
@@ -33,10 +30,6 @@ namespace System.Reflection.Runtime.TypeInfos.NativeFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_DeclaringMethod(this);
-#endif
return _declaringRuntimeNamedMethodInfo;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs
index 00092acda57..047e71112c9 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs
@@ -8,8 +8,6 @@ using System.Collections.Generic;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.TypeInfos;
-using Internal.Reflection.Tracing;
-
using Internal.Metadata.NativeFormat;
namespace System.Reflection.Runtime.TypeInfos.NativeFormat
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs
index 90a08477655..8f5658c179b 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs
@@ -8,8 +8,6 @@ using System.Collections.Generic;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.TypeInfos;
-using Internal.Reflection.Tracing;
-
using Internal.Metadata.NativeFormat;
namespace System.Reflection.Runtime.TypeInfos.NativeFormat
@@ -29,10 +27,6 @@ namespace System.Reflection.Runtime.TypeInfos.NativeFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_DeclaringMethod(this);
-#endif
return null;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs
index a1d0567664f..80b394decba 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs
@@ -9,8 +9,6 @@ using System.Reflection.Runtime.Assemblies;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.CustomAttributes;
-using Internal.Reflection.Tracing;
-
using Internal.Metadata.NativeFormat;
namespace System.Reflection.Runtime.TypeInfos.NativeFormat
@@ -87,11 +85,6 @@ namespace System.Reflection.Runtime.TypeInfos.NativeFormat
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_Namespace(this);
-#endif
-
return NamespaceChain.NameSpace.EscapeTypeNameIdentifier();
}
}
@@ -285,35 +278,6 @@ namespace System.Reflection.Runtime.TypeInfos.NativeFormat
return base.Equals(otherAsObject);
}
-#if ENABLE_REFLECTION_TRACE
- internal sealed override string TraceableTypeName
- {
- get
- {
- MetadataReader reader = Reader;
-
- String s = "";
- TypeDefinitionHandle typeDefinitionHandle = TypeDefinitionHandle;
- do
- {
- TypeDefinition typeDefinition = typeDefinitionHandle.GetTypeDefinition(reader);
- String name = typeDefinition.Name.GetString(reader);
- if (s == "")
- s = name;
- else
- s = name + "+" + s;
- typeDefinitionHandle = typeDefinition.EnclosingType;
- }
- while (!typeDefinitionHandle.IsNull(reader));
-
- String ns = NamespaceChain.NameSpace;
- if (ns != null)
- s = ns + "." + s;
- return s;
- }
- }
-#endif
-
internal sealed override QTypeDefRefOrSpec TypeDefinitionQHandle
{
get
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs
index e625166fed8..b5ccec16c0e 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs
@@ -11,7 +11,6 @@ using System.Reflection.Runtime.Assemblies;
using System.Reflection.Runtime.CustomAttributes;
using Internal.LowLevelLinq;
-using Internal.Reflection.Tracing;
using Internal.Reflection.Core.Execution;
using CharSet = System.Runtime.InteropServices.CharSet;
@@ -57,10 +56,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_CustomAttributes(this);
-#endif
return Empty<CustomAttributeData>.Enumerable;
}
}
@@ -69,10 +64,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_FullName(this);
-#endif
return GeneratedName;
}
}
@@ -101,10 +92,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_Namespace(this);
-#endif
return null; // Reflection-blocked framework types report themselves as existing in the "root" namespace.
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs
index ec4b500e9a5..0e6fda3edaa 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs
@@ -8,7 +8,6 @@ using System.Reflection.Runtime.General;
using System.Reflection.Runtime.MethodInfos;
using System.Runtime.InteropServices;
-using Internal.Reflection.Tracing;
using Internal.Reflection.Core.Execution;
namespace System.Reflection.Runtime.TypeInfos
@@ -40,11 +39,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_CustomAttributes(this);
-#endif
-
return Empty<CustomAttributeData>.Enumerable;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs
index 63938404fae..5cd6c23e8ca 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs
@@ -10,7 +10,6 @@ using System.Collections.Concurrent;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.TypeInfos;
-using Internal.Reflection.Tracing;
using Internal.Reflection.Core.Execution;
using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute;
@@ -75,11 +74,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_CustomAttributes(this);
-#endif
-
return GenericTypeDefinitionTypeInfo.CustomAttributes;
}
}
@@ -88,10 +82,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_FullName(this);
-#endif
// Desktop quirk: open constructions don't have "fullNames".
if (ContainsGenericParameters)
return null;
@@ -158,10 +148,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_Namespace(this);
-#endif
return GenericTypeDefinitionTypeInfo.Namespace;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs
index 2434f3b9278..28f19623348 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs
@@ -13,8 +13,6 @@ using System.Reflection.Runtime.CustomAttributes;
using Internal.Reflection.Core;
using Internal.Reflection.Core.Execution;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.TypeInfos
{
internal abstract class RuntimeGenericParameterTypeInfo : RuntimeTypeInfo
@@ -67,10 +65,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_FullName(this);
-#endif
return null; // We return null as generic parameter types are not roundtrippable through Type.GetType().
}
}
@@ -100,10 +94,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_Namespace(this);
-#endif
return DeclaringType.Namespace;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs
index f0dbbac9761..05a65a8c80a 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs
@@ -10,8 +10,6 @@ using System.Runtime.InteropServices;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.TypeInfos;
-using Internal.Reflection.Tracing;
-
namespace System.Reflection.Runtime.TypeInfos
{
//
@@ -79,11 +77,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_CustomAttributes(this);
-#endif
-
return Empty<CustomAttributeData>.Enumerable;
}
}
@@ -100,10 +93,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_FullName(this);
-#endif
string elementFullName = _key.ElementType.FullName;
if (elementFullName == null)
return null;
@@ -124,10 +113,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_Namespace(this);
-#endif
return _key.ElementType.Namespace;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs
index 3622630315a..ddf99822a3f 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs
@@ -8,8 +8,6 @@ using System.Runtime.InteropServices;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.CustomAttributes;
-using Internal.Reflection.Tracing;
-
#pragma warning disable CA1067 // override Equals because it implements IEquatable<T>
namespace System.Reflection.Runtime.TypeInfos
@@ -37,11 +35,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_CustomAttributes(this);
-#endif
-
foreach (CustomAttributeData cad in TrueCustomAttributes)
yield return cad;
@@ -94,11 +87,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_FullName(this);
-#endif
-
Debug.Assert(!IsConstructedGenericType);
Debug.Assert(!IsGenericParameter);
Debug.Assert(!HasElementType);
@@ -210,10 +198,6 @@ namespace System.Reflection.Runtime.TypeInfos
}
}
-#if ENABLE_REFLECTION_TRACE
- internal abstract string TraceableTypeName { get; }
-#endif
-
/// <summary>
/// QTypeDefRefOrSpec handle that can be used to re-acquire this type. Must be implemented
/// for all metadata sourced type implementations.
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs
index cc95bb1a0c6..2939a881e75 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs
@@ -11,7 +11,6 @@ using System.Reflection.Runtime.Assemblies;
using System.Reflection.Runtime.CustomAttributes;
using Internal.LowLevelLinq;
-using Internal.Reflection.Tracing;
using Internal.Reflection.Core.Execution;
using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute;
@@ -58,10 +57,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_FullName(this);
-#endif
throw ReflectionCoreExecution.ExecutionDomain.CreateMissingMetadataException(this);
}
}
@@ -90,10 +85,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_Namespace(this);
-#endif
throw ReflectionCoreExecution.ExecutionDomain.CreateMissingMetadataException(this);
}
}
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs
index bf946e99f1d..647b50e484a 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs
@@ -11,7 +11,6 @@ using System.Reflection.Runtime.MethodInfos;
using Internal.Reflection.Core.Execution;
using Internal.Reflection.Core.NonPortable;
-using Internal.Reflection.Tracing;
using Internal.Reflection.Augments;
using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute;
@@ -34,7 +33,7 @@ namespace System.Reflection.Runtime.TypeInfos
// shows up as build error.
//
[DebuggerDisplay("{_debugName}")]
- internal abstract partial class RuntimeTypeInfo : RuntimeType, ITraceableTypeMember, ICloneable
+ internal abstract partial class RuntimeTypeInfo : RuntimeType, ICloneable
{
protected RuntimeTypeInfo()
{
@@ -61,11 +60,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_AssemblyQualifiedName(this);
-#endif
-
string fullName = FullName;
if (fullName == null) // Some Types (such as generic parameters) return null for FullName by design.
return null;
@@ -83,11 +77,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_BaseType(this);
-#endif
-
// If this has a RuntimeTypeHandle, let the underlying runtime engine have the first crack. If it refuses, fall back to metadata.
RuntimeTypeHandle typeHandle = InternalTypeHandleIfAvailable;
if (!typeHandle.IsNull())
@@ -427,11 +416,6 @@ namespace System.Reflection.Runtime.TypeInfos
[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
public sealed override Type MakeArrayType()
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_MakeArrayType(this);
-#endif
-
// Do not implement this as a call to MakeArrayType(1) - they are not interchangable. MakeArrayType() returns a
// vector type ("SZArray") while MakeArrayType(1) returns a multidim array of rank 1. These are distinct types
// in the ECMA model and in CLR Reflection.
@@ -441,11 +425,6 @@ namespace System.Reflection.Runtime.TypeInfos
[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
public sealed override Type MakeArrayType(int rank)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_MakeArrayType(this, rank);
-#endif
-
if (rank <= 0)
throw new IndexOutOfRangeException();
return this.GetMultiDimArrayTypeWithTypeHandle(rank);
@@ -453,10 +432,6 @@ namespace System.Reflection.Runtime.TypeInfos
public sealed override Type MakeByRefType()
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_MakeByRefType(this);
-#endif
return this.GetByRefType();
}
@@ -464,11 +439,6 @@ namespace System.Reflection.Runtime.TypeInfos
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public sealed override Type MakeGenericType(params Type[] typeArguments)
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_MakeGenericType(this, typeArguments);
-#endif
-
if (typeArguments == null)
throw new ArgumentNullException(nameof(typeArguments));
@@ -520,11 +490,6 @@ namespace System.Reflection.Runtime.TypeInfos
public sealed override Type MakePointerType()
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_MakePointerType(this);
-#endif
-
return this.GetPointerType();
}
@@ -540,11 +505,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
get
{
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- ReflectionTrace.TypeInfo_Name(this);
-#endif
-
Type rootCauseForFailure = null;
string name = InternalGetNameIfAvailable(ref rootCauseForFailure);
if (name == null)
@@ -623,23 +583,6 @@ namespace System.Reflection.Runtime.TypeInfos
return 0 != (Classification & TypeClassification.IsValueType);
}
- string ITraceableTypeMember.MemberName
- {
- get
- {
- string name = InternalNameIfAvailable;
- return name ?? string.Empty;
- }
- }
-
- Type ITraceableTypeMember.ContainingType
- {
- get
- {
- return this.InternalDeclaringType;
- }
- }
-
//
// Returns the anchoring typedef that declares the members that this type wants returned by the Declared*** properties.
// The Declared*** properties will project the anchoring typedef's members by overriding their DeclaringType property with "this"
@@ -799,11 +742,6 @@ namespace System.Reflection.Runtime.TypeInfos
{
_debugName = "Constructing..."; // Protect against any inadvertent reentrancy.
string debugName;
-#if ENABLE_REFLECTION_TRACE
- if (ReflectionTrace.Enabled)
- debugName = this.GetTraceString(); // If tracing on, call this.GetTraceString() which only gives you useful strings when metadata is available but doesn't pollute the ETW trace.
- else
-#endif
debugName = this.ToString();
if (debugName == null)
debugName = "";
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj
index 7e870c7eee8..e8b65e31ca0 100644
--- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj
+++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" />
- <ProjectReference Include="..\..\System.Private.Reflection.Metadata\src\System.Private.Reflection.Metadata.csproj" />
<ProjectReference Include="..\..\System.Private.TypeLoader\src\System.Private.TypeLoader.csproj" />
<ProjectReference Include="..\..\System.Private.Reflection.Core\src\System.Private.Reflection.Core.csproj" />
</ItemGroup>
diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Metadata/src/System.Private.Reflection.Metadata.csproj b/src/coreclr/nativeaot/System.Private.Reflection.Metadata/src/System.Private.Reflection.Metadata.csproj
deleted file mode 100644
index 7b3f55c5bf1..00000000000
--- a/src/coreclr/nativeaot/System.Private.Reflection.Metadata/src/System.Private.Reflection.Metadata.csproj
+++ /dev/null
@@ -1,27 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
- <ItemGroup>
- <ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" />
- </ItemGroup>
- <PropertyGroup>
- <NativeFormatCommonPath>$(CompilerCommonPath)\Internal\NativeFormat</NativeFormatCommonPath>
- <MetadataCommonPath>$(CompilerCommonPath)\Internal\Metadata\NativeFormat</MetadataCommonPath>
- </PropertyGroup>
- <ItemGroup>
- <Compile Include="$(NativeFormatCommonPath)\NativeFormat.cs" />
- <Compile Include="$(NativeFormatCommonPath)\NativeFormatReader.cs" />
- <Compile Include="$(NativeFormatCommonPath)\NativeFormatReader.Primitives.cs" />
- <Compile Include="$(NativeFormatCommonPath)\NativeFormatReader.String.cs" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="$(MetadataCommonPath)\NativeFormatReaderCommonGen.cs" />
- <Compile Include="$(MetadataCommonPath)\MdBinaryReader.cs" />
- <Compile Include="$(MetadataCommonPath)\MdBinaryReaderGen.cs" />
- <Compile Include="$(MetadataCommonPath)\NativeMetadataReader.cs" />
- <Compile Include="$(MetadataCommonPath)\NativeFormatReaderGen.cs" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="$(AotCommonPath)\System\Runtime\CompilerServices\__BlockAllReflectionAttribute.cs">
- <Link>System\Runtime\CompilerServices\__BlockAllReflectionAttribute.cs</Link>
- </Compile>
- </ItemGroup>
-</Project>
diff --git a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj
index c591e321e0d..0b0589e507a 100644
--- a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj
+++ b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj
@@ -5,7 +5,6 @@
<ItemGroup>
<ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" />
- <ProjectReference Include="..\..\System.Private.Reflection.Metadata\src\System.Private.Reflection.Metadata.csproj" />
<ProjectReference Include="..\..\System.Private.TypeLoader\src\System.Private.TypeLoader.csproj" />
<ProjectReference Include="..\..\System.Private.Reflection.Execution\src\System.Private.Reflection.Execution.csproj" />
</ItemGroup>
diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
index b7f25b102fa..73332581e50 100644
--- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
+++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
@@ -10,7 +10,6 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" />
- <ProjectReference Include="..\..\System.Private.Reflection.Metadata\src\System.Private.Reflection.Metadata.csproj" />
</ItemGroup>
<PropertyGroup>
<NativeFormatCommonPath>$(CompilerCommonPath)\Internal\NativeFormat</NativeFormatCommonPath>
diff --git a/src/coreclr/nativeaot/docs/optimizing.md b/src/coreclr/nativeaot/docs/optimizing.md
index aca22fd31bb..aeee66fa2f4 100644
--- a/src/coreclr/nativeaot/docs/optimizing.md
+++ b/src/coreclr/nativeaot/docs/optimizing.md
@@ -44,6 +44,6 @@ To aid in troubleshooting some of the most common problems related to trimming a
## Special considerations for Linux/macOS
-Debugging symbols (data about your program required for debugging) is by default part of native executable files on Unix-like operating systems. To minimize the size of your native executable, you can run the `strip` tool to remove the debugging symbols.
+Debugging symbols (data about your program required for debugging) is by default part of native executable files on Unix-like operating systems. To strip symbols into a separate file (`*.dbg` on Linux and `*.dwarf` on macOS), set `<StripSymbols>true</StripSymbols>`.
No action is needed on Windows since the platform convention is to generate debug information into a separate file (`*.pdb`).
diff --git a/src/coreclr/nativeaot/docs/prerequisites.md b/src/coreclr/nativeaot/docs/prerequisites.md
index 9024d6c5052..a0fc1897cf9 100644
--- a/src/coreclr/nativeaot/docs/prerequisites.md
+++ b/src/coreclr/nativeaot/docs/prerequisites.md
@@ -28,22 +28,26 @@ Notes:
- The `--installPath` option affects Build Tools installation only. Visual Studio Installer is always installed into
the `%ProgramFiles(x86)%\Microsoft Visual Studio\Installer` directory.
-# Fedora (31+)
+# Linux
-* Install `clang` and developer packages for libraries that .NET Core depends on:
+Install `clang` and developer packages for libraries that .NET runtime depends on:
+
+## Fedora (31+)
```sh
sudo dnf install clang zlib-devel ncurses-compat-libs
```
-This was tested on Fedora 31, but will most likely work on lower versions too.
+## Ubuntu (16.04+)
-# Ubuntu (16.04+)
+```sh
+sudo apt-get install clang zlib1g-dev
+```
-* Install `clang` and developer packages for libraries that .NET Core depends on:
+## Alpine (3.14+)
```sh
-sudo apt-get install clang zlib1g-dev
+sudo apk add clang gcc lld musl-dev build-base zlib-dev
```
# macOS (10.13+)
diff --git a/src/coreclr/nativeaot/nativeaot.sln b/src/coreclr/nativeaot/nativeaot.sln
index f66b164b16f..f2bbfe6e9fb 100644
--- a/src/coreclr/nativeaot/nativeaot.sln
+++ b/src/coreclr/nativeaot/nativeaot.sln
@@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Reflection.C
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Reflection.Execution", "System.Private.Reflection.Execution\src\System.Private.Reflection.Execution.csproj", "{7498DD7C-76C1-4912-AF72-DA84E05B568F}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Reflection.Metadata", "System.Private.Reflection.Metadata\src\System.Private.Reflection.Metadata.csproj", "{C0245BD9-6AE2-47A5-BC41-DB6F777423AF}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.StackTraceMetadata", "System.Private.StackTraceMetadata\src\System.Private.StackTraceMetadata.csproj", "{33CAE331-16EE-443C-A0CC-4337B94A02AD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.TypeLoader", "System.Private.TypeLoader\src\System.Private.TypeLoader.csproj", "{3E43ACA2-073E-4A66-BA9C-417C5F83D430}"
diff --git a/src/coreclr/scripts/superpmi_collect_setup.py b/src/coreclr/scripts/superpmi_collect_setup.py
index ce6eee4bd5f..993af83cc20 100644
--- a/src/coreclr/scripts/superpmi_collect_setup.py
+++ b/src/coreclr/scripts/superpmi_collect_setup.py
@@ -156,15 +156,24 @@ native_binaries_to_ignore = [
"mscorrc.dll",
"msdia140.dll",
"msquic.dll",
+ "msvcp140.dll",
+ "vcruntime140.dll",
+ "vcruntime140_1.dll",
"R2RDump.exe",
"R2RTest.exe",
"superpmi.exe",
"superpmi-shim-collector.dll",
"superpmi-shim-counter.dll",
"superpmi-shim-simple.dll",
+ "System.CommandLine.resources.dll", # Managed, but uninteresting
"System.IO.Compression.Native.dll",
"ucrtbase.dll",
"xunit.console.exe",
+
+ # The following cause VM asserts. Disabling to attempt to fix periodic SPMI collection pipeline failures.
+ # Tracked by: https://github.com/dotnet/runtime/issues/70293
+ "System.Runtime.InteropServices.Tests.dll", # libraries test
+ "DllImportPathTest.dll", # coreclr test
]
MAX_FILES_COUNT = 1500
@@ -253,13 +262,13 @@ def get_files_sorted_by_size(src_directory, exclude_directories, exclude_files):
return pair
filename_with_size = []
+ exclude_files_lower = [filename.lower() for filename in exclude_files]
for file_path, dirs, files in os.walk(src_directory, topdown=True):
# Credit: https://stackoverflow.com/a/19859907
dirs[:] = [d for d in dirs if d not in exclude_directories]
for name in files:
# Make the exclude check case-insensitive
- exclude_files_lower = [filename.lower() for filename in exclude_files]
if name.lower() in exclude_files_lower:
continue
curr_file_path = os.path.join(file_path, name)
diff --git a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs
index d03685f725a..0f9bc5952ea 100644
--- a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs
+++ b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs
@@ -123,9 +123,9 @@ namespace ILCompiler
return null;
}
- public EcmaModule GetModuleFromPath(string filePath)
+ public EcmaModule GetModuleFromPath(string filePath, bool throwOnFailureToLoad = true)
{
- return GetOrAddModuleFromPath(filePath, true);
+ return GetOrAddModuleFromPath(filePath, true, throwOnFailureToLoad: throwOnFailureToLoad);
}
public EcmaModule GetMetadataOnlyModuleFromPath(string filePath)
@@ -133,7 +133,7 @@ namespace ILCompiler
return GetOrAddModuleFromPath(filePath, false);
}
- private EcmaModule GetOrAddModuleFromPath(string filePath, bool useForBinding)
+ private EcmaModule GetOrAddModuleFromPath(string filePath, bool useForBinding, bool throwOnFailureToLoad = true)
{
filePath = Path.GetFullPath(filePath);
@@ -144,7 +144,7 @@ namespace ILCompiler
return entry.Module;
}
- return AddModule(filePath, null, useForBinding);
+ return AddModule(filePath, null, useForBinding, throwOnFailureToLoad: throwOnFailureToLoad);
}
public static unsafe PEReader OpenPEFile(string filePath, out MemoryMappedViewAccessor mappedViewAccessor)
@@ -182,7 +182,7 @@ namespace ILCompiler
}
}
- private EcmaModule AddModule(string filePath, string expectedSimpleName, bool useForBinding, ModuleData oldModuleData = null)
+ private EcmaModule AddModule(string filePath, string expectedSimpleName, bool useForBinding, ModuleData oldModuleData = null, bool throwOnFailureToLoad = true)
{
filePath = Path.GetFullPath(filePath);
@@ -210,6 +210,11 @@ namespace ILCompiler
pdbReader = oldModuleData.Module.PdbReader;
}
+ if (!peReader.HasMetadata && !throwOnFailureToLoad)
+ {
+ return null;
+ }
+
EcmaModule module = EcmaModule.Create(this, peReader, containingAssembly: null, pdbReader);
MetadataReader metadataReader = module.MetadataReader;
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/CsWriter.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/CsWriter.cs
index 48af0fc72a1..e279a86b850 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/CsWriter.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/CsWriter.cs
@@ -88,4 +88,14 @@ class CsWriter : IDisposable
{
WriteLine("/// " + s);
}
+
+ public void WriteTypeAttributesForCoreLib()
+ {
+ WriteLineIfNeeded();
+
+ _writer.WriteLine("#if SYSTEM_PRIVATE_CORELIB");
+ WriteScopeAttribute("[CLSCompliant(false)]");
+ WriteScopeAttribute("[ReflectionBlocked]");
+ _writer.WriteLine("#endif");
+ }
}
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/NativeFormatGen.csproj b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/NativeFormatGen.csproj
index f9927e4661d..03209735728 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/NativeFormatGen.csproj
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/NativeFormatGen.csproj
@@ -1,37 +1,10 @@
-<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
+ <TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<OutputType>Exe</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>NativeFormatGen</RootNamespace>
- <AssemblyName>NativeFormatGen</AssemblyName>
- <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
- <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+ <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <PlatformTarget>AnyCPU</PlatformTarget>
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <PlatformTarget>AnyCPU</PlatformTarget>
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="Microsoft.CSharp" />
- </ItemGroup>
+
<ItemGroup>
<Compile Include="CsWriter.cs" />
<Compile Include="MdBinaryReaderGen.cs" />
@@ -42,12 +15,4 @@
<Compile Include="SchemaDef.cs" />
<Compile Include="WriterGen.cs" />
</ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/PublicGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/PublicGen.cs
index 178d10e3699..e2139fb0bfc 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/PublicGen.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/PublicGen.cs
@@ -36,6 +36,7 @@ class PublicGen : CsWriter
WriteLine("using System;");
WriteLine("using System.Reflection;");
WriteLine("using System.Collections.Generic;");
+ WriteLine("using System.Runtime.CompilerServices;");
WriteLine();
WriteLine("#pragma warning disable 108 // base type 'uint' is not CLS-compliant");
@@ -81,6 +82,7 @@ class PublicGen : CsWriter
{
if ((record.Flags & RecordDefFlags.Flags) != 0)
WriteScopeAttribute("[Flags]");
+ WriteTypeAttributesForCoreLib();
OpenScope($"public enum {record.Name} : {record.BaseTypeName}");
foreach (var member in record.Members)
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs
index ea9bba916ba..21242607049 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs
@@ -21,12 +21,14 @@ class ReaderGen : CsWriter
WriteLine("#pragma warning disable 169");
WriteLine("#pragma warning disable 282 // There is no defined ordering between fields in multiple declarations of partial class or struct");
WriteLine("#pragma warning disable CA1066 // IEquatable<T> implementations aren't used");
+ WriteLine("#pragma warning disable CA1822");
WriteLine("#pragma warning disable IDE0059");
WriteLine();
WriteLine("using System;");
WriteLine("using System.Reflection;");
WriteLine("using System.Collections.Generic;");
+ WriteLine("using System.Runtime.CompilerServices;");
WriteLine("using Internal.NativeFormat;");
WriteLine();
@@ -57,6 +59,7 @@ class ReaderGen : CsWriter
private void EmitRecord(RecordDef record)
{
+ WriteTypeAttributesForCoreLib();
OpenScope($"public partial struct {record.Name}");
WriteLine("internal MetadataReader _reader;");
@@ -101,6 +104,7 @@ class ReaderGen : CsWriter
{
string handleName = $"{record.Name}Handle";
+ WriteTypeAttributesForCoreLib();
OpenScope($"public partial struct {handleName}");
OpenScope("public override bool Equals(object obj)");
@@ -175,6 +179,7 @@ class ReaderGen : CsWriter
private void EmitCollection(string collectionTypeName, string elementTypeName)
{
+ WriteTypeAttributesForCoreLib();
OpenScope($"public partial struct {collectionTypeName}");
WriteLine("private NativeReader _reader;");
@@ -197,6 +202,7 @@ class ReaderGen : CsWriter
WriteLine($"return new Enumerator(_reader, _offset);");
CloseScope("GetEnumerator");
+ WriteTypeAttributesForCoreLib();
OpenScope($"public struct Enumerator");
WriteLine("private NativeReader _reader;");
@@ -234,6 +240,7 @@ class ReaderGen : CsWriter
private void EmitOpaqueHandle()
{
+ WriteTypeAttributesForCoreLib();
OpenScope("public partial struct Handle");
foreach (var record in SchemaDef.RecordSchema)
@@ -250,6 +257,7 @@ class ReaderGen : CsWriter
private void EmitMetadataReader()
{
+ WriteTypeAttributesForCoreLib();
OpenScope("public partial class MetadataReader");
foreach (var record in SchemaDef.RecordSchema)
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs
index d7a28a874cc..355bd288672 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs
@@ -6,6 +6,7 @@
using System;
using System.Reflection;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
#pragma warning disable 108 // base type 'uint' is not CLS-compliant
#pragma warning disable 3009 // base type 'uint' is not CLS-compliant
@@ -14,6 +15,10 @@ using System.Collections.Generic;
namespace Internal.Metadata.NativeFormat
{
[Flags]
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public enum AssemblyFlags : uint
{
/// The assembly reference holds the full (unhashed) public key.
@@ -29,6 +34,10 @@ namespace Internal.Metadata.NativeFormat
EnableJITcompileTracking = 0x8000,
} // AssemblyFlags
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public enum AssemblyHashAlgorithm : uint
{
None = 0x0,
@@ -36,6 +45,10 @@ namespace Internal.Metadata.NativeFormat
SHA1 = 0x8004,
} // AssemblyHashAlgorithm
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public enum GenericParameterKind : byte
{
/// Represents a type parameter for a generic type.
@@ -45,6 +58,10 @@ namespace Internal.Metadata.NativeFormat
GenericMethodParameter = 0x1,
} // GenericParameterKind
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public enum NamedArgumentMemberKind : byte
{
/// Specifies the name of a property
@@ -54,6 +71,10 @@ namespace Internal.Metadata.NativeFormat
Field = 0x1,
} // NamedArgumentMemberKind
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public enum HandleType : byte
{
Null = 0x0,
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs
index b324c876461..faa24815ba5 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs
@@ -13,10 +13,15 @@
using System;
using System.Reflection;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
using Internal.NativeFormat;
namespace Internal.Metadata.NativeFormat
{
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ArraySignature
{
internal MetadataReader _reader;
@@ -72,6 +77,10 @@ namespace Internal.Metadata.NativeFormat
internal Int32Collection _lowerBounds;
} // ArraySignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ArraySignatureHandle
{
public override bool Equals(object obj)
@@ -155,6 +164,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ArraySignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ByReferenceSignature
{
internal MetadataReader _reader;
@@ -180,6 +193,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _type;
} // ByReferenceSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ByReferenceSignatureHandle
{
public override bool Equals(object obj)
@@ -263,6 +280,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ByReferenceSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantBooleanArray
{
internal MetadataReader _reader;
@@ -287,6 +308,10 @@ namespace Internal.Metadata.NativeFormat
internal BooleanCollection _value;
} // ConstantBooleanArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantBooleanArrayHandle
{
public override bool Equals(object obj)
@@ -370,6 +395,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantBooleanArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantBooleanValue
{
internal MetadataReader _reader;
@@ -394,6 +423,10 @@ namespace Internal.Metadata.NativeFormat
internal bool _value;
} // ConstantBooleanValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantBooleanValueHandle
{
public override bool Equals(object obj)
@@ -477,6 +510,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantBooleanValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantBoxedEnumValue
{
internal MetadataReader _reader;
@@ -513,6 +550,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _type;
} // ConstantBoxedEnumValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantBoxedEnumValueHandle
{
public override bool Equals(object obj)
@@ -596,6 +637,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantBoxedEnumValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantByteArray
{
internal MetadataReader _reader;
@@ -620,6 +665,10 @@ namespace Internal.Metadata.NativeFormat
internal ByteCollection _value;
} // ConstantByteArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantByteArrayHandle
{
public override bool Equals(object obj)
@@ -703,6 +752,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantByteArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantByteValue
{
internal MetadataReader _reader;
@@ -727,6 +780,10 @@ namespace Internal.Metadata.NativeFormat
internal byte _value;
} // ConstantByteValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantByteValueHandle
{
public override bool Equals(object obj)
@@ -810,6 +867,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantByteValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantCharArray
{
internal MetadataReader _reader;
@@ -834,6 +895,10 @@ namespace Internal.Metadata.NativeFormat
internal CharCollection _value;
} // ConstantCharArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantCharArrayHandle
{
public override bool Equals(object obj)
@@ -917,6 +982,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantCharArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantCharValue
{
internal MetadataReader _reader;
@@ -941,6 +1010,10 @@ namespace Internal.Metadata.NativeFormat
internal char _value;
} // ConstantCharValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantCharValueHandle
{
public override bool Equals(object obj)
@@ -1024,6 +1097,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantCharValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantDoubleArray
{
internal MetadataReader _reader;
@@ -1048,6 +1125,10 @@ namespace Internal.Metadata.NativeFormat
internal DoubleCollection _value;
} // ConstantDoubleArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantDoubleArrayHandle
{
public override bool Equals(object obj)
@@ -1131,6 +1212,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantDoubleArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantDoubleValue
{
internal MetadataReader _reader;
@@ -1155,6 +1240,10 @@ namespace Internal.Metadata.NativeFormat
internal double _value;
} // ConstantDoubleValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantDoubleValueHandle
{
public override bool Equals(object obj)
@@ -1238,6 +1327,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantDoubleValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantEnumArray
{
internal MetadataReader _reader;
@@ -1272,6 +1365,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _value;
} // ConstantEnumArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantEnumArrayHandle
{
public override bool Equals(object obj)
@@ -1355,6 +1452,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantEnumArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantHandleArray
{
internal MetadataReader _reader;
@@ -1379,6 +1480,10 @@ namespace Internal.Metadata.NativeFormat
internal HandleCollection _value;
} // ConstantHandleArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantHandleArrayHandle
{
public override bool Equals(object obj)
@@ -1462,6 +1567,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantHandleArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt16Array
{
internal MetadataReader _reader;
@@ -1486,6 +1595,10 @@ namespace Internal.Metadata.NativeFormat
internal Int16Collection _value;
} // ConstantInt16Array
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt16ArrayHandle
{
public override bool Equals(object obj)
@@ -1569,6 +1682,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantInt16ArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt16Value
{
internal MetadataReader _reader;
@@ -1593,6 +1710,10 @@ namespace Internal.Metadata.NativeFormat
internal short _value;
} // ConstantInt16Value
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt16ValueHandle
{
public override bool Equals(object obj)
@@ -1676,6 +1797,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantInt16ValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt32Array
{
internal MetadataReader _reader;
@@ -1700,6 +1825,10 @@ namespace Internal.Metadata.NativeFormat
internal Int32Collection _value;
} // ConstantInt32Array
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt32ArrayHandle
{
public override bool Equals(object obj)
@@ -1783,6 +1912,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantInt32ArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt32Value
{
internal MetadataReader _reader;
@@ -1807,6 +1940,10 @@ namespace Internal.Metadata.NativeFormat
internal int _value;
} // ConstantInt32Value
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt32ValueHandle
{
public override bool Equals(object obj)
@@ -1890,6 +2027,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantInt32ValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt64Array
{
internal MetadataReader _reader;
@@ -1914,6 +2055,10 @@ namespace Internal.Metadata.NativeFormat
internal Int64Collection _value;
} // ConstantInt64Array
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt64ArrayHandle
{
public override bool Equals(object obj)
@@ -1997,6 +2142,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantInt64ArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt64Value
{
internal MetadataReader _reader;
@@ -2021,6 +2170,10 @@ namespace Internal.Metadata.NativeFormat
internal long _value;
} // ConstantInt64Value
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantInt64ValueHandle
{
public override bool Equals(object obj)
@@ -2104,6 +2257,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantInt64ValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantReferenceValue
{
internal MetadataReader _reader;
@@ -2118,6 +2275,10 @@ namespace Internal.Metadata.NativeFormat
} // Handle
} // ConstantReferenceValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantReferenceValueHandle
{
public override bool Equals(object obj)
@@ -2201,6 +2362,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantReferenceValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSByteArray
{
internal MetadataReader _reader;
@@ -2225,6 +2390,10 @@ namespace Internal.Metadata.NativeFormat
internal SByteCollection _value;
} // ConstantSByteArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSByteArrayHandle
{
public override bool Equals(object obj)
@@ -2308,6 +2477,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantSByteArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSByteValue
{
internal MetadataReader _reader;
@@ -2332,6 +2505,10 @@ namespace Internal.Metadata.NativeFormat
internal sbyte _value;
} // ConstantSByteValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSByteValueHandle
{
public override bool Equals(object obj)
@@ -2415,6 +2592,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantSByteValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSingleArray
{
internal MetadataReader _reader;
@@ -2439,6 +2620,10 @@ namespace Internal.Metadata.NativeFormat
internal SingleCollection _value;
} // ConstantSingleArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSingleArrayHandle
{
public override bool Equals(object obj)
@@ -2522,6 +2707,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantSingleArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSingleValue
{
internal MetadataReader _reader;
@@ -2546,6 +2735,10 @@ namespace Internal.Metadata.NativeFormat
internal float _value;
} // ConstantSingleValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantSingleValueHandle
{
public override bool Equals(object obj)
@@ -2629,6 +2822,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantSingleValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantStringArray
{
internal MetadataReader _reader;
@@ -2654,6 +2851,10 @@ namespace Internal.Metadata.NativeFormat
internal HandleCollection _value;
} // ConstantStringArray
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantStringArrayHandle
{
public override bool Equals(object obj)
@@ -2737,6 +2938,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantStringArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantStringValue
{
internal MetadataReader _reader;
@@ -2761,6 +2966,10 @@ namespace Internal.Metadata.NativeFormat
internal string _value;
} // ConstantStringValue
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantStringValueHandle
{
public override bool Equals(object obj)
@@ -2844,6 +3053,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantStringValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt16Array
{
internal MetadataReader _reader;
@@ -2868,6 +3081,10 @@ namespace Internal.Metadata.NativeFormat
internal UInt16Collection _value;
} // ConstantUInt16Array
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt16ArrayHandle
{
public override bool Equals(object obj)
@@ -2951,6 +3168,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantUInt16ArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt16Value
{
internal MetadataReader _reader;
@@ -2975,6 +3196,10 @@ namespace Internal.Metadata.NativeFormat
internal ushort _value;
} // ConstantUInt16Value
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt16ValueHandle
{
public override bool Equals(object obj)
@@ -3058,6 +3283,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantUInt16ValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt32Array
{
internal MetadataReader _reader;
@@ -3082,6 +3311,10 @@ namespace Internal.Metadata.NativeFormat
internal UInt32Collection _value;
} // ConstantUInt32Array
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt32ArrayHandle
{
public override bool Equals(object obj)
@@ -3165,6 +3398,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantUInt32ArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt32Value
{
internal MetadataReader _reader;
@@ -3189,6 +3426,10 @@ namespace Internal.Metadata.NativeFormat
internal uint _value;
} // ConstantUInt32Value
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt32ValueHandle
{
public override bool Equals(object obj)
@@ -3272,6 +3513,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantUInt32ValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt64Array
{
internal MetadataReader _reader;
@@ -3296,6 +3541,10 @@ namespace Internal.Metadata.NativeFormat
internal UInt64Collection _value;
} // ConstantUInt64Array
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt64ArrayHandle
{
public override bool Equals(object obj)
@@ -3379,6 +3628,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantUInt64ArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt64Value
{
internal MetadataReader _reader;
@@ -3403,6 +3656,10 @@ namespace Internal.Metadata.NativeFormat
internal ulong _value;
} // ConstantUInt64Value
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ConstantUInt64ValueHandle
{
public override bool Equals(object obj)
@@ -3486,6 +3743,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ConstantUInt64ValueHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct CustomAttribute
{
internal MetadataReader _reader;
@@ -3532,6 +3793,10 @@ namespace Internal.Metadata.NativeFormat
internal NamedArgumentHandleCollection _namedArguments;
} // CustomAttribute
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct CustomAttributeHandle
{
public override bool Equals(object obj)
@@ -3615,6 +3880,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // CustomAttributeHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Event
{
internal MetadataReader _reader;
@@ -3680,6 +3949,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _customAttributes;
} // Event
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct EventHandle
{
public override bool Equals(object obj)
@@ -3763,6 +4036,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // EventHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Field
{
internal MetadataReader _reader;
@@ -3838,6 +4115,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _customAttributes;
} // Field
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct FieldHandle
{
public override bool Equals(object obj)
@@ -3921,6 +4202,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // FieldHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct FieldSignature
{
internal MetadataReader _reader;
@@ -3946,6 +4231,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _type;
} // FieldSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct FieldSignatureHandle
{
public override bool Equals(object obj)
@@ -4029,6 +4318,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // FieldSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct FunctionPointerSignature
{
internal MetadataReader _reader;
@@ -4053,6 +4346,10 @@ namespace Internal.Metadata.NativeFormat
internal MethodSignatureHandle _signature;
} // FunctionPointerSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct FunctionPointerSignatureHandle
{
public override bool Equals(object obj)
@@ -4136,6 +4433,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // FunctionPointerSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct GenericParameter
{
internal MetadataReader _reader;
@@ -4211,6 +4512,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _customAttributes;
} // GenericParameter
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct GenericParameterHandle
{
public override bool Equals(object obj)
@@ -4294,6 +4599,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // GenericParameterHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MemberReference
{
internal MetadataReader _reader;
@@ -4340,6 +4649,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _signature;
} // MemberReference
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MemberReferenceHandle
{
public override bool Equals(object obj)
@@ -4423,6 +4736,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // MemberReferenceHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Method
{
internal MetadataReader _reader;
@@ -4507,6 +4824,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _customAttributes;
} // Method
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodHandle
{
public override bool Equals(object obj)
@@ -4590,6 +4911,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // MethodHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodInstantiation
{
internal MetadataReader _reader;
@@ -4626,6 +4951,10 @@ namespace Internal.Metadata.NativeFormat
internal HandleCollection _genericTypeArguments;
} // MethodInstantiation
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodInstantiationHandle
{
public override bool Equals(object obj)
@@ -4709,6 +5038,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // MethodInstantiationHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodSemantics
{
internal MetadataReader _reader;
@@ -4743,6 +5076,10 @@ namespace Internal.Metadata.NativeFormat
internal MethodHandle _method;
} // MethodSemantics
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodSemanticsHandle
{
public override bool Equals(object obj)
@@ -4826,6 +5163,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // MethodSemanticsHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodSignature
{
internal MetadataReader _reader;
@@ -4893,6 +5234,10 @@ namespace Internal.Metadata.NativeFormat
internal HandleCollection _varArgParameters;
} // MethodSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodSignatureHandle
{
public override bool Equals(object obj)
@@ -4976,6 +5321,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // MethodSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodTypeVariableSignature
{
internal MetadataReader _reader;
@@ -5000,6 +5349,10 @@ namespace Internal.Metadata.NativeFormat
internal int _number;
} // MethodTypeVariableSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodTypeVariableSignatureHandle
{
public override bool Equals(object obj)
@@ -5083,6 +5436,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // MethodTypeVariableSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ModifiedType
{
internal MetadataReader _reader;
@@ -5129,6 +5486,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _type;
} // ModifiedType
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ModifiedTypeHandle
{
public override bool Equals(object obj)
@@ -5212,6 +5573,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ModifiedTypeHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamedArgument
{
internal MetadataReader _reader;
@@ -5268,6 +5633,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _value;
} // NamedArgument
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamedArgumentHandle
{
public override bool Equals(object obj)
@@ -5351,6 +5720,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // NamedArgumentHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamespaceDefinition
{
internal MetadataReader _reader;
@@ -5416,6 +5789,10 @@ namespace Internal.Metadata.NativeFormat
internal NamespaceDefinitionHandleCollection _namespaceDefinitions;
} // NamespaceDefinition
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamespaceDefinitionHandle
{
public override bool Equals(object obj)
@@ -5499,6 +5876,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // NamespaceDefinitionHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamespaceReference
{
internal MetadataReader _reader;
@@ -5534,6 +5915,10 @@ namespace Internal.Metadata.NativeFormat
internal ConstantStringValueHandle _name;
} // NamespaceReference
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamespaceReferenceHandle
{
public override bool Equals(object obj)
@@ -5617,6 +6002,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // NamespaceReferenceHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Parameter
{
internal MetadataReader _reader;
@@ -5682,6 +6071,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _customAttributes;
} // Parameter
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ParameterHandle
{
public override bool Equals(object obj)
@@ -5765,6 +6158,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ParameterHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct PointerSignature
{
internal MetadataReader _reader;
@@ -5790,6 +6187,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _type;
} // PointerSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct PointerSignatureHandle
{
public override bool Equals(object obj)
@@ -5873,6 +6274,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // PointerSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Property
{
internal MetadataReader _reader;
@@ -5948,6 +6353,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _customAttributes;
} // Property
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct PropertyHandle
{
public override bool Equals(object obj)
@@ -6031,6 +6440,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // PropertyHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct PropertySignature
{
internal MetadataReader _reader;
@@ -6077,6 +6490,10 @@ namespace Internal.Metadata.NativeFormat
internal HandleCollection _parameters;
} // PropertySignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct PropertySignatureHandle
{
public override bool Equals(object obj)
@@ -6160,6 +6577,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // PropertySignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct QualifiedField
{
internal MetadataReader _reader;
@@ -6194,6 +6615,10 @@ namespace Internal.Metadata.NativeFormat
internal TypeDefinitionHandle _enclosingType;
} // QualifiedField
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct QualifiedFieldHandle
{
public override bool Equals(object obj)
@@ -6277,6 +6702,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // QualifiedFieldHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct QualifiedMethod
{
internal MetadataReader _reader;
@@ -6311,6 +6740,10 @@ namespace Internal.Metadata.NativeFormat
internal TypeDefinitionHandle _enclosingType;
} // QualifiedMethod
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct QualifiedMethodHandle
{
public override bool Equals(object obj)
@@ -6394,6 +6827,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // QualifiedMethodHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct SZArraySignature
{
internal MetadataReader _reader;
@@ -6419,6 +6856,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _elementType;
} // SZArraySignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct SZArraySignatureHandle
{
public override bool Equals(object obj)
@@ -6502,6 +6943,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // SZArraySignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ScopeDefinition
{
internal MetadataReader _reader;
@@ -6676,6 +7121,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _moduleCustomAttributes;
} // ScopeDefinition
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ScopeDefinitionHandle
{
public override bool Equals(object obj)
@@ -6759,6 +7208,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ScopeDefinitionHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ScopeReference
{
internal MetadataReader _reader;
@@ -6853,6 +7306,10 @@ namespace Internal.Metadata.NativeFormat
internal ConstantStringValueHandle _culture;
} // ScopeReference
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ScopeReferenceHandle
{
public override bool Equals(object obj)
@@ -6936,6 +7393,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // ScopeReferenceHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeDefinition
{
internal MetadataReader _reader;
@@ -7102,6 +7563,10 @@ namespace Internal.Metadata.NativeFormat
internal CustomAttributeHandleCollection _customAttributes;
} // TypeDefinition
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeDefinitionHandle
{
public override bool Equals(object obj)
@@ -7185,6 +7650,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // TypeDefinitionHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeForwarder
{
internal MetadataReader _reader;
@@ -7229,6 +7698,10 @@ namespace Internal.Metadata.NativeFormat
internal TypeForwarderHandleCollection _nestedTypes;
} // TypeForwarder
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeForwarderHandle
{
public override bool Equals(object obj)
@@ -7312,6 +7785,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // TypeForwarderHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeInstantiationSignature
{
internal MetadataReader _reader;
@@ -7348,6 +7825,10 @@ namespace Internal.Metadata.NativeFormat
internal HandleCollection _genericTypeArguments;
} // TypeInstantiationSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeInstantiationSignatureHandle
{
public override bool Equals(object obj)
@@ -7431,6 +7912,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // TypeInstantiationSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeReference
{
internal MetadataReader _reader;
@@ -7466,6 +7951,10 @@ namespace Internal.Metadata.NativeFormat
internal ConstantStringValueHandle _typeName;
} // TypeReference
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeReferenceHandle
{
public override bool Equals(object obj)
@@ -7549,6 +8038,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // TypeReferenceHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeSpecification
{
internal MetadataReader _reader;
@@ -7574,6 +8067,10 @@ namespace Internal.Metadata.NativeFormat
internal Handle _signature;
} // TypeSpecification
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeSpecificationHandle
{
public override bool Equals(object obj)
@@ -7657,6 +8154,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // TypeSpecificationHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeVariableSignature
{
internal MetadataReader _reader;
@@ -7681,6 +8182,10 @@ namespace Internal.Metadata.NativeFormat
internal int _number;
} // TypeVariableSignature
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeVariableSignatureHandle
{
public override bool Equals(object obj)
@@ -7764,6 +8269,10 @@ namespace Internal.Metadata.NativeFormat
} // ToString
} // TypeVariableSignatureHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamedArgumentHandleCollection
{
private NativeReader _reader;
@@ -7790,6 +8299,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -7827,6 +8340,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // NamedArgumentHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodSemanticsHandleCollection
{
private NativeReader _reader;
@@ -7853,6 +8370,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -7890,6 +8411,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // MethodSemanticsHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct CustomAttributeHandleCollection
{
private NativeReader _reader;
@@ -7916,6 +8441,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -7953,6 +8482,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // CustomAttributeHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ParameterHandleCollection
{
private NativeReader _reader;
@@ -7979,6 +8512,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8016,6 +8553,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // ParameterHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct GenericParameterHandleCollection
{
private NativeReader _reader;
@@ -8042,6 +8583,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8079,6 +8624,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // GenericParameterHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeDefinitionHandleCollection
{
private NativeReader _reader;
@@ -8105,6 +8654,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8142,6 +8695,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // TypeDefinitionHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct TypeForwarderHandleCollection
{
private NativeReader _reader;
@@ -8168,6 +8725,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8205,6 +8766,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // TypeForwarderHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct NamespaceDefinitionHandleCollection
{
private NativeReader _reader;
@@ -8231,6 +8796,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8268,6 +8837,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // NamespaceDefinitionHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct MethodHandleCollection
{
private NativeReader _reader;
@@ -8294,6 +8867,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8331,6 +8908,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // MethodHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct FieldHandleCollection
{
private NativeReader _reader;
@@ -8357,6 +8938,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8394,6 +8979,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // FieldHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct PropertyHandleCollection
{
private NativeReader _reader;
@@ -8420,6 +9009,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8457,6 +9050,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // PropertyHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct EventHandleCollection
{
private NativeReader _reader;
@@ -8483,6 +9080,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8520,6 +9121,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // EventHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ScopeDefinitionHandleCollection
{
private NativeReader _reader;
@@ -8546,6 +9151,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8583,6 +9192,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // ScopeDefinitionHandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct BooleanCollection
{
private NativeReader _reader;
@@ -8609,6 +9222,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8646,6 +9263,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // BooleanCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct CharCollection
{
private NativeReader _reader;
@@ -8672,6 +9293,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8709,6 +9334,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // CharCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct ByteCollection
{
private NativeReader _reader;
@@ -8735,6 +9364,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8772,6 +9405,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // ByteCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct SByteCollection
{
private NativeReader _reader;
@@ -8798,6 +9435,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8835,6 +9476,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // SByteCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Int16Collection
{
private NativeReader _reader;
@@ -8861,6 +9506,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8898,6 +9547,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // Int16Collection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct UInt16Collection
{
private NativeReader _reader;
@@ -8924,6 +9577,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -8961,6 +9618,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // UInt16Collection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Int32Collection
{
private NativeReader _reader;
@@ -8987,6 +9648,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -9024,6 +9689,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // Int32Collection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct UInt32Collection
{
private NativeReader _reader;
@@ -9050,6 +9719,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -9087,6 +9760,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // UInt32Collection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Int64Collection
{
private NativeReader _reader;
@@ -9113,6 +9790,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -9150,6 +9831,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // Int64Collection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct UInt64Collection
{
private NativeReader _reader;
@@ -9176,6 +9861,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -9213,6 +9902,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // UInt64Collection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct SingleCollection
{
private NativeReader _reader;
@@ -9239,6 +9932,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -9276,6 +9973,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // SingleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct DoubleCollection
{
private NativeReader _reader;
@@ -9302,6 +10003,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -9339,6 +10044,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // DoubleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct Handle
{
public ArraySignatureHandle ToArraySignatureHandle(MetadataReader reader)
@@ -9657,6 +10366,10 @@ namespace Internal.Metadata.NativeFormat
} // ToTypeVariableSignatureHandle
} // Handle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial struct HandleCollection
{
private NativeReader _reader;
@@ -9683,6 +10396,10 @@ namespace Internal.Metadata.NativeFormat
return new Enumerator(_reader, _offset);
} // GetEnumerator
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public struct Enumerator
{
private NativeReader _reader;
@@ -9720,6 +10437,10 @@ namespace Internal.Metadata.NativeFormat
} // Enumerator
} // HandleCollection
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public partial class MetadataReader
{
public ArraySignature GetArraySignature(ArraySignatureHandle handle)
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs
index 8be485c1463..170dbc9efda 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs
@@ -16,6 +16,9 @@ namespace Internal.Metadata.NativeFormat
{
// This Enum matches CorMethodSemanticsAttr defined in CorHdr.h
[Flags]
+#if SYSTEM_PRIVATE_CORELIB
+ [ReflectionBlocked]
+#endif
public enum MethodSemanticsAttributes
{
Setter = 0x0001,
@@ -28,6 +31,9 @@ namespace Internal.Metadata.NativeFormat
// This Enum matches CorPInvokeMap defined in CorHdr.h
[Flags]
+#if SYSTEM_PRIVATE_CORELIB
+ [ReflectionBlocked]
+#endif
public enum PInvokeAttributes
{
NoMangle = 0x0001,
@@ -148,6 +154,10 @@ namespace Internal.Metadata.NativeFormat
#endif
}
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+ [ReflectionBlocked]
+#endif
public static class NativeFormatReaderExtensions
{
public static string GetString(this MetadataReader reader, ConstantStringValueHandle handle)
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/UpdateNativeFormatSources.cmd b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/UpdateNativeFormatSources.cmd
index b74e787cc77..4c2d088d59c 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/UpdateNativeFormatSources.cmd
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/UpdateNativeFormatSources.cmd
@@ -1,2 +1 @@
-csc Generator\*.cs /out:Generator.exe
-Generator.exe
+dotnet run --project Generator\NativeFormatGen.csproj
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
index 5dc8f3b12c6..fa7a9f8688d 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
@@ -2549,25 +2549,10 @@ namespace Internal.JitInterface
}
}
- [UnmanagedCallersOnly]
- static byte _doesFieldBelongToClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd, CORINFO_CLASS_STRUCT_* cls)
- {
- var _this = GetThis(thisHandle);
- try
- {
- return _this.doesFieldBelongToClass(fldHnd, cls) ? (byte)1 : (byte)0;
- }
- catch (Exception ex)
- {
- *ppException = _this.AllocException(ex);
- return default;
- }
- }
-
static IntPtr GetUnmanagedCallbacks()
{
- void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 173);
+ void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 172);
callbacks[0] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte>)&_isIntrinsic;
callbacks[1] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodAttribs;
@@ -2741,7 +2726,6 @@ namespace Internal.JitInterface
callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
- callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_doesFieldBelongToClass;
return (IntPtr)callbacks;
}
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs
index c161947fb83..b6d7649864b 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs
@@ -271,6 +271,7 @@ namespace Internal.JitInterface
CORINFO_HELP_THROW_NOT_IMPLEMENTED, // throw NotImplementedException
CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, // throw PlatformNotSupportedException
CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED, // throw TypeNotSupportedException
+ CORINFO_HELP_THROW_AMBIGUOUS_RESOLUTION_EXCEPTION, // throw AmbiguousResolutionException for failed static virtual method resolution
CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument
CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument
diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
index 964eebcfcc0..45fcdef14fa 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -325,4 +325,3 @@ FUNCTIONS
uint16_t getRelocTypeHint(void* target)
uint32_t getExpectedTargetArchitecture()
uint32_t getJitFlags(CORJIT_FLAGS* flags, uint32_t sizeInBytes)
- bool doesFieldBelongToClass(CORINFO_FIELD_HANDLE fldHnd, CORINFO_CLASS_HANDLE cls)
diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs
index 490e804dda6..0e38a100098 100644
--- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs
@@ -1544,16 +1544,12 @@ namespace Internal.TypeSystem.Interop
}
else
{
-#if READYTORUN
- throw new NotSupportedException();
-#else
var helper = Context.GetHelperEntryPoint("InteropHelpers", "StringToUnicodeBuffer");
LoadManagedValue(codeStream);
codeStream.Emit(ILOpcode.call, emitter.NewToken(helper));
StoreNativeValue(codeStream);
-#endif
}
}
@@ -1593,11 +1589,6 @@ namespace Internal.TypeSystem.Interop
class AnsiStringMarshaller : Marshaller
{
-#if READYTORUN
- const int MAX_LOCAL_BUFFER_LENGTH = 260 + 1; // MAX_PATH + 1
-
- private ILLocalVariable? _localBuffer = null;
-#endif
internal override bool CleanupRequired
{
@@ -1620,80 +1611,6 @@ namespace Internal.TypeSystem.Interop
//
// ANSI marshalling. Allocate a byte array, copy characters
//
-
-#if READYTORUN
- var stringToAnsi =
- Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
- .GetKnownMethod("ConvertToNative", null);
-
- bool bPassByValueInOnly = In && !Out && !IsManagedByRef;
-
- if (bPassByValueInOnly)
- {
- var bufSize = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32));
- _localBuffer = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr));
-
- // LocalBuffer = 0
- codeStream.Emit(ILOpcode.ldnull);
- codeStream.EmitStLoc((ILLocalVariable)_localBuffer);
-
- var noOptimize = emitter.NewCodeLabel();
-
- // if == NULL, goto NoOptimize
- LoadManagedValue(codeStream);
- codeStream.Emit(ILOpcode.brfalse, noOptimize);
-
- // String.Length + 2
- LoadManagedValue(codeStream);
- var stringLen =
- Context.GetWellKnownType(WellKnownType.String)
- .GetKnownMethod("get_Length", null);
- codeStream.Emit(ILOpcode.call, emitter.NewToken(stringLen));
- codeStream.EmitLdc(2);
- codeStream.Emit(ILOpcode.add);
-
- // (String.Length + 2) * GetMaxDBCSCharByteSize()
- codeStream.Emit(ILOpcode.ldsfld, emitter.NewToken(Context.SystemModule.GetKnownType(
- "System.Runtime.InteropServices","Marshal")
- .GetKnownField("SystemMaxDBCSCharSize")));
- codeStream.Emit(ILOpcode.mul_ovf);
-
- // BufSize = (String.Length + 2) * GetMaxDBCSCharByteSize()
- codeStream.EmitStLoc(bufSize);
-
- // if (MAX_LOCAL_BUFFER_LENGTH < BufSize ) goto NoOptimize
- codeStream.EmitLdc(MAX_LOCAL_BUFFER_LENGTH + 1);
- codeStream.EmitLdLoc(bufSize);
- codeStream.Emit(ILOpcode.clt);
- codeStream.Emit(ILOpcode.brtrue, noOptimize);
-
- // LocalBuffer = localloc(BufSize);
- codeStream.EmitLdLoc(bufSize);
- codeStream.Emit(ILOpcode.localloc);
- codeStream.EmitStLoc((ILLocalVariable)_localBuffer);
-
- // NoOptimize:
- codeStream.EmitLabel(noOptimize);
- }
-
- int flags = (PInvokeFlags.BestFitMapping ? 0x1 : 0)
- | (PInvokeFlags.ThrowOnUnmappableChar ? 0x100 : 0);
-
- // CSTRMarshaler.ConvertToNative pManaged, dwAnsiMarshalFlags, pLocalBuffer
- codeStream.EmitLdc(flags);
- LoadManagedValue(codeStream);
-
- if (_localBuffer.HasValue)
- {
- codeStream.EmitLdLoc((ILLocalVariable)_localBuffer);
- }
- else
- {
- codeStream.Emit(ILOpcode.ldnull);
- }
-
- codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi));
-#else
LoadManagedValue(codeStream);
var stringToAnsi = Context.GetHelperEntryPoint("InteropHelpers", "StringToAnsiString");
@@ -1701,7 +1618,6 @@ namespace Internal.TypeSystem.Interop
codeStream.Emit(PInvokeFlags.ThrowOnUnmappableChar ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0);
codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi));
-#endif
StoreNativeValue(codeStream);
}
@@ -1709,14 +1625,7 @@ namespace Internal.TypeSystem.Interop
protected override void TransformNativeToManaged(ILCodeStream codeStream)
{
ILEmitter emitter = _ilCodeStreams.Emitter;
-
-#if READYTORUN
- var ansiToString =
- Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
- .GetKnownMethod("ConvertToManaged", null);
-#else
var ansiToString = Context.GetHelperEntryPoint("InteropHelpers", "AnsiStringToString");
-#endif
LoadNativeValue(codeStream);
codeStream.Emit(ILOpcode.call, emitter.NewToken(ansiToString));
StoreManagedValue(codeStream);
@@ -1725,30 +1634,6 @@ namespace Internal.TypeSystem.Interop
protected override void EmitCleanupManaged(ILCodeStream codeStream)
{
var emitter = _ilCodeStreams.Emitter;
-#if READYTORUN
- var optimize = emitter.NewCodeLabel();
-
- MethodDesc clearNative =
- Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
- .GetKnownMethod("ClearNative", null);
-
- if (_localBuffer.HasValue)
- {
- // if (m_dwLocalBuffer) goto Optimize
- codeStream.EmitLdLoc((ILLocalVariable)_localBuffer);
- codeStream.Emit(ILOpcode.brtrue, optimize);
- }
-
- LoadNativeValue(codeStream);
- // static void m_idClearNative(IntPtr ptr)
- codeStream.Emit(ILOpcode.call, emitter.NewToken(clearNative));
-
- // Optimize:
- if (_localBuffer != default)
- {
- codeStream.EmitLabel(optimize);
- }
-#else
var lNullCheck = emitter.NewCodeLabel();
// Check for null array
@@ -1760,7 +1645,6 @@ namespace Internal.TypeSystem.Interop
InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null)));
codeStream.EmitLabel(lNullCheck);
-#endif
}
}
@@ -2042,11 +1926,7 @@ namespace Internal.TypeSystem.Interop
codeStream.Emit(ILOpcode.brfalse, lNullPointer);
codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
-#if READYTORUN
- InteropTypes.GetMarshal(Context).GetKnownMethod("GetFunctionPointerForDelegate",
-#else
InteropTypes.GetPInvokeMarshal(Context).GetKnownMethod("GetFunctionPointerForDelegate",
-#endif
new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.IntPtr),
new TypeDesc[] { Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType }
))));
@@ -2070,19 +1950,6 @@ namespace Internal.TypeSystem.Interop
LoadNativeValue(codeStream);
codeStream.Emit(ILOpcode.dup);
codeStream.Emit(ILOpcode.brfalse, lNullPointer);
-
-#if READYTORUN
- TypeDesc systemType = Context.SystemModule.GetKnownType("System", "Type");
-
- codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType));
- codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(systemType.GetKnownMethod("GetTypeFromHandle", null)));
-
- codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
- InteropTypes.GetMarshal(Context).GetKnownMethod("GetDelegateForFunctionPointer",
- new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType,
- new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr), systemType }
- ))));
-#else
codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType));
codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
@@ -2090,7 +1957,6 @@ namespace Internal.TypeSystem.Interop
new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType,
new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr), Context.GetWellKnownType(WellKnownType.RuntimeTypeHandle) }
))));
-#endif
codeStream.Emit(ILOpcode.br, lDone);
diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs
index ac32fbbe546..d78b275f49e 100644
--- a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs
@@ -44,11 +44,6 @@ namespace Internal.TypeSystem.Interop
return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "MemoryMarshal");
}
- public static MetadataType GetStubHelpers(TypeSystemContext context)
- {
- return context.SystemModule.GetKnownType("System.StubHelpers", "StubHelpers");
- }
-
public static MetadataType GetNativeFunctionPointerWrapper(TypeSystemContext context)
{
return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "NativeFunctionPointerWrapper");
diff --git a/src/coreclr/tools/aot/.editorconfig b/src/coreclr/tools/aot/.editorconfig
new file mode 100644
index 00000000000..5f1bbfd2429
--- /dev/null
+++ b/src/coreclr/tools/aot/.editorconfig
@@ -0,0 +1,29 @@
+# Linker port settings:
+# A newline ending every file
+# Use tabs as indentation
+[ILLink.Shared/**.cs]
+indent_style = tab
+indent_size = 4
+csharp_new_line_before_open_brace = types,methods
+csharp_new_line_before_else = false
+csharp_new_line_before_catch = false
+csharp_new_line_before_finally = false
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_declaration_name_and_open_parenthesis = true
+csharp_space_between_method_call_name_and_opening_parenthesis = true
+csharp_space_before_open_square_brackets = false
+csharp_space_after_cast = true
+
+csharp_indent_switch_labels = false
+
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DependencyGraphTests.cs b/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DependencyGraphTests.cs
index a4e3ee1ae0d..dc1bf6c9cd0 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DependencyGraphTests.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DependencyGraphTests.cs
@@ -71,7 +71,7 @@ namespace ILCompiler.Compiler.Tests
UsageBasedMetadataManager metadataManager = new UsageBasedMetadataManager(compilationGroup, context,
new FullyBlockedMetadataBlockingPolicy(), new FullyBlockedManifestResourceBlockingPolicy(),
null, new NoStackTraceEmissionPolicy(), new NoDynamicInvokeThunkGenerationPolicy(),
- new Dataflow.FlowAnnotations(Logger.Null, ilProvider), UsageBasedMetadataGenerationOptions.None,
+ new ILLink.Shared.TrimAnalysis.FlowAnnotations(Logger.Null, ilProvider), UsageBasedMetadataGenerationOptions.None,
Logger.Null, Array.Empty<KeyValuePair<string, bool>>(), Array.Empty<string>(), Array.Empty<string>());
CompilationBuilder builder = new RyuJitCompilationBuilder(context, compilationGroup)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ArrayValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ArrayValue.cs
new file mode 100644
index 00000000000..5c48191c8ec
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ArrayValue.cs
@@ -0,0 +1,130 @@
+// 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.Text;
+using ILCompiler.Dataflow;
+using ILLink.Shared.DataFlow;
+using Internal.TypeSystem;
+
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ partial record ArrayValue
+ {
+ public static MultiValue Create(MultiValue size, TypeDesc elementType)
+ {
+ MultiValue result = MultiValueLattice.Top;
+ foreach (var sizeValue in size)
+ {
+ result = MultiValueLattice.Meet(result, new MultiValue(new ArrayValue(sizeValue, elementType)));
+ }
+
+ return result;
+ }
+
+ public static MultiValue Create(int size, TypeDesc elementType)
+ {
+ return new MultiValue(new ArrayValue(new ConstIntValue(size), elementType));
+ }
+
+ /// <summary>
+ /// Constructs an array value of the given size
+ /// </summary>
+ ArrayValue(SingleValue size, TypeDesc elementType)
+ {
+ Size = size;
+ ElementType = elementType;
+ IndexValues = new Dictionary<int, ValueBasicBlockPair>();
+ }
+
+ public TypeDesc ElementType { get; }
+ public Dictionary<int, ValueBasicBlockPair> IndexValues { get; }
+
+ public partial bool TryGetValueByIndex(int index, out MultiValue value)
+ {
+ if (IndexValues.TryGetValue(index, out var valuePair))
+ {
+ value = valuePair.Value;
+ return true;
+ }
+
+ value = default;
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(GetType().GetHashCode(), Size);
+ }
+
+ public bool Equals(ArrayValue? otherArr)
+ {
+ if (otherArr == null)
+ return false;
+
+ bool equals = Size.Equals(otherArr.Size);
+ equals &= IndexValues.Count == otherArr.IndexValues.Count;
+ if (!equals)
+ return false;
+
+ // If both sets T and O are the same size and "T intersect O" is empty, then T == O.
+ HashSet<KeyValuePair<int, ValueBasicBlockPair>> thisValueSet = new(IndexValues);
+ HashSet<KeyValuePair<int, ValueBasicBlockPair>> otherValueSet = new(otherArr.IndexValues);
+ thisValueSet.ExceptWith(otherValueSet);
+ return thisValueSet.Count == 0;
+ }
+
+ public override SingleValue DeepCopy()
+ {
+ var newValue = new ArrayValue(Size.DeepCopy(), ElementType);
+ foreach (var kvp in IndexValues)
+ {
+ newValue.IndexValues.Add(kvp.Key, new ValueBasicBlockPair(kvp.Value.Value.Clone(), kvp.Value.BasicBlockIndex));
+ }
+
+ return newValue;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder result = new();
+ result.Append("Array Size:");
+ result.Append(this.ValueToString(Size));
+
+ result.Append(", Values:(");
+ bool first = true;
+ foreach (var element in IndexValues)
+ {
+ if (!first)
+ {
+ result.Append(",");
+ first = false;
+ }
+
+ result.Append("(");
+ result.Append(element.Key);
+ result.Append(",(");
+ bool firstValue = true;
+ foreach (var v in element.Value.Value)
+ {
+ if (firstValue)
+ {
+ result.Append(",");
+ firstValue = false;
+ }
+
+ result.Append(v.ToString());
+ }
+ result.Append("))");
+ }
+ result.Append(')');
+
+ return result.ToString();
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticContext.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticContext.cs
new file mode 100644
index 00000000000..afb38e0370a
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticContext.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using ILCompiler;
+using ILCompiler.Logging;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ readonly partial struct DiagnosticContext
+ {
+ public readonly MessageOrigin Origin;
+ public readonly bool DiagnosticsEnabled;
+ readonly Logger _logger;
+
+ public DiagnosticContext(in MessageOrigin origin, bool diagnosticsEnabled, Logger logger)
+ => (Origin, DiagnosticsEnabled, _logger) = (origin, diagnosticsEnabled, logger);
+
+ public partial void AddDiagnostic(DiagnosticId id, params string[] args)
+ {
+ if (DiagnosticsEnabled)
+ _logger.LogWarning(Origin, id, args);
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticUtilities.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticUtilities.cs
index 828c073f246..5cf498bcfc6 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticUtilities.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticUtilities.cs
@@ -131,12 +131,12 @@ namespace ILCompiler.Dataflow
method.IsInRequiresScope(requiresAttribute, true);
/// <summary>
- /// True if member of a call is considered to be annotated with the Requires... attribute.
- /// Doesn't check the associated symbol for overrides and virtual methods because we should warn on mismatched between the property AND the accessors
- /// </summary>
- /// <param name="method">
- /// MethodDesc that is either an overriding member or an overriden/virtual member
- /// </param>
+ /// True if member of a call is considered to be annotated with the Requires... attribute.
+ /// Doesn't check the associated symbol for overrides and virtual methods because we should warn on mismatched between the property AND the accessors
+ /// </summary>
+ /// <param name="method">
+ /// MethodDesc that is either an overriding member or an overriden/virtual member
+ /// </param>
internal static bool IsOverrideInRequiresScope(this MethodDesc method, string requiresAttribute) =>
method.IsInRequiresScope(requiresAttribute, false);
@@ -185,10 +185,10 @@ namespace ILCompiler.Dataflow
TryGetRequiresAttribute(property, requiresAttribute, out attribute);
/// <summary>
- /// Determines if member requires (and thus any usage of such method should be warned about).
- /// </summary>
- /// <remarks>Unlike <see cref="IsInRequiresScope(MethodDesc, string)"/> only static methods
- /// and .ctors are reported as requires when the declaring type has Requires on it.</remarks>
+ /// Determines if member requires (and thus any usage of such method should be warned about).
+ /// </summary>
+ /// <remarks>Unlike <see cref="IsInRequiresScope(MethodDesc, string)"/> only static methods
+ /// and .ctors are reported as requires when the declaring type has Requires on it.</remarks>
internal static bool DoesMemberRequire(this TypeSystemEntity member, string requiresAttribute, [NotNullWhen(returnValue: true)] out CustomAttributeValue<TypeDesc>? attribute)
{
attribute = null;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs
index 1704c3c8267..4b621432c74 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs
@@ -352,7 +352,7 @@ namespace ILCompiler.Dataflow
type = type.BaseType;
onBaseType = true;
}
-
+
while (type != null)
{
if (type.GetTypeDefinition() is not EcmaType ecmaType)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/EcmaExtensions.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/EcmaExtensions.cs
index 07dcfb8362c..77266e84ddc 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/EcmaExtensions.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/EcmaExtensions.cs
@@ -22,7 +22,7 @@ namespace ILCompiler.Dataflow
public static bool IsPublic(this FieldDesc field)
{
return field.GetTypicalFieldDefinition() is EcmaField ecmaField
- && (ecmaField.Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Public;
+ && (ecmaField.Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Public;
}
public static bool IsPrivate(this MethodDesc method)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FieldValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FieldValue.cs
new file mode 100644
index 00000000000..3c23fba55f5
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FieldValue.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.
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILCompiler;
+using ILCompiler.Dataflow;
+using ILLink.Shared.DataFlow;
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+
+ /// <summary>
+ /// A representation of a field. Typically a result of ldfld.
+ /// </summary>
+ sealed partial record FieldValue : IValueWithStaticType
+ {
+ public FieldValue(FieldDesc field, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ StaticType = field.FieldType;
+ Field = field;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly FieldDesc Field;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch()
+ => new string[] { Field.GetDisplayName() };
+
+ public TypeDesc? StaticType { get; }
+
+ public override SingleValue DeepCopy() => this; // This value is immutable
+
+ public override string ToString() => this.ValueToString(Field, DynamicallyAccessedMemberTypes);
+ }
+}
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 107a15ea481..489c2726eb2 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs
@@ -9,17 +9,22 @@ using System.Reflection.Metadata;
using Internal.IL;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
-
+using ILCompiler;
+using ILCompiler.Dataflow;
using ILLink.Shared;
+using ILLink.Shared.TypeSystemProxy;
using Debug = System.Diagnostics.Debug;
+using WellKnownType = Internal.TypeSystem.WellKnownType;
+
+#nullable enable
-namespace ILCompiler.Dataflow
+namespace ILLink.Shared.TrimAnalysis
{
/// <summary>
/// Caches dataflow annotations for type members.
/// </summary>
- public class FlowAnnotations
+ public partial class FlowAnnotations
{
private readonly TypeAnnotationsHashtable _hashtable;
private readonly Logger _logger;
@@ -145,7 +150,7 @@ namespace ILCompiler.Dataflow
public bool ShouldWarnWhenAccessedForReflection(MethodDesc method)
{
method = method.GetTypicalMethodDefinition();
-
+
if (!GetAnnotations(method.OwningType).TryGetAnnotation(method, out var annotation))
return false;
@@ -249,7 +254,7 @@ namespace ILCompiler.Dataflow
// class, interface, struct can have annotations
TypeDefinition typeDef = reader.GetTypeDefinition(ecmaType.Handle);
DynamicallyAccessedMemberTypes typeAnnotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, typeDef.GetCustomAttributes());
-
+
try
{
// Also inherit annotation from bases
@@ -301,14 +306,14 @@ namespace ILCompiler.Dataflow
// Next go over all methods with an explicit annotation
foreach (EcmaMethod method in ecmaType.GetMethods())
{
- DynamicallyAccessedMemberTypes[] paramAnnotations = null;
+ DynamicallyAccessedMemberTypes[]? paramAnnotations = null;
// We convert indices from metadata space to IL space here.
// IL space assigns index 0 to the `this` parameter on instance methods.
DynamicallyAccessedMemberTypes methodMemberTypes =
GetMemberTypesForDynamicallyAccessedMembersAttribute(reader, reader.GetMethodDefinition(method.Handle).GetCustomAttributes());
-
+
MethodSignature signature;
try
{
@@ -383,7 +388,7 @@ namespace ILCompiler.Dataflow
}
}
- DynamicallyAccessedMemberTypes[] genericParameterAnnotations = null;
+ DynamicallyAccessedMemberTypes[]? genericParameterAnnotations = null;
foreach (EcmaGenericParameter genericParameter in method.Instantiation)
{
GenericParameter genericParameterDef = reader.GetGenericParameter(genericParameter.Handle);
@@ -431,7 +436,7 @@ namespace ILCompiler.Dataflow
continue;
}
- FieldDesc backingFieldFromSetter = null;
+ FieldDesc? backingFieldFromSetter = null;
// Propagate the annotation to the setter method
MethodDesc setMethod = property.SetMethod;
@@ -451,7 +456,7 @@ namespace ILCompiler.Dataflow
if (annotatedMethods.Any(a => a.Method == setMethod))
{
-
+
_logger.LogWarning(setMethod, DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor, property.GetDisplayName(), setMethod.GetDisplayName());
}
else
@@ -466,7 +471,7 @@ namespace ILCompiler.Dataflow
}
}
- FieldDesc backingFieldFromGetter = null;
+ FieldDesc? backingFieldFromGetter = null;
// Propagate the annotation to the getter method
MethodDesc getMethod = property.GetMethod;
@@ -494,7 +499,7 @@ namespace ILCompiler.Dataflow
}
}
- FieldDesc backingField;
+ FieldDesc? backingField;
if (backingFieldFromGetter != null && backingFieldFromSetter != null &&
backingFieldFromGetter != backingFieldFromSetter)
{
@@ -519,7 +524,7 @@ namespace ILCompiler.Dataflow
}
}
- DynamicallyAccessedMemberTypes[] typeGenericParameterAnnotations = null;
+ DynamicallyAccessedMemberTypes[]? typeGenericParameterAnnotations = null;
foreach (EcmaGenericParameter genericParameter in ecmaType.Instantiation)
{
GenericParameter genericParameterDef = reader.GetGenericParameter(genericParameter.Handle);
@@ -536,7 +541,7 @@ namespace ILCompiler.Dataflow
return new TypeAnnotations(ecmaType, typeAnnotation, annotatedMethods.ToArray(), annotatedFields.ToArray(), typeGenericParameterAnnotations);
}
- private static bool ScanMethodBodyForFieldAccess(MethodIL body, bool write, out FieldDesc found)
+ private static bool ScanMethodBodyForFieldAccess(MethodIL body, bool write, out FieldDesc? found)
{
// Tries to find the backing field for a property getter/setter.
// Returns true if this is a method body that we can unambiguously analyze.
@@ -637,7 +642,7 @@ namespace ILCompiler.Dataflow
if (methodAnnotations.ParameterAnnotations != null || baseMethodAnnotations.ParameterAnnotations != null)
{
if (methodAnnotations.ParameterAnnotations == null)
- ValidateMethodParametersHaveNoAnnotations(baseMethodAnnotations.ParameterAnnotations, method, baseMethod, method);
+ ValidateMethodParametersHaveNoAnnotations(baseMethodAnnotations.ParameterAnnotations!, method, baseMethod, method);
else if (baseMethodAnnotations.ParameterAnnotations == null)
ValidateMethodParametersHaveNoAnnotations(methodAnnotations.ParameterAnnotations, method, baseMethod, method);
else
@@ -659,7 +664,7 @@ namespace ILCompiler.Dataflow
if (methodAnnotations.GenericParameterAnnotations != null || baseMethodAnnotations.GenericParameterAnnotations != null)
{
if (methodAnnotations.GenericParameterAnnotations == null)
- ValidateMethodGenericParametersHaveNoAnnotations(baseMethodAnnotations.GenericParameterAnnotations, method, baseMethod, method);
+ ValidateMethodGenericParametersHaveNoAnnotations(baseMethodAnnotations.GenericParameterAnnotations!, method, baseMethod, method);
else if (baseMethodAnnotations.GenericParameterAnnotations == null)
ValidateMethodGenericParametersHaveNoAnnotations(methodAnnotations.GenericParameterAnnotations, method, baseMethod, method);
else
@@ -740,18 +745,18 @@ namespace ILCompiler.Dataflow
{
public readonly TypeDesc Type;
public readonly DynamicallyAccessedMemberTypes TypeAnnotation;
- private readonly MethodAnnotations[] _annotatedMethods;
- private readonly FieldAnnotation[] _annotatedFields;
- private readonly DynamicallyAccessedMemberTypes[] _genericParameterAnnotations;
+ private readonly MethodAnnotations[]? _annotatedMethods;
+ private readonly FieldAnnotation[]? _annotatedFields;
+ private readonly DynamicallyAccessedMemberTypes[]? _genericParameterAnnotations;
public bool IsDefault => _annotatedMethods == null && _annotatedFields == null && _genericParameterAnnotations == null;
public TypeAnnotations(
TypeDesc type,
DynamicallyAccessedMemberTypes typeAnnotations,
- MethodAnnotations[] annotatedMethods,
- FieldAnnotation[] annotatedFields,
- DynamicallyAccessedMemberTypes[] genericParameterAnnotations)
+ MethodAnnotations[]? annotatedMethods,
+ FieldAnnotation[]? annotatedFields,
+ DynamicallyAccessedMemberTypes[]? genericParameterAnnotations)
=> (Type, TypeAnnotation, _annotatedMethods, _annotatedFields, _genericParameterAnnotations)
= (type, typeAnnotations, annotatedMethods, annotatedFields, genericParameterAnnotations);
@@ -820,15 +825,15 @@ namespace ILCompiler.Dataflow
private readonly struct MethodAnnotations
{
public readonly MethodDesc Method;
- public readonly DynamicallyAccessedMemberTypes[] ParameterAnnotations;
+ public readonly DynamicallyAccessedMemberTypes[]? ParameterAnnotations;
public readonly DynamicallyAccessedMemberTypes ReturnParameterAnnotation;
- public readonly DynamicallyAccessedMemberTypes[] GenericParameterAnnotations;
+ public readonly DynamicallyAccessedMemberTypes[]? GenericParameterAnnotations;
public MethodAnnotations(
MethodDesc method,
- DynamicallyAccessedMemberTypes[] paramAnnotations,
+ DynamicallyAccessedMemberTypes[]? paramAnnotations,
DynamicallyAccessedMemberTypes returnParamAnnotations,
- DynamicallyAccessedMemberTypes[] genericParameterAnnotations)
+ DynamicallyAccessedMemberTypes[]? genericParameterAnnotations)
=> (Method, ParameterAnnotations, ReturnParameterAnnotation, GenericParameterAnnotations) =
(method, paramAnnotations, returnParamAnnotations, genericParameterAnnotations);
@@ -860,5 +865,31 @@ namespace ILCompiler.Dataflow
public FieldAnnotation(FieldDesc field, DynamicallyAccessedMemberTypes annotation)
=> (Field, Annotation) = (field, annotation);
}
+
+ 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)
+ => GetMethodReturnValue(method, GetReturnParameterAnnotation(method.Method));
+
+ internal partial GenericParameterValue GetGenericParameterValue(GenericParameterProxy genericParameter)
+ => new GenericParameterValue(genericParameter.GenericParameter, GetGenericParameterAnnotation(genericParameter.GenericParameter));
+
+#pragma warning disable CA1822 // Mark members as static - keep this an instance method for consistency with the others
+ internal partial MethodThisParameterValue GetMethodThisParameterValue(MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new MethodThisParameterValue(method.Method, dynamicallyAccessedMemberTypes);
+#pragma warning restore CA1822
+
+ internal partial MethodThisParameterValue GetMethodThisParameterValue(MethodProxy method)
+ => GetMethodThisParameterValue(method, GetParameterAnnotation(method.Method, 0));
+
+ internal partial MethodParameterValue GetMethodParameterValue(MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new(method.Method, parameterIndex, dynamicallyAccessedMemberTypes);
+
+ internal partial MethodParameterValue GetMethodParameterValue(MethodProxy method, int parameterIndex)
+ => GetMethodParameterValue(method, parameterIndex, GetParameterAnnotation(method.Method, parameterIndex + (method.IsStatic() ? 0 : 1)));
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterProxy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterProxy.cs
new file mode 100644
index 00000000000..b04e245ee50
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterProxy.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal readonly partial struct GenericParameterProxy
+ {
+ public GenericParameterProxy(GenericParameterDesc genericParameter) => GenericParameter = genericParameter;
+
+ public static implicit operator GenericParameterProxy(GenericParameterDesc genericParameter) => new(genericParameter);
+
+ internal partial bool HasDefaultConstructorConstraint() => GenericParameter.HasDefaultConstructorConstraint;
+
+ public readonly GenericParameterDesc GenericParameter;
+
+ public override string ToString() => GenericParameter.ToString();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterValue.cs
new file mode 100644
index 00000000000..423b17c54d5
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterValue.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;
+using ILCompiler.Dataflow;
+using ILLink.Shared.DataFlow;
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is a System.Type value which represents generic parameter (basically result of typeof(T))
+ /// Its actual type is unknown, but it can have annotations.
+ /// </summary>
+ partial record GenericParameterValue
+ {
+ public GenericParameterValue(GenericParameterDesc genericParameter, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ GenericParameter = new(genericParameter);
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch()
+ => new string[] { GenericParameter.GenericParameter.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(new GenericParameterOrigin(GenericParameter.GenericParameter)) };
+
+ public override SingleValue DeepCopy() => this; // This value is immutable
+
+ public override string ToString() => this.ValueToString(GenericParameter, DynamicallyAccessedMemberTypes);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs
new file mode 100644
index 00000000000..9b41163b33a
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs
@@ -0,0 +1,126 @@
+// 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.Reflection;
+using ILCompiler;
+using ILCompiler.Dataflow;
+using ILLink.Shared.TypeSystemProxy;
+using Internal.TypeSystem;
+
+using WellKnownType = ILLink.Shared.TypeSystemProxy.WellKnownType;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ partial struct HandleCallAction
+ {
+#pragma warning disable CA1822 // Mark members as static - the other partial implementations might need to be instance methods
+
+ readonly ReflectionMarker _reflectionMarker;
+ readonly MethodDesc _callingMethod;
+ readonly Origin _memberWithRequirements;
+
+ public HandleCallAction(
+ FlowAnnotations annotations,
+ ReflectionMarker reflectionMarker,
+ in DiagnosticContext diagnosticContext,
+ MethodDesc callingMethod,
+ Origin memberWithRequirements)
+ {
+ _reflectionMarker = reflectionMarker;
+ _diagnosticContext = diagnosticContext;
+ _callingMethod = callingMethod;
+ _annotations = annotations;
+ _memberWithRequirements = memberWithRequirements;
+ _requireDynamicallyAccessedMembersAction = new(reflectionMarker, diagnosticContext, memberWithRequirements);
+ }
+
+ private partial bool MethodIsTypeConstructor(MethodProxy method)
+ {
+ if (!method.Method.IsConstructor)
+ return false;
+ TypeDesc? type = method.Method.OwningType;
+ while (type is not null)
+ {
+ if (type.IsTypeOf(WellKnownType.System_Type))
+ return true;
+ type = type.BaseType;
+ }
+ return false;
+ }
+
+ private partial IEnumerable<SystemReflectionMethodBaseValue> GetMethodsOnTypeHierarchy(TypeProxy type, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var method in type.Type.GetMethodsOnTypeHierarchy(m => m.Name == name, bindingFlags))
+ yield return new SystemReflectionMethodBaseValue(new MethodProxy(method));
+ }
+
+ private partial IEnumerable<SystemTypeValue> GetNestedTypesOnType(TypeProxy type, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var nestedType in type.Type.GetNestedTypesOnType(t => t.Name == name, bindingFlags))
+ yield return new SystemTypeValue(new TypeProxy(nestedType));
+ }
+
+ private partial bool TryGetBaseType(TypeProxy type, out TypeProxy? baseType)
+ {
+ if (type.Type.BaseType != null)
+ {
+ baseType = new TypeProxy(type.Type.BaseType);
+ return true;
+ }
+
+ baseType = null;
+ return false;
+ }
+
+ private partial bool TryResolveTypeNameForCreateInstance(in MethodProxy calledMethod, string assemblyName, string typeName, out TypeProxy resolvedType)
+ {
+ // TODO: niche APIs that we probably shouldn't even have added
+ // We have to issue a warning, otherwise we could break the app without a warning.
+ // This is not the ideal warning, but it's good enough for now.
+ _diagnosticContext.AddDiagnostic(DiagnosticId.UnrecognizedParameterInMethodCreateInstance, calledMethod.GetParameterDisplayName(1), calledMethod.GetDisplayName());
+ resolvedType = default;
+ return false;
+ }
+
+ private partial void MarkStaticConstructor(TypeProxy type)
+ => _reflectionMarker.MarkStaticConstructor(_diagnosticContext.Origin, type.Type);
+
+ private partial void MarkEventsOnTypeHierarchy(TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMarker.MarkEventsOnTypeHierarchy(_diagnosticContext.Origin, type.Type, e => e.Name == name, _memberWithRequirements, bindingFlags);
+
+ private partial void MarkFieldsOnTypeHierarchy(TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMarker.MarkFieldsOnTypeHierarchy(_diagnosticContext.Origin, type.Type, f => f.Name == name, _memberWithRequirements, bindingFlags);
+
+ private partial void MarkPropertiesOnTypeHierarchy(TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMarker.MarkPropertiesOnTypeHierarchy(_diagnosticContext.Origin, type.Type, p => p.Name == name, _memberWithRequirements, bindingFlags);
+
+ private partial void MarkPublicParameterlessConstructorOnType(TypeProxy type)
+ => _reflectionMarker.MarkConstructorsOnType(_diagnosticContext.Origin, type.Type, m => m.IsPublic() && m.Signature.Length == 0, _memberWithRequirements);
+
+ private partial void MarkConstructorsOnType(TypeProxy type, BindingFlags? bindingFlags, int? parameterCount)
+ => _reflectionMarker.MarkConstructorsOnType(_diagnosticContext.Origin, type.Type, parameterCount == null ? null : m => m.Signature.Length == parameterCount, _memberWithRequirements, bindingFlags);
+
+ private partial void MarkMethod(MethodProxy method)
+ => _reflectionMarker.MarkMethod(_diagnosticContext.Origin, method.Method, _memberWithRequirements);
+
+ private partial void MarkType(TypeProxy type)
+ => _reflectionMarker.MarkType(_diagnosticContext.Origin, type.Type, _memberWithRequirements);
+
+ private partial bool MarkAssociatedProperty(MethodProxy method)
+ {
+ var propertyDefinition = method.Method.GetPropertyForAccessor();
+ if (propertyDefinition is null)
+ {
+ return false;
+ }
+
+ _reflectionMarker.MarkProperty(_diagnosticContext.Origin, propertyDefinition, _memberWithRequirements);
+ return true;
+ }
+
+ private partial string GetContainingSymbolDisplayName() => _callingMethod.GetDisplayName();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/IValueWithStaticType.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/IValueWithStaticType.cs
new file mode 100644
index 00000000000..eb08e77d017
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/IValueWithStaticType.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 Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILCompiler.Dataflow
+{
+ interface IValueWithStaticType
+ {
+ /// <summary>
+ /// The IL type of the value, represented as closely as possible, but not always exact. It can be null, for
+ /// example, when the analysis is imprecise or operating on malformed IL.
+ /// </summary>
+ TypeDesc? StaticType { get; }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodBodyScanner.cs
index f07166e28d8..535ae2d1cf2 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodBodyScanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodBodyScanner.cs
@@ -4,10 +4,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
-
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TrimAnalysis;
+using ILLink.Shared.TypeSystemProxy;
using Internal.IL;
using Internal.TypeSystem;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+
+#nullable enable
+
namespace ILCompiler.Dataflow
{
/// <summary>
@@ -15,14 +21,26 @@ namespace ILCompiler.Dataflow
/// </summary>
readonly struct StackSlot
{
- public ValueNode Value { get; }
+ public MultiValue Value { get; }
/// <summary>
/// True if the value is on the stack as a byref
/// </summary>
public bool IsByRef { get; }
- public StackSlot(ValueNode value, bool isByRef = false)
+ public StackSlot()
+ {
+ Value = new MultiValue(UnknownValue.Instance);
+ IsByRef = false;
+ }
+
+ public StackSlot(SingleValue value, bool isByRef = false)
+ {
+ Value = new MultiValue(value);
+ IsByRef = isByRef;
+ }
+
+ public StackSlot(MultiValue value, bool isByRef = false)
{
Value = value;
IsByRef = isByRef;
@@ -31,7 +49,9 @@ namespace ILCompiler.Dataflow
abstract partial class MethodBodyScanner
{
- internal ValueNode MethodReturnValue { private set; get; }
+ protected static ValueSetLattice<SingleValue> MultiValueLattice => default;
+
+ internal MultiValue ReturnValue { private set; get; }
protected virtual void WarnAboutInvalidILInMethod(MethodIL method, int ilOffset)
{
@@ -78,21 +98,7 @@ namespace ILCompiler.Dataflow
private static StackSlot MergeStackElement(StackSlot a, StackSlot b)
{
- StackSlot mergedSlot;
- if (b.Value == null)
- {
- mergedSlot = a;
- }
- else if (a.Value == null)
- {
- mergedSlot = b;
- }
- else
- {
- mergedSlot = new StackSlot(MergePointValue.MergeValues(a.Value, b.Value));
- }
-
- return mergedSlot;
+ return new StackSlot(MultiValueLattice.Meet(a.Value, b.Value));
}
// Merge stacks together. This may return the first stack, the stack length must be the same for the two stacks.
@@ -121,7 +127,7 @@ namespace ILCompiler.Dataflow
return new Stack<StackSlot>(newStack);
}
- private static void ClearStack(ref Stack<StackSlot> stack)
+ private static void ClearStack(ref Stack<StackSlot>? stack)
{
stack = null;
}
@@ -188,63 +194,62 @@ namespace ILCompiler.Dataflow
}
private static void StoreMethodLocalValue(
- ValueBasicBlockPair[] valueCollection,
- ValueNode valueToStore,
+ ValueBasicBlockPair?[] valueCollection,
+ in MultiValue valueToStore,
int index,
int curBasicBlock)
{
- ValueBasicBlockPair newValue = new ValueBasicBlockPair { BasicBlockIndex = curBasicBlock };
+ MultiValue value;
- ValueBasicBlockPair existingValue = valueCollection[index];
- if (existingValue.Value != null
- && existingValue.BasicBlockIndex == curBasicBlock)
+ ValueBasicBlockPair? existingValue = valueCollection[index];
+ if (!existingValue.HasValue
+ || existingValue.Value.BasicBlockIndex == curBasicBlock)
{
// If the previous value was stored in the current basic block, then we can safely
// overwrite the previous value with the new one.
- newValue.Value = valueToStore;
+ value = valueToStore;
}
else
{
// If the previous value came from a previous basic block, then some other use of
// the local could see the previous value, so we must merge the new value with the
// old value.
- newValue.Value = MergePointValue.MergeValues(existingValue.Value, valueToStore);
+ value = MultiValueLattice.Meet(existingValue.Value.Value, valueToStore);
}
- valueCollection[index] = newValue;
+ valueCollection[index] = new ValueBasicBlockPair(value, curBasicBlock);
}
private static void StoreMethodLocalValue<KeyType>(
Dictionary<KeyType, ValueBasicBlockPair> valueCollection,
- ValueNode valueToStore,
+ in MultiValue valueToStore,
KeyType collectionKey,
int curBasicBlock,
int? maxTrackedValues = null)
+ where KeyType : notnull
{
- ValueBasicBlockPair newValue = new ValueBasicBlockPair { BasicBlockIndex = curBasicBlock };
-
- ValueBasicBlockPair existingValue;
- if (valueCollection.TryGetValue(collectionKey, out existingValue))
+ if (valueCollection.TryGetValue(collectionKey, out ValueBasicBlockPair existingValue))
{
+ MultiValue value;
+
if (existingValue.BasicBlockIndex == curBasicBlock)
{
// If the previous value was stored in the current basic block, then we can safely
// overwrite the previous value with the new one.
- newValue.Value = valueToStore;
+ value = valueToStore;
}
else
{
// If the previous value came from a previous basic block, then some other use of
// the local could see the previous value, so we must merge the new value with the
// old value.
- newValue.Value = MergePointValue.MergeValues(existingValue.Value, valueToStore);
+ value = MultiValueLattice.Meet(existingValue.Value, valueToStore);
}
- valueCollection[collectionKey] = newValue;
+ valueCollection[collectionKey] = new ValueBasicBlockPair(value, curBasicBlock);
}
else if (maxTrackedValues == null || valueCollection.Count < maxTrackedValues)
{
// We're not currently tracking a value a this index, so store the value now.
- newValue.Value = valueToStore;
- valueCollection[collectionKey] = newValue;
+ valueCollection[collectionKey] = new ValueBasicBlockPair(valueToStore, curBasicBlock);
}
}
@@ -252,16 +257,16 @@ namespace ILCompiler.Dataflow
{
MethodDesc thisMethod = methodBody.OwningMethod;
- ValueBasicBlockPair[] locals = new ValueBasicBlockPair[methodBody.GetLocals().Length];
+ ValueBasicBlockPair?[] locals = new ValueBasicBlockPair?[methodBody.GetLocals().Length];
Dictionary<int, Stack<StackSlot>> knownStacks = new Dictionary<int, Stack<StackSlot>>();
- Stack<StackSlot> currentStack = new Stack<StackSlot>(methodBody.MaxStack);
+ Stack<StackSlot>? currentStack = new Stack<StackSlot>(methodBody.MaxStack);
ScanExceptionInformation(knownStacks, methodBody);
BasicBlockIterator blockIterator = new BasicBlockIterator(methodBody);
- MethodReturnValue = null;
+ ReturnValue = new();
ILReader reader = new ILReader(methodBody.GetILBytes());
while (reader.HasNext)
{
@@ -509,7 +514,7 @@ namespace ILCompiler.Dataflow
{
StackSlot count = PopUnknown(currentStack, 1, methodBody, offset);
var arrayElement = (TypeDesc)methodBody.GetObject(reader.ReadILToken());
- currentStack.Push(new StackSlot(new ArrayValue(count.Value, arrayElement)));
+ currentStack.Push(new StackSlot(ArrayValue.Create(count.Value, arrayElement)));
}
break;
@@ -589,7 +594,8 @@ namespace ILCompiler.Dataflow
case ILOpcode.stloc_1:
case ILOpcode.stloc_2:
case ILOpcode.stloc_3:
- ScanStloc(methodBody, offset, opcode switch {
+ ScanStloc(methodBody, offset, opcode switch
+ {
ILOpcode.stloc => reader.ReadILUInt16(),
ILOpcode.stloc_s => reader.ReadILByte(),
_ => opcode - ILOpcode.stloc_0,
@@ -674,7 +680,7 @@ namespace ILCompiler.Dataflow
if (hasReturnValue)
{
StackSlot retValue = PopUnknown(currentStack, 1, methodBody, offset);
- MethodReturnValue = MergePointValue.MergeValues(MethodReturnValue, retValue.Value);
+ ReturnValue = MultiValueLattice.Meet(ReturnValue, retValue.Value);
}
ClearStack(ref currentStack);
break;
@@ -742,7 +748,7 @@ namespace ILCompiler.Dataflow
}
}
- protected abstract ValueNode GetMethodParameterValue(MethodDesc method, int parameterIndex);
+ protected abstract SingleValue GetMethodParameterValue(MethodDesc method, int parameterIndex);
private void ScanLdarg(ILOpcode opcode, int paramNum, Stack<StackSlot> currentStack, MethodDesc thisMethod)
{
@@ -771,7 +777,11 @@ namespace ILCompiler.Dataflow
)
{
var valueToStore = PopUnknown(currentStack, 1, methodBody, offset);
- HandleStoreParameter(methodBody, offset, index, valueToStore.Value);
+ var targetValue = GetMethodParameterValue(methodBody.OwningMethod, index);
+ if (targetValue is MethodParameterValue targetParameterValue)
+ HandleStoreParameter(methodBody, offset, targetParameterValue, valueToStore.Value);
+
+ // If the targetValue is MethodThisValue do nothing - it should never happen really, and if it does, there's nothing we can track there
}
private void ScanLdloc(
@@ -780,20 +790,19 @@ namespace ILCompiler.Dataflow
ILOpcode operation,
int index,
Stack<StackSlot> currentStack,
- ValueBasicBlockPair[] locals)
+ ValueBasicBlockPair?[] locals)
{
bool isByRef = operation == ILOpcode.ldloca || operation == ILOpcode.ldloca_s
|| methodBody.GetLocals()[index].Type.IsByRefOrPointer();
- ValueBasicBlockPair localValue = locals[index];
- if (localValue.Value != null)
+ ValueBasicBlockPair? localValue = locals[index];
+ if (!localValue.HasValue)
{
- ValueNode valueToPush = localValue.Value;
- currentStack.Push(new StackSlot(valueToPush, isByRef));
+ currentStack.Push(new StackSlot(UnknownValue.Instance, isByRef));
}
else
{
- currentStack.Push(new StackSlot(null, isByRef));
+ currentStack.Push(new StackSlot(localValue.Value.Value, isByRef));
}
}
@@ -808,8 +817,31 @@ namespace ILCompiler.Dataflow
}
else
{
- StackSlot slot = new StackSlot(new RuntimeTypeHandleValue(type));
- currentStack.Push(slot);
+ // Note that Nullable types without a generic argument (i.e. Nullable<>) will be RuntimeTypeHandleValue / SystemTypeValue
+ if (type.HasInstantiation && !type.IsGenericDefinition && type.IsTypeOf(ILLink.Shared.TypeSystemProxy.WellKnownType.System_Nullable_T))
+ {
+ switch (type.Instantiation[0])
+ {
+ case GenericParameterDesc genericParam:
+ var nullableDam = new RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers(new TypeProxy(type),
+ new RuntimeTypeHandleForGenericParameterValue(genericParam));
+ currentStack.Push(new StackSlot(nullableDam));
+ return;
+ case MetadataType underlyingType:
+ var nullableType = new RuntimeTypeHandleForNullableSystemTypeValue(new TypeProxy(type), new SystemTypeValue(underlyingType));
+ currentStack.Push(new StackSlot(nullableType));
+ return;
+ default:
+ PushUnknown(currentStack);
+ return;
+ }
+ }
+ else
+ {
+ var typeHandle = new RuntimeTypeHandleValue(new TypeProxy(type));
+ currentStack.Push(new StackSlot(typeHandle));
+ return;
+ }
}
}
else if (operand is MethodDesc method)
@@ -828,7 +860,7 @@ namespace ILCompiler.Dataflow
int offset,
int index,
Stack<StackSlot> currentStack,
- ValueBasicBlockPair[] locals,
+ ValueBasicBlockPair?[] locals,
int curBasicBlock)
{
StackSlot valueToStore = PopUnknown(currentStack, 1, methodBody, offset);
@@ -843,21 +875,21 @@ namespace ILCompiler.Dataflow
StackSlot valueToStore = PopUnknown(currentStack, 1, methodBody, offset);
StackSlot destination = PopUnknown(currentStack, 1, methodBody, offset);
- foreach (var uniqueDestination in destination.Value.UniqueValues())
+ foreach (var uniqueDestination in destination.Value)
{
- if (uniqueDestination.Kind == ValueNodeKind.LoadField)
+ if (uniqueDestination is FieldValue fieldDestination)
{
- HandleStoreField(methodBody, offset, ((LoadFieldValue)uniqueDestination).Field, valueToStore.Value);
+ HandleStoreField(methodBody, offset, fieldDestination, valueToStore.Value);
}
- else if (uniqueDestination.Kind == ValueNodeKind.MethodParameter)
+ else if (uniqueDestination is MethodParameterValue parameterDestination)
{
- HandleStoreParameter(methodBody, offset, ((MethodParameterValue)uniqueDestination).ParameterIndex, valueToStore.Value);
+ HandleStoreParameter(methodBody, offset, parameterDestination, valueToStore.Value);
}
}
}
- protected abstract ValueNode GetFieldValue(MethodIL method, FieldDesc field);
+ protected abstract MultiValue GetFieldValue(FieldDesc field);
private void ScanLdfld(
MethodIL methodBody,
@@ -872,15 +904,15 @@ namespace ILCompiler.Dataflow
bool isByRef = opcode == ILOpcode.ldflda || opcode == ILOpcode.ldsflda;
- StackSlot slot = new StackSlot(GetFieldValue(methodBody, field), isByRef);
+ StackSlot slot = new StackSlot(GetFieldValue(field), isByRef);
currentStack.Push(slot);
}
- protected virtual void HandleStoreField(MethodIL method, int offset, FieldDesc field, ValueNode valueToStore)
+ protected virtual void HandleStoreField(MethodIL method, int offset, FieldValue field, MultiValue valueToStore)
{
}
- protected virtual void HandleStoreParameter(MethodIL method, int offset, int index, ValueNode valueToStore)
+ protected virtual void HandleStoreParameter(MethodIL method, int offset, MethodParameterValue parameter, MultiValue valueToStore)
{
}
@@ -895,7 +927,15 @@ namespace ILCompiler.Dataflow
if (opcode == ILOpcode.stfld)
PopUnknown(currentStack, 1, methodBody, offset);
- HandleStoreField(methodBody, offset, field, valueToStoreSlot.Value);
+ foreach (var value in GetFieldValue(field))
+ {
+ // GetFieldValue may return different node types, in which case they can't be stored to.
+ // At least not yet.
+ if (value is not FieldValue fieldValue)
+ continue;
+
+ HandleStoreField(methodBody, offset, fieldValue, valueToStoreSlot.Value);
+ }
}
private ValueNodeList PopCallArguments(
@@ -903,7 +943,7 @@ namespace ILCompiler.Dataflow
MethodDesc methodCalled,
MethodIL containingMethodBody,
bool isNewObj, int ilOffset,
- out ValueNode newObjValue)
+ out SingleValue? newObjValue)
{
newObjValue = null;
@@ -938,11 +978,11 @@ namespace ILCompiler.Dataflow
{
bool isNewObj = opcode == ILOpcode.newobj;
- ValueNode newObjValue;
+ SingleValue? newObjValue;
ValueNodeList methodParams = PopCallArguments(currentStack, calledMethod, callingMethodBody, isNewObj,
offset, out newObjValue);
- ValueNode methodReturnValue;
+ MultiValue methodReturnValue;
bool handledFunction = HandleCall(
callingMethodBody,
calledMethod,
@@ -957,7 +997,7 @@ namespace ILCompiler.Dataflow
if (isNewObj)
{
if (newObjValue == null)
- PushUnknown(currentStack);
+ methodReturnValue = UnknownValue.Instance;
else
methodReturnValue = newObjValue;
}
@@ -970,14 +1010,17 @@ namespace ILCompiler.Dataflow
}
}
- if (methodReturnValue != null)
+ if (isNewObj || !calledMethod.Signature.ReturnType.IsVoid)
currentStack.Push(new StackSlot(methodReturnValue, calledMethod.Signature.ReturnType.IsByRefOrPointer()));
foreach (var param in methodParams)
{
- if (param is ArrayValue arr)
+ foreach (var v in param)
{
- MarkArrayValuesAsUnknown(arr, curBasicBlock);
+ if (v is ArrayValue arr)
+ {
+ MarkArrayValuesAsUnknown(arr, curBasicBlock);
+ }
}
}
}
@@ -988,7 +1031,7 @@ namespace ILCompiler.Dataflow
ILOpcode operation,
int offset,
ValueNodeList methodParams,
- out ValueNode methodReturnValue);
+ out MultiValue methodReturnValue);
// Limit tracking array values to 32 values for performance reasons. There are many arrays much longer than 32 elements in .NET, but the interesting ones for the linker are nearly always less than 32 elements.
private const int MaxTrackedArrayValues = 32;
@@ -1014,7 +1057,7 @@ namespace ILCompiler.Dataflow
StackSlot indexToStoreAt = PopUnknown(currentStack, 1, methodBody, offset);
StackSlot arrayToStoreIn = PopUnknown(currentStack, 1, methodBody, offset);
int? indexToStoreAtInt = indexToStoreAt.Value.AsConstInt();
- foreach (var array in arrayToStoreIn.Value.UniqueValues())
+ foreach (var array in arrayToStoreIn.Value)
{
if (array is ArrayValue arrValue)
{
@@ -1040,7 +1083,7 @@ namespace ILCompiler.Dataflow
{
StackSlot indexToLoadFrom = PopUnknown(currentStack, 1, methodBody, offset);
StackSlot arrayToLoadFrom = PopUnknown(currentStack, 1, methodBody, offset);
- if (arrayToLoadFrom.Value is not ArrayValue arr)
+ if (arrayToLoadFrom.Value.AsSingleValue() is not ArrayValue arr)
{
PushUnknown(currentStack);
return;
@@ -1058,17 +1101,13 @@ namespace ILCompiler.Dataflow
return;
}
-
- ValueBasicBlockPair arrayIndexValue;
- arr.IndexValues.TryGetValue(index.Value, out arrayIndexValue);
- if (arrayIndexValue.Value != null)
+ if (arr.IndexValues.TryGetValue(index.Value, out ValueBasicBlockPair arrayIndexValue))
{
- ValueNode valueToPush = arrayIndexValue.Value;
- currentStack.Push(new StackSlot(valueToPush, isByRef));
+ currentStack.Push(new StackSlot(arrayIndexValue.Value, isByRef));
}
else
{
- currentStack.Push(new StackSlot(null, isByRef));
+ PushUnknown(currentStack);
}
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodParameterValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodParameterValue.cs
new file mode 100644
index 00000000000..b8e5e728030
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodParameterValue.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.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILCompiler.Dataflow;
+using ILLink.Shared.DataFlow;
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+
+ /// <summary>
+ /// A value that came from a method parameter - such as the result of a ldarg.
+ /// </summary>
+ partial record MethodParameterValue : IValueWithStaticType
+ {
+ public MethodParameterValue(MethodDesc method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ StaticType = method.Signature[parameterIndex];
+ Method = method;
+ ParameterIndex = parameterIndex;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly MethodDesc Method;
+
+ /// <summary>
+ /// This is the index of non-implicit parameter - so the index into MethodDesc.Signature array.
+ /// It's NOT the IL parameter index which could be offset by 1 if the method has an implicit this.
+ /// </summary>
+ public readonly int ParameterIndex;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch()
+ => new string[] { DiagnosticUtilities.GetParameterNameForErrorMessage(Method, ParameterIndex), DiagnosticUtilities.GetMethodSignatureDisplayName(Method) };
+
+ public TypeDesc? StaticType { get; }
+
+ public override SingleValue DeepCopy() => this; // This value is immutable
+
+ public override string ToString() => this.ValueToString(Method, ParameterIndex, DynamicallyAccessedMemberTypes);
+
+ internal ParameterOrigin ParameterOrigin
+ {
+ get
+ {
+ int index = ParameterIndex;
+ if (!Method.Signature.IsStatic)
+ index++;
+
+ return new ParameterOrigin(Method, index);
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodProxy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodProxy.cs
new file mode 100644
index 00000000000..ed866e82d32
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodProxy.cs
@@ -0,0 +1,65 @@
+// 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.Immutable;
+using ILCompiler;
+using ILCompiler.Dataflow;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ readonly partial struct MethodProxy
+ {
+ public MethodProxy(MethodDesc method) => Method = method;
+
+ public static implicit operator MethodProxy(MethodDesc method) => new(method);
+
+ public readonly MethodDesc Method;
+
+ public string Name { get => Method.Name; }
+
+ public string GetDisplayName() => Method.GetDisplayName();
+
+ internal partial bool IsDeclaredOnType(string fullTypeName) => Method.IsDeclaredOnType(fullTypeName);
+
+ internal partial bool HasParameters() => Method.Signature.Length > 0;
+
+ internal partial int GetParametersCount() => Method.Signature.Length;
+
+ internal partial bool HasParameterOfType(int parameterIndex, string fullTypeName) => Method.HasParameterOfType(parameterIndex, fullTypeName);
+
+ internal partial string GetParameterDisplayName(int parameterIndex) =>
+ (Method is EcmaMethod ecmaMethod)
+ ? ecmaMethod.GetParameterDisplayName(parameterIndex)
+ : $"#{parameterIndex}";
+
+ internal partial bool HasGenericParameters() => Method.HasInstantiation;
+
+ internal partial bool HasGenericParametersCount(int genericParameterCount) => Method.Instantiation.Length == genericParameterCount;
+
+ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters()
+ {
+ var methodDef = Method.GetMethodDefinition();
+
+ if (!methodDef.HasInstantiation)
+ return ImmutableArray<GenericParameterProxy>.Empty;
+
+ var builder = ImmutableArray.CreateBuilder<GenericParameterProxy>(methodDef.Instantiation.Length);
+ foreach (var genericParameter in methodDef.Instantiation)
+ {
+ builder.Add(new GenericParameterProxy((GenericParameterDesc)genericParameter));
+ }
+
+ return builder.ToImmutableArray();
+ }
+
+ internal partial bool IsStatic() => Method.Signature.IsStatic;
+
+ internal partial bool ReturnsVoid() => Method.Signature.ReturnType.IsVoid;
+
+ public override string ToString() => Method.ToString();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs
new file mode 100644
index 00000000000..552e971a059
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs
@@ -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.
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILCompiler.Dataflow;
+using ILLink.Shared.DataFlow;
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// Return value from a method
+ /// </summary>
+ partial record MethodReturnValue : IValueWithStaticType
+ {
+ public MethodReturnValue(MethodDesc method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ StaticType = method.Signature.ReturnType;
+ Method = method;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly MethodDesc Method;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch()
+ => new string[] { DiagnosticUtilities.GetMethodSignatureDisplayName(Method) };
+
+ public TypeDesc? StaticType { get; }
+
+ public override SingleValue DeepCopy() => this; // This value is immutable
+
+ public override string ToString() => this.ValueToString(Method, DynamicallyAccessedMemberTypes);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodThisParameterValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodThisParameterValue.cs
new file mode 100644
index 00000000000..b04698e26d0
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodThisParameterValue.cs
@@ -0,0 +1,40 @@
+// 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;
+using ILCompiler;
+using ILCompiler.Dataflow;
+using ILLink.Shared.DataFlow;
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+
+ /// <summary>
+ /// A value that came from the implicit this parameter of a method
+ /// </summary>
+ partial record MethodThisParameterValue : IValueWithStaticType
+ {
+ public MethodThisParameterValue(MethodDesc method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ Method = method;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly MethodDesc Method;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch()
+ => new string[] { Method.GetDisplayName() };
+
+ public TypeDesc? StaticType => Method.OwningType;
+
+ public override SingleValue DeepCopy() => this; // This value is immutable
+
+ public override string ToString() => this.ValueToString(Method, DynamicallyAccessedMemberTypes);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ArrayValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ArrayValue.cs
new file mode 100644
index 00000000000..71934bc28ca
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ArrayValue.cs
@@ -0,0 +1,121 @@
+// 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.Text;
+using ILLink.Shared.DataFlow;
+using Mono.Cecil;
+using Mono.Linker.Dataflow;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ partial record ArrayValue
+ {
+ public static MultiValue Create (MultiValue size, TypeReference elementType)
+ {
+ MultiValue result = MultiValueLattice.Top;
+ foreach (var sizeValue in size) {
+ result = MultiValueLattice.Meet (result, new MultiValue (new ArrayValue (sizeValue, elementType)));
+ }
+
+ return result;
+ }
+
+ public static MultiValue Create (int size, TypeReference elementType)
+ {
+ return new MultiValue (new ArrayValue (new ConstIntValue (size), elementType));
+ }
+
+ /// <summary>
+ /// Constructs an array value of the given size
+ /// </summary>
+ ArrayValue (SingleValue size, TypeReference elementType)
+ {
+ Size = size;
+ ElementType = elementType;
+ IndexValues = new Dictionary<int, ValueBasicBlockPair> ();
+ }
+
+ public TypeReference ElementType { get; }
+ public Dictionary<int, ValueBasicBlockPair> IndexValues { get; }
+
+ public partial bool TryGetValueByIndex (int index, out MultiValue value)
+ {
+ if (IndexValues.TryGetValue (index, out var valuePair)) {
+ value = valuePair.Value;
+ return true;
+ }
+
+ value = default;
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ return HashCode.Combine (GetType ().GetHashCode (), Size);
+ }
+
+ public bool Equals (ArrayValue? otherArr)
+ {
+ if (otherArr == null)
+ return false;
+
+ bool equals = Size.Equals (otherArr.Size);
+ equals &= IndexValues.Count == otherArr.IndexValues.Count;
+ if (!equals)
+ return false;
+
+ // If both sets T and O are the same size and "T intersect O" is empty, then T == O.
+ HashSet<KeyValuePair<int, ValueBasicBlockPair>> thisValueSet = new (IndexValues);
+ HashSet<KeyValuePair<int, ValueBasicBlockPair>> otherValueSet = new (otherArr.IndexValues);
+ thisValueSet.ExceptWith (otherValueSet);
+ return thisValueSet.Count == 0;
+ }
+
+ public override SingleValue DeepCopy ()
+ {
+ var newValue = new ArrayValue (Size.DeepCopy (), ElementType);
+ foreach (var kvp in IndexValues) {
+ newValue.IndexValues.Add (kvp.Key, new ValueBasicBlockPair (kvp.Value.Value.Clone (), kvp.Value.BasicBlockIndex));
+ }
+
+ return newValue;
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder result = new ();
+ result.Append ("Array Size:");
+ result.Append (this.ValueToString (Size));
+
+ result.Append (", Values:(");
+ bool first = true;
+ foreach (var element in IndexValues) {
+ if (!first) {
+ result.Append (",");
+ first = false;
+ }
+
+ result.Append ("(");
+ result.Append (element.Key);
+ result.Append (",(");
+ bool firstValue = true;
+ foreach (var v in element.Value.Value) {
+ if (firstValue) {
+ result.Append (",");
+ firstValue = false;
+ }
+
+ result.Append (v.ToString ());
+ }
+ result.Append ("))");
+ }
+ result.Append (')');
+
+ return result.ToString ();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticContext.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticContext.cs
new file mode 100644
index 00000000000..df43246bbb8
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticContext.cs
@@ -0,0 +1,23 @@
+// 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 Mono.Linker;
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ readonly partial struct DiagnosticContext
+ {
+ public readonly MessageOrigin Origin;
+ public readonly bool DiagnosticsEnabled;
+ readonly LinkContext _context;
+
+ public DiagnosticContext (in MessageOrigin origin, bool diagnosticsEnabled, LinkContext context)
+ => (Origin, DiagnosticsEnabled, _context) = (origin, diagnosticsEnabled, context);
+
+ public partial void AddDiagnostic (DiagnosticId id, params string[] args)
+ {
+ if (DiagnosticsEnabled)
+ _context.LogWarning (Origin, id, args);
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticUtilities.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticUtilities.cs
index 9aef3fde6d2..e354b683e04 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticUtilities.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DiagnosticUtilities.cs
@@ -1,5 +1,5 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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 Mono.Cecil;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersBinder.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersBinder.cs
index b44dd1cd1cd..26b67b55310 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersBinder.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersBinder.cs
@@ -1,21 +1,15 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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 System.Reflection;
+using ILLink.Shared;
using Mono.Cecil;
namespace Mono.Linker
{
- // Temporary workaround - should be removed once linker can be upgraded to build against
- // high enough version of the framework which has this enum value.
- internal static class DynamicallyAccessedMemberTypesOverlay
- {
- public const DynamicallyAccessedMemberTypes Interfaces = (DynamicallyAccessedMemberTypes) 0x2000;
- }
-
internal static class DynamicallyAccessedMembersBinder
{
// Returns the members of the type bound by memberTypes. For DynamicallyAccessedMemberTypes.All, this returns all members of the type and its
@@ -427,4 +421,4 @@ namespace Mono.Linker
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersTypeHierarchy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersTypeHierarchy.cs
new file mode 100644
index 00000000000..56e9496e84e
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/DynamicallyAccessedMembersTypeHierarchy.cs
@@ -0,0 +1,265 @@
+// 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.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared;
+using Mono.Cecil;
+using Mono.Linker.Steps;
+
+namespace Mono.Linker.Dataflow
+{
+ class DynamicallyAccessedMembersTypeHierarchy
+ {
+ readonly LinkContext _context;
+ readonly MarkStep _markStep;
+
+ // Cache of DynamicallyAccessedMembers annotations applied to types and their hierarchies
+ // Values
+ // annotation - the aggregated annotation value from the entire base and interface hierarchy of the given type
+ // If the type has a base class with annotation a1 and an interface with annotation a2, the stored
+ // annotation is a1 | a2.
+ // applied - set to true once the annotation was applied to the type
+ // This only happens once the right reflection pattern is found.
+ // If a new type is being marked and one of its base types/interface has the applied set to true
+ // the new type will apply its annotation and will also set its applied to true.
+ // Non-interface types
+ // - Only marked types with non-empty annotation are put into the cache
+ // - Non-marked types are not stored in the cache
+ // - Marked types which are not in the cache don't have any annotation
+ // Interface types
+ // - All interface types accessible from marked types are stored in the cache
+ // - If the interface type doesn't have annotation the value None is stored here
+ //
+ // It's not possible to use the marking as a filter for interfaces in the cache
+ // because interfaces are marked late and in effectively random order.
+ // For this cache to be effective we need to be able to fill it for all base types and interfaces
+ // of a type which is currently being marked - at which point the interfaces are not yet marked.
+ readonly Dictionary<TypeDefinition, (DynamicallyAccessedMemberTypes annotation, bool applied)> _typesInDynamicallyAccessedMembersHierarchy;
+
+ public DynamicallyAccessedMembersTypeHierarchy (LinkContext context, MarkStep markStep)
+ {
+ _context = context;
+ _markStep = markStep;
+ _typesInDynamicallyAccessedMembersHierarchy = new Dictionary<TypeDefinition, (DynamicallyAccessedMemberTypes, bool)> ();
+ }
+
+ public (DynamicallyAccessedMemberTypes annotation, bool applied) ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (TypeDefinition type)
+ {
+ // We'll use the cache also as a way to detect and avoid recursion for interfaces and annotated base types
+ if (_typesInDynamicallyAccessedMembersHierarchy.TryGetValue (type, out var existingValue))
+ return existingValue;
+
+ DynamicallyAccessedMemberTypes annotation = _context.Annotations.FlowAnnotations.GetTypeAnnotation (type);
+ bool apply = false;
+
+ if (type.IsInterface)
+ _typesInDynamicallyAccessedMembersHierarchy.Add (type, (annotation, false));
+
+ TypeDefinition? baseType = _context.TryResolve (type.BaseType);
+ if (baseType != null) {
+ var baseValue = ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (baseType);
+ annotation |= baseValue.annotation;
+ apply |= baseValue.applied;
+ }
+
+ // For the purposes of the DynamicallyAccessedMembers type hierarchies
+ // we consider interfaces of marked types to be also "marked" in that
+ // their annotations will be applied to the type regardless if later on
+ // we decide to remove the interface. This is to keep the complexity of the implementation
+ // relatively low. In the future it could be possibly optimized.
+ if (type.HasInterfaces) {
+ foreach (InterfaceImplementation iface in type.Interfaces) {
+ var interfaceType = _context.TryResolve (iface.InterfaceType);
+ if (interfaceType != null) {
+ var interfaceValue = ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (interfaceType);
+ annotation |= interfaceValue.annotation;
+ apply |= interfaceValue.applied;
+ }
+ }
+ }
+
+ Debug.Assert (!apply || annotation != DynamicallyAccessedMemberTypes.None);
+
+ // If OptimizeTypeHierarchyAnnotations is disabled, we will apply the annotations without seeing object.GetType()
+ bool applyOptimizeTypeHierarchyAnnotations = (annotation != DynamicallyAccessedMemberTypes.None) && !_context.IsOptimizationEnabled (CodeOptimizations.OptimizeTypeHierarchyAnnotations, type);
+ // Unfortunately, we cannot apply the annotation to type derived from EventSource - Revisit after https://github.com/dotnet/runtime/issues/54859
+ // Breaking the logic to make it easier to maintain in the future since the logic is convoluted
+ // DisableEventSourceSpecialHandling is closely tied to a type derived from EventSource and should always go together
+ // However, logically it should be possible to use DisableEventSourceSpecialHandling to allow marking types derived from EventSource when OptimizeTypeHierarchyAnnotations is disabled
+ apply |= applyOptimizeTypeHierarchyAnnotations && (_context.DisableEventSourceSpecialHandling || !BCL.EventTracingForWindows.IsEventSourceImplementation (type, _context));
+
+ // Store the results in the cache
+ // Don't store empty annotations for non-interface types - we can use the presence of the row
+ // in the cache as indication of it instead.
+ // This doesn't work for interfaces, since we can't rely on them being marked (and thus have the cache
+ // already filled), so we need to always store the row (even if empty) for interfaces.
+ if (annotation != DynamicallyAccessedMemberTypes.None || type.IsInterface) {
+ _typesInDynamicallyAccessedMembersHierarchy[type] = (annotation, apply);
+ }
+
+ // It's important to first store the annotation in the cache and only then apply the annotation.
+ // Applying the annotation will lead to marking additional types which in turn calls back into this
+ // method to look for annotations. If the newly marked type derives from the one we're processing
+ // it will rely on the cache to know if it's annotated - so the record must be in the cache
+ // before it happens.
+ if (apply) {
+ // One of the base/interface types is already marked as having the annotation applied
+ // so we need to apply the annotation to this type as well
+ var origin = new MessageOrigin (type);
+ var reflectionMarker = new ReflectionMarker (_context, _markStep);
+ // Report warnings on access to annotated members, with the annotated type as the origin.
+ ApplyDynamicallyAccessedMembersToType (reflectionMarker, origin, type, annotation);
+ }
+
+ return (annotation, apply);
+ }
+
+ public DynamicallyAccessedMemberTypes ApplyDynamicallyAccessedMembersToTypeHierarchy (
+ ReflectionMarker reflectionMarker,
+ TypeDefinition type)
+ {
+ (var annotation, var applied) = ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (type);
+
+ // If the annotation was already applied to this type, there's no reason to repeat the operation, the result will
+ // be no change.
+ if (applied || annotation == DynamicallyAccessedMemberTypes.None)
+ return annotation;
+
+ // Apply the effective annotation for the type
+ var origin = new MessageOrigin (type);
+ // Report warnings on access to annotated members, with the annotated type as the origin.
+ ApplyDynamicallyAccessedMembersToType (reflectionMarker, origin, type, annotation);
+
+ // Mark it as applied in the cache
+ _typesInDynamicallyAccessedMembersHierarchy[type] = (annotation, true);
+
+ // Propagate the newly applied annotation to all derived/implementation types
+ // Since we don't have a data structure which would allow us to enumerate all derived/implementation types
+ // walk all of the types in the cache. These are good candidates as types not in the cache don't apply.
+ //
+ // Applying annotations can lead to marking additional types which can lead to adding new records
+ // to the cache. So we can't simply iterate over the cache. We also can't rely on the auto-applying annotations
+ // which is triggered from marking via ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy as that will
+ // only reliably work once the annotations are applied to all types in the cache first. Partially
+ // applied annotations to the cache are not enough. So we have to apply the annotations to any types
+ // added to the cache during the application as well.
+ //
+ HashSet<TypeDefinition> typesProcessed = new HashSet<TypeDefinition> ();
+ List<TypeDefinition> candidateTypes = new List<TypeDefinition> ();
+ while (true) {
+ candidateTypes.Clear ();
+ foreach (var candidate in _typesInDynamicallyAccessedMembersHierarchy) {
+ if (candidate.Value.annotation == DynamicallyAccessedMemberTypes.None || candidate.Value.applied)
+ continue;
+
+ if (typesProcessed.Add (candidate.Key))
+ candidateTypes.Add (candidate.Key);
+ }
+
+ if (candidateTypes.Count == 0)
+ break;
+
+ foreach (var candidateType in candidateTypes) {
+ ApplyDynamicallyAccessedMembersToTypeHierarchyInner (reflectionMarker, candidateType);
+ }
+ }
+
+ return annotation;
+ }
+
+ bool ApplyDynamicallyAccessedMembersToTypeHierarchyInner (
+ in ReflectionMarker reflectionMarker,
+ TypeDefinition type)
+ {
+ (var annotation, var applied) = GetCachedInfoForTypeInHierarchy (type);
+
+ if (annotation == DynamicallyAccessedMemberTypes.None)
+ return false;
+
+ if (applied)
+ return true;
+
+ TypeDefinition? baseType = _context.TryResolve (type.BaseType);
+ if (baseType != null)
+ applied = ApplyDynamicallyAccessedMembersToTypeHierarchyInner (reflectionMarker, baseType);
+
+ if (!applied && type.HasInterfaces) {
+ foreach (InterfaceImplementation iface in type.Interfaces) {
+ var interfaceType = _context.TryResolve (iface.InterfaceType);
+ if (interfaceType != null) {
+ if (ApplyDynamicallyAccessedMembersToTypeHierarchyInner (reflectionMarker, interfaceType)) {
+ applied = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (applied) {
+ var origin = new MessageOrigin (type);
+ // Report warnings on access to annotated members, with the annotated type as the origin.
+ ApplyDynamicallyAccessedMembersToType (reflectionMarker, origin, type, annotation);
+ _typesInDynamicallyAccessedMembersHierarchy[type] = (annotation, true);
+ }
+
+ return applied;
+ }
+
+ void ApplyDynamicallyAccessedMembersToType (in ReflectionMarker reflectionMarker, in MessageOrigin origin, TypeDefinition type, DynamicallyAccessedMemberTypes annotation)
+ {
+ Debug.Assert (annotation != DynamicallyAccessedMemberTypes.None);
+
+ // We need to apply annotations to this type, and its base/interface types (recursively)
+ // But the annotations on base/interfaces are already applied so we don't need to apply those
+ // again (and should avoid doing so as it would produce extra warnings).
+ var baseType = _context.TryResolve (type.BaseType);
+ if (baseType != null) {
+ var baseAnnotation = GetCachedInfoForTypeInHierarchy (baseType);
+ var annotationToApplyToBase = Annotations.GetMissingMemberTypes (annotation, baseAnnotation.annotation);
+
+ // Apply any annotations that didn't exist on the base type to the base type.
+ // This may produce redundant warnings when the annotation is DAMT.All or DAMT.PublicConstructors and the base already has a
+ // subset of those annotations.
+ reflectionMarker.MarkTypeForDynamicallyAccessedMembers (origin, baseType, annotationToApplyToBase, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: false);
+ }
+
+ // Most of the DynamicallyAccessedMemberTypes don't select members on interfaces. We only need to apply
+ // annotations to interfaces separately if dealing with DAMT.All or DAMT.Interfaces.
+ if (annotation.HasFlag (DynamicallyAccessedMemberTypesOverlay.Interfaces) && type.HasInterfaces) {
+ var annotationToApplyToInterfaces = annotation == DynamicallyAccessedMemberTypes.All ? annotation : DynamicallyAccessedMemberTypesOverlay.Interfaces;
+ foreach (var iface in type.Interfaces) {
+ var interfaceType = _context.TryResolve (iface.InterfaceType);
+ if (interfaceType == null)
+ continue;
+
+ var interfaceAnnotation = GetCachedInfoForTypeInHierarchy (interfaceType);
+ if (interfaceAnnotation.annotation.HasFlag (annotationToApplyToInterfaces))
+ continue;
+
+ // Apply All or Interfaces to the interface type.
+ // DAMT.All may produce redundant warnings from implementing types, when the interface type already had some annotations.
+ reflectionMarker.MarkTypeForDynamicallyAccessedMembers (origin, interfaceType, annotationToApplyToInterfaces, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: false);
+ }
+ }
+
+ // The annotations this type inherited from its base types or interfaces should not produce
+ // warnings on the respective base/interface members, since those are already covered by applying
+ // the annotations to those types. So we only need to handle the members directly declared on this type.
+ reflectionMarker.MarkTypeForDynamicallyAccessedMembers (origin, type, annotation, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: true);
+ }
+
+ (DynamicallyAccessedMemberTypes annotation, bool applied) GetCachedInfoForTypeInHierarchy (TypeDefinition type)
+ {
+ // The type should be in our cache already
+ if (!_typesInDynamicallyAccessedMembersHierarchy.TryGetValue (type, out var existingValue)) {
+ // If it's not in the cache it should be a non-interface type in which case it means there were no annotations
+ Debug.Assert (!type.IsInterface);
+ return (DynamicallyAccessedMemberTypes.None, false);
+ }
+
+ return existingValue;
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FieldValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FieldValue.cs
new file mode 100644
index 00000000000..6d20f8301c7
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FieldValue.cs
@@ -0,0 +1,41 @@
+// 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.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.DataFlow;
+using Mono.Linker;
+using Mono.Linker.Dataflow;
+using FieldDefinition = Mono.Cecil.FieldDefinition;
+using TypeDefinition = Mono.Cecil.TypeDefinition;
+
+
+namespace ILLink.Shared.TrimAnalysis
+{
+
+ /// <summary>
+ /// A representation of a field. Typically a result of ldfld.
+ /// </summary>
+ sealed partial record FieldValue : IValueWithStaticType
+ {
+ public FieldValue (TypeDefinition? staticType, FieldDefinition fieldToLoad, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ StaticType = staticType;
+ Field = fieldToLoad;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly FieldDefinition Field;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => new string[] { Field.GetDisplayName () };
+
+ public TypeDefinition? StaticType { get; }
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (Field, DynamicallyAccessedMemberTypes);
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FlowAnnotations.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FlowAnnotations.cs
index 4f4a50dae20..aea413b2c7c 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FlowAnnotations.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/FlowAnnotations.cs
@@ -1,16 +1,19 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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;
using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Cecil.Cil;
+using Mono.Linker;
+using Mono.Linker.Dataflow;
-namespace Mono.Linker.Dataflow
+namespace ILLink.Shared.TrimAnalysis
{
- class FlowAnnotations
+ partial class FlowAnnotations
{
readonly LinkContext _context;
readonly Dictionary<TypeDefinition, TypeAnnotations> _annotations = new Dictionary<TypeDefinition, TypeAnnotations> ();
@@ -169,9 +172,7 @@ namespace Mono.Linker.Dataflow
if (attribute.ConstructorArguments.Count == 1)
return (DynamicallyAccessedMemberTypes) (int) attribute.ConstructorArguments[0].Value;
else
- _context.LogWarning (
- $"Attribute 'System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute' doesn't have the required number of parameters specified.",
- 2028, member);
+ _context.LogWarning (member, DiagnosticId.AttributeDoesntHaveTheRequiredNumberOfParameters, "System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute");
}
return DynamicallyAccessedMemberTypes.None;
}
@@ -193,9 +194,7 @@ namespace Mono.Linker.Dataflow
if (!IsTypeInterestingForDataflow (field.FieldType)) {
// Already know that there's a non-empty annotation on a field which is not System.Type/String and we're about to ignore it
- _context.LogWarning (
- $"Field '{field.GetDisplayName ()}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to fields of type 'System.Type' or 'System.String'.",
- 2097, field, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (field, DiagnosticId.DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings, field.GetDisplayName ());
continue;
}
@@ -227,16 +226,12 @@ namespace Mono.Linker.Dataflow
paramAnnotations[0] = methodMemberTypes;
}
} else if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) {
- _context.LogWarning (
- $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.",
- 2041, method, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods);
}
} else {
offset = 0;
if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) {
- _context.LogWarning (
- $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.",
- 2041, method, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods);
}
}
@@ -247,9 +242,8 @@ namespace Mono.Linker.Dataflow
continue;
if (!IsTypeInterestingForDataflow (methodParameter.ParameterType)) {
- _context.LogWarning (
- $"Parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (methodParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodParameter.Method)}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to parameters of type 'System.Type' or 'System.String'.",
- 2098, method, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings,
+ DiagnosticUtilities.GetParameterNameForErrorMessage (methodParameter), DiagnosticUtilities.GetMethodSignatureDisplayName (methodParameter.Method));
continue;
}
@@ -261,9 +255,7 @@ namespace Mono.Linker.Dataflow
DynamicallyAccessedMemberTypes returnAnnotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (method, providerIfNotMember: method.MethodReturnType);
if (returnAnnotation != DynamicallyAccessedMemberTypes.None && !IsTypeInterestingForDataflow (method.ReturnType)) {
- _context.LogWarning (
- $"Return type of method '{method.GetDisplayName ()}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'.",
- 2106, method, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings, method.GetDisplayName ());
}
DynamicallyAccessedMemberTypes[]? genericParameterAnnotations = null;
@@ -306,9 +298,7 @@ namespace Mono.Linker.Dataflow
continue;
if (!IsTypeInterestingForDataflow (property.PropertyType)) {
- _context.LogWarning (
- $"Property '{property.GetDisplayName ()}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'.",
- 2099, property, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (property, DiagnosticId.DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings, property.GetDisplayName ());
continue;
}
@@ -328,9 +318,7 @@ namespace Mono.Linker.Dataflow
}
if (annotatedMethods.Any (a => a.Method == setMethod)) {
- _context.LogWarning (
- $"'DynamicallyAccessedMembersAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its accessor '{setMethod.GetDisplayName ()}'.",
- 2043, setMethod, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (setMethod, DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor, property.GetDisplayName (), setMethod.GetDisplayName ());
} else {
int offset = setMethod.HasImplicitThis () ? 1 : 0;
if (setMethod.Parameters.Count > 0) {
@@ -357,9 +345,7 @@ namespace Mono.Linker.Dataflow
}
if (annotatedMethods.Any (a => a.Method == getMethod)) {
- _context.LogWarning (
- $"'DynamicallyAccessedMembersAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its accessor '{getMethod.GetDisplayName ()}'.",
- 2043, getMethod, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (getMethod, DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor, property.GetDisplayName (), getMethod.GetDisplayName ());
} else {
annotatedMethods.Add (new MethodAnnotations (getMethod, null, annotation, null));
}
@@ -368,9 +354,7 @@ namespace Mono.Linker.Dataflow
FieldDefinition? backingField;
if (backingFieldFromGetter != null && backingFieldFromSetter != null &&
backingFieldFromGetter != backingFieldFromSetter) {
- _context.LogWarning (
- $"Could not find a unique backing field for property '{property.GetDisplayName ()}' to propagate 'DynamicallyAccessedMembersAttribute'.",
- 2042, property, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (property, DiagnosticId.DynamicallyAccessedMembersCouldNotFindBackingField, property.GetDisplayName ());
backingField = null;
} else {
backingField = backingFieldFromGetter ?? backingFieldFromSetter;
@@ -378,9 +362,7 @@ namespace Mono.Linker.Dataflow
if (backingField != null) {
if (annotatedFields.Any (a => a.Field == backingField)) {
- _context.LogWarning (
- $"'DynamicallyAccessedMemberAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its backing field '{backingField.GetDisplayName ()}'.",
- 2056, backingField, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (backingField, DiagnosticId.DynamicallyAccessedMembersOnPropertyConflictsWithBackingField, property.GetDisplayName (), backingField.GetDisplayName ());
} else {
annotatedFields.Add (new FieldAnnotation (backingField, annotation));
}
@@ -548,34 +530,24 @@ namespace Mono.Linker.Dataflow
switch (provider) {
case ParameterDefinition parameterDefinition:
var baseParameterDefinition = (ParameterDefinition) baseProvider;
- _context.LogWarning (
- $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (parameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (parameterDefinition.Method)}' " +
- $"don't match overridden parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (baseParameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (baseParameterDefinition.Method)}'. " +
- $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
- 2092, origin, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (origin, DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides,
+ DiagnosticUtilities.GetParameterNameForErrorMessage (parameterDefinition), DiagnosticUtilities.GetMethodSignatureDisplayName (parameterDefinition.Method),
+ DiagnosticUtilities.GetParameterNameForErrorMessage (baseParameterDefinition), DiagnosticUtilities.GetMethodSignatureDisplayName (baseParameterDefinition.Method));
break;
case MethodReturnType methodReturnType:
- _context.LogWarning (
- $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodReturnType.Method)}' " +
- $"don't match overridden return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (((MethodReturnType) baseProvider).Method)}'. " +
- $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
- 2093, origin, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (origin, DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides,
+ DiagnosticUtilities.GetMethodSignatureDisplayName (methodReturnType.Method), DiagnosticUtilities.GetMethodSignatureDisplayName (((MethodReturnType) baseProvider).Method));
break;
// No fields - it's not possible to have a virtual field and override it
case MethodDefinition methodDefinition:
- _context.LogWarning (
- $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodDefinition)}' " +
- $"don't match overridden implicit 'this' parameter of method '{DiagnosticUtilities.GetMethodSignatureDisplayName ((MethodDefinition) baseProvider)}'. " +
- $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
- 2094, origin, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (origin, DiagnosticId.DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides,
+ DiagnosticUtilities.GetMethodSignatureDisplayName (methodDefinition), DiagnosticUtilities.GetMethodSignatureDisplayName ((MethodDefinition) baseProvider));
break;
case GenericParameter genericParameterOverride:
var genericParameterBase = (GenericParameter) baseProvider;
- _context.LogWarning (
- $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the generic parameter '{genericParameterOverride.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterOverride)}' " +
- $"don't match overridden generic parameter '{genericParameterBase.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterBase)}'. " +
- $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
- 2095, origin, subcategory: MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (origin, DiagnosticId.DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides,
+ genericParameterOverride.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterOverride),
+ genericParameterBase.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterBase));
break;
default:
throw new NotImplementedException ($"Unsupported provider type '{provider.GetType ()}'.");
@@ -696,5 +668,31 @@ namespace Mono.Linker.Dataflow
public FieldAnnotation (FieldDefinition field, DynamicallyAccessedMemberTypes annotation)
=> (Field, Annotation) = (field, annotation);
}
+
+ 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)
+ => GetMethodReturnValue (method, GetReturnParameterAnnotation (method.Method));
+
+ internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter)
+ => new GenericParameterValue (genericParameter.GenericParameter, GetGenericParameterAnnotation (genericParameter.GenericParameter));
+
+#pragma warning disable CA1822 // Mark members as static - keep this an instance method for consistency with the others
+ internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new MethodThisParameterValue (method.Method, dynamicallyAccessedMemberTypes);
+#pragma warning restore CA1822
+
+ internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method)
+ => GetMethodThisParameterValue (method, GetParameterAnnotation (method.Method, 0));
+
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new (method.Method.Parameters[parameterIndex].ParameterType.ResolveToTypeDefinition (_context), method.Method, parameterIndex, dynamicallyAccessedMemberTypes);
+
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex)
+ => GetMethodParameterValue (method, parameterIndex, GetParameterAnnotation (method.Method, parameterIndex + (method.IsStatic () ? 0 : 1)));
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterProxy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterProxy.cs
new file mode 100644
index 00000000000..1c92df4559c
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterProxy.cs
@@ -0,0 +1,20 @@
+// 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 Mono.Cecil;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal readonly partial struct GenericParameterProxy
+ {
+ public GenericParameterProxy (GenericParameter genericParameter) => GenericParameter = genericParameter;
+
+ public static implicit operator GenericParameterProxy (GenericParameter genericParameter) => new (genericParameter);
+
+ internal partial bool HasDefaultConstructorConstraint () => GenericParameter.HasDefaultConstructorConstraint;
+
+ public readonly GenericParameter GenericParameter;
+
+ public override string ToString () => GenericParameter.ToString ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterValue.cs
new file mode 100644
index 00000000000..8f1d6069ea3
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterValue.cs
@@ -0,0 +1,33 @@
+// 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.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.DataFlow;
+using Mono.Linker.Dataflow;
+using GenericParameter = Mono.Cecil.GenericParameter;
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is a System.Type value which represents generic parameter (basically result of typeof(T))
+ /// Its actual type is unknown, but it can have annotations.
+ /// </summary>
+ partial record GenericParameterValue
+ {
+ public GenericParameterValue (GenericParameter genericParameter, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ GenericParameter = new (genericParameter);
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => new string[] { GenericParameter.GenericParameter.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (GenericParameter.GenericParameter) };
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (GenericParameter, DynamicallyAccessedMemberTypes);
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/HandleCallAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/HandleCallAction.cs
new file mode 100644
index 00000000000..3d402cef977
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/HandleCallAction.cs
@@ -0,0 +1,133 @@
+// 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.Collections.Generic;
+using System.Reflection;
+using ILLink.Shared.TypeSystemProxy;
+using Mono.Cecil;
+using Mono.Linker;
+using Mono.Linker.Dataflow;
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ partial struct HandleCallAction
+ {
+#pragma warning disable CA1822 // Mark members as static - the other partial implementations might need to be instance methods
+
+ readonly LinkContext _context;
+ readonly ReflectionMarker _reflectionMarker;
+ readonly MethodDefinition _callingMethodDefinition;
+
+ public HandleCallAction (
+ LinkContext context,
+ ReflectionMarker reflectionMarker,
+ in DiagnosticContext diagnosticContext,
+ MethodDefinition callingMethodDefinition)
+ {
+ _context = context;
+ _reflectionMarker = reflectionMarker;
+ _diagnosticContext = diagnosticContext;
+ _callingMethodDefinition = callingMethodDefinition;
+ _annotations = context.Annotations.FlowAnnotations;
+ _requireDynamicallyAccessedMembersAction = new (context, reflectionMarker, diagnosticContext);
+ }
+
+ private partial bool MethodIsTypeConstructor (MethodProxy method)
+ {
+ if (!method.Method.IsConstructor)
+ return false;
+ TypeDefinition? type = method.Method.DeclaringType;
+ while (type is not null) {
+ if (type.IsTypeOf (WellKnownType.System_Type))
+ return true;
+ type = _context.Resolve (type.BaseType);
+ }
+ return false;
+ }
+
+ private partial IEnumerable<SystemReflectionMethodBaseValue> GetMethodsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var method in type.Type.GetMethodsOnTypeHierarchy (_context, m => m.Name == name, bindingFlags))
+ yield return new SystemReflectionMethodBaseValue (new MethodProxy (method));
+ }
+
+ private partial IEnumerable<SystemTypeValue> GetNestedTypesOnType (TypeProxy type, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var nestedType in type.Type.GetNestedTypesOnType (t => t.Name == name, bindingFlags))
+ yield return new SystemTypeValue (new TypeProxy (nestedType));
+ }
+
+ private partial bool TryGetBaseType (TypeProxy type, out TypeProxy? baseType)
+ {
+ if (type.Type.BaseType is TypeReference baseTypeRef && _context.TryResolve (baseTypeRef) is TypeDefinition baseTypeDefinition) {
+ baseType = new TypeProxy (baseTypeDefinition);
+ return true;
+ }
+
+ baseType = null;
+ return false;
+ }
+
+ private partial bool TryResolveTypeNameForCreateInstance (in MethodProxy calledMethod, string assemblyName, string typeName, out TypeProxy resolvedType)
+ {
+ var resolvedAssembly = _context.TryResolve (assemblyName);
+ if (resolvedAssembly == null) {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.UnresolvedAssemblyInCreateInstance,
+ assemblyName,
+ calledMethod.GetDisplayName ());
+ resolvedType = default;
+ return false;
+ }
+
+ if (!_context.TypeNameResolver.TryResolveTypeName (resolvedAssembly, typeName, out TypeReference? typeRef)
+ || _context.TryResolve (typeRef) is not TypeDefinition resolvedTypeDefinition
+ || typeRef is ArrayType) {
+ // It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case
+ // Note that we did find the assembly, so it's not a linker config problem, it's either intentional, or wrong versions of assemblies
+ // but linker can't know that. In case a user tries to create an array using System.Activator we should simply ignore it, the user
+ // might expect an exception to be thrown.
+ resolvedType = default;
+ return false;
+ }
+
+ resolvedType = new TypeProxy (resolvedTypeDefinition);
+ return true;
+ }
+
+ private partial void MarkStaticConstructor (TypeProxy type)
+ => _reflectionMarker.MarkStaticConstructor (_diagnosticContext.Origin, type.Type);
+
+ private partial void MarkEventsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMarker.MarkEventsOnTypeHierarchy (_diagnosticContext.Origin, type.Type, e => e.Name == name, bindingFlags);
+
+ private partial void MarkFieldsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMarker.MarkFieldsOnTypeHierarchy (_diagnosticContext.Origin, type.Type, f => f.Name == name, bindingFlags);
+
+ private partial void MarkPropertiesOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMarker.MarkPropertiesOnTypeHierarchy (_diagnosticContext.Origin, type.Type, p => p.Name == name, bindingFlags);
+
+ private partial void MarkPublicParameterlessConstructorOnType (TypeProxy type)
+ => _reflectionMarker.MarkConstructorsOnType (_diagnosticContext.Origin, type.Type, m => m.IsPublic && m.Parameters.Count == 0);
+
+ private partial void MarkConstructorsOnType (TypeProxy type, BindingFlags? bindingFlags, int? parameterCount)
+ => _reflectionMarker.MarkConstructorsOnType (_diagnosticContext.Origin, type.Type, parameterCount == null ? null : m => m.Parameters.Count == parameterCount, bindingFlags);
+
+ private partial void MarkMethod (MethodProxy method)
+ => _reflectionMarker.MarkMethod (_diagnosticContext.Origin, method.Method);
+
+ private partial void MarkType (TypeProxy type)
+ => _reflectionMarker.MarkType (_diagnosticContext.Origin, type.Type);
+
+ private partial bool MarkAssociatedProperty (MethodProxy method)
+ {
+ if (method.Method.TryGetProperty (out PropertyDefinition? propertyDefinition)) {
+ _reflectionMarker.MarkProperty (_diagnosticContext.Origin, propertyDefinition);
+ return true;
+ }
+
+ return false;
+ }
+
+ private partial string GetContainingSymbolDisplayName () => _callingMethodDefinition.GetDisplayName ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/IValueWithStaticType.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/IValueWithStaticType.cs
new file mode 100644
index 00000000000..e18561f1e5d
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/IValueWithStaticType.cs
@@ -0,0 +1,16 @@
+// 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 Mono.Cecil;
+
+namespace Mono.Linker.Dataflow
+{
+ interface IValueWithStaticType
+ {
+ /// <summary>
+ /// The IL type of the value, represented as closely as possible, but not always exact. It can be null, for
+ /// example, when the analysis is imprecise or operating on malformed IL.
+ /// </summary>
+ TypeDefinition? StaticType { get; }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodBodyScanner.cs
index f3cce6d4b8c..b50de89788f 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodBodyScanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodBodyScanner.cs
@@ -1,12 +1,16 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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.Linq;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TrimAnalysis;
+using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
namespace Mono.Linker.Dataflow
{
@@ -15,14 +19,26 @@ namespace Mono.Linker.Dataflow
/// </summary>
readonly struct StackSlot
{
- public ValueNode? Value { get; }
+ public MultiValue Value { get; }
/// <summary>
/// True if the value is on the stack as a byref
/// </summary>
public bool IsByRef { get; }
- public StackSlot (ValueNode? value, bool isByRef = false)
+ public StackSlot ()
+ {
+ Value = new MultiValue (UnknownValue.Instance);
+ IsByRef = false;
+ }
+
+ public StackSlot (SingleValue value, bool isByRef = false)
+ {
+ Value = new MultiValue (value);
+ IsByRef = isByRef;
+ }
+
+ public StackSlot (MultiValue value, bool isByRef = false)
{
Value = value;
IsByRef = isByRef;
@@ -32,13 +48,14 @@ namespace Mono.Linker.Dataflow
abstract partial class MethodBodyScanner
{
protected readonly LinkContext _context;
+ protected static ValueSetLattice<SingleValue> MultiValueLattice => default;
protected MethodBodyScanner (LinkContext context)
{
this._context = context;
}
- internal ValueNode? MethodReturnValue { private set; get; }
+ internal MultiValue ReturnValue { private set; get; }
protected virtual void WarnAboutInvalidILInMethod (MethodBody method, int ilOffset)
{
@@ -83,16 +100,7 @@ namespace Mono.Linker.Dataflow
private static StackSlot MergeStackElement (StackSlot a, StackSlot b)
{
- StackSlot mergedSlot;
- if (b.Value == null) {
- mergedSlot = a;
- } else if (a.Value == null) {
- mergedSlot = b;
- } else {
- mergedSlot = new StackSlot (MergePointValue.MergeValues (a.Value, b.Value));
- }
-
- return mergedSlot;
+ return new StackSlot (MultiValueLattice.Meet (a.Value, b.Value));
}
// Merge stacks together. This may return the first stack, the stack length must be the same for the two stacks.
@@ -174,31 +182,28 @@ namespace Mono.Linker.Dataflow
private static void StoreMethodLocalValue<KeyType> (
Dictionary<KeyType, ValueBasicBlockPair> valueCollection,
- ValueNode? valueToStore,
+ in MultiValue valueToStore,
KeyType collectionKey,
int curBasicBlock,
int? maxTrackedValues = null)
where KeyType : notnull
{
- ValueBasicBlockPair newValue = new ValueBasicBlockPair { BasicBlockIndex = curBasicBlock };
-
- ValueBasicBlockPair existingValue;
- if (valueCollection.TryGetValue (collectionKey, out existingValue)) {
+ if (valueCollection.TryGetValue (collectionKey, out ValueBasicBlockPair existingValue)) {
+ MultiValue value;
if (existingValue.BasicBlockIndex == curBasicBlock) {
- // If the previous value was stored in the current basic block, then we can safely
+ // If the previous value was stored in the current basic block, then we can safely
// overwrite the previous value with the new one.
- newValue.Value = valueToStore;
+ value = valueToStore;
} else {
- // If the previous value came from a previous basic block, then some other use of
- // the local could see the previous value, so we must merge the new value with the
+ // If the previous value came from a previous basic block, then some other use of
+ // the local could see the previous value, so we must merge the new value with the
// old value.
- newValue.Value = MergePointValue.MergeValues (existingValue.Value, valueToStore);
+ value = MultiValueLattice.Meet (existingValue.Value, valueToStore);
}
- valueCollection[collectionKey] = newValue;
+ valueCollection[collectionKey] = new ValueBasicBlockPair (value, curBasicBlock);
} else if (maxTrackedValues == null || valueCollection.Count < maxTrackedValues) {
// We're not currently tracking a value a this index, so store the value now.
- newValue.Value = valueToStore;
- valueCollection[collectionKey] = newValue;
+ valueCollection[collectionKey] = new ValueBasicBlockPair (valueToStore, curBasicBlock);
}
}
@@ -215,7 +220,7 @@ namespace Mono.Linker.Dataflow
BasicBlockIterator blockIterator = new BasicBlockIterator (methodBody);
- MethodReturnValue = null;
+ ReturnValue = new ();
foreach (Instruction operation in methodBody.Instructions) {
int curBasicBlock = blockIterator.MoveNext (operation);
@@ -421,12 +426,12 @@ namespace Mono.Linker.Dataflow
case Code.Ldsfld:
case Code.Ldflda:
case Code.Ldsflda:
- ScanLdfld (operation, currentStack, thisMethod, methodBody);
+ ScanLdfld (operation, currentStack, methodBody);
break;
case Code.Newarr: {
StackSlot count = PopUnknown (currentStack, 1, methodBody, operation.Offset);
- currentStack.Push (new StackSlot (new ArrayValue (count.Value, (TypeReference) operation.Operand)));
+ currentStack.Push (new StackSlot (ArrayValue.Create (count.Value, (TypeReference) operation.Operand)));
}
break;
@@ -532,7 +537,7 @@ namespace Mono.Linker.Dataflow
// Pop function pointer
PopUnknown (currentStack, 1, methodBody, operation.Offset);
- if (GetReturnTypeWithoutModifiers (signature.ReturnType).MetadataType != MetadataType.Void)
+ if (!signature.ReturnsVoid ())
PushUnknown (currentStack);
}
break;
@@ -568,14 +573,14 @@ namespace Mono.Linker.Dataflow
case Code.Ret: {
- bool hasReturnValue = GetReturnTypeWithoutModifiers (methodBody.Method.ReturnType).MetadataType != MetadataType.Void;
+ bool hasReturnValue = !methodBody.Method.ReturnsVoid ();
if (currentStack.Count != (hasReturnValue ? 1 : 0)) {
WarnAboutInvalidILInMethod (methodBody, operation.Offset);
}
if (hasReturnValue) {
StackSlot retValue = PopUnknown (currentStack, 1, methodBody, operation.Offset);
- MethodReturnValue = MergePointValue.MergeValues (MethodReturnValue, retValue.Value);
+ ReturnValue = MultiValueLattice.Meet (ReturnValue, retValue.Value);
}
ClearStack (ref currentStack);
break;
@@ -633,7 +638,7 @@ namespace Mono.Linker.Dataflow
}
}
- protected abstract ValueNode GetMethodParameterValue (MethodDefinition method, int parameterIndex);
+ protected abstract SingleValue GetMethodParameterValue (MethodDefinition method, int parameterIndex);
private void ScanLdarg (Instruction operation, Stack<StackSlot> currentStack, MethodDefinition thisMethod, MethodBody methodBody)
{
@@ -687,7 +692,11 @@ namespace Mono.Linker.Dataflow
{
ParameterDefinition param = (ParameterDefinition) operation.Operand;
var valueToStore = PopUnknown (currentStack, 1, methodBody, operation.Offset);
- HandleStoreParameter (thisMethod, param.Sequence, operation, valueToStore.Value);
+ var targetValue = GetMethodParameterValue (thisMethod, param.Sequence);
+ if (targetValue is MethodParameterValue targetParameterValue)
+ HandleStoreParameter (thisMethod, targetParameterValue, operation, valueToStore.Value);
+
+ // If the targetValue is MethodThisValue do nothing - it should never happen really, and if it does, there's nothing we can track there
}
private void ScanLdloc (
@@ -705,41 +714,49 @@ namespace Mono.Linker.Dataflow
bool isByRef = operation.OpCode.Code == Code.Ldloca || operation.OpCode.Code == Code.Ldloca_S
|| localDef.VariableType.IsByRefOrPointer ();
- ValueBasicBlockPair localValue;
- locals.TryGetValue (localDef, out localValue);
- if (localValue.Value != null) {
- ValueNode valueToPush = localValue.Value;
- currentStack.Push (new StackSlot (valueToPush, isByRef));
- } else {
- currentStack.Push (new StackSlot (null, isByRef));
- }
+ if (!locals.TryGetValue (localDef, out ValueBasicBlockPair localValue))
+ currentStack.Push (new StackSlot (UnknownValue.Instance, isByRef));
+ else
+ currentStack.Push (new StackSlot (localValue.Value, isByRef));
}
void ScanLdtoken (Instruction operation, Stack<StackSlot> currentStack)
{
- if (operation.Operand is GenericParameter genericParameter) {
- StackSlot slot = new StackSlot (new RuntimeTypeHandleForGenericParameterValue (genericParameter));
- currentStack.Push (slot);
+ switch (operation.Operand) {
+ case GenericParameter genericParameter:
+ var param = new RuntimeTypeHandleForGenericParameterValue (genericParameter);
+ currentStack.Push (new StackSlot (param));
return;
- }
-
- if (operation.Operand is TypeReference typeReference) {
- var resolvedReference = ResolveToTypeDefinition (typeReference);
- if (resolvedReference != null) {
- StackSlot slot = new StackSlot (new RuntimeTypeHandleValue (resolvedReference));
- currentStack.Push (slot);
- return;
- }
- } else if (operation.Operand is MethodReference methodReference) {
- var resolvedMethod = _context.TryResolve (methodReference);
- if (resolvedMethod != null) {
- StackSlot slot = new StackSlot (new RuntimeMethodHandleValue (resolvedMethod));
- currentStack.Push (slot);
+ case TypeReference typeReference when ResolveToTypeDefinition (typeReference) is TypeDefinition resolvedDefinition:
+ // Note that Nullable types without a generic argument (i.e. Nullable<>) will be RuntimeTypeHandleValue / SystemTypeValue
+ if (typeReference is IGenericInstance instance && resolvedDefinition.IsTypeOf (WellKnownType.System_Nullable_T)) {
+ switch (instance.GenericArguments[0]) {
+ case GenericParameter genericParam:
+ var nullableDam = new RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers (new TypeProxy (resolvedDefinition),
+ new RuntimeTypeHandleForGenericParameterValue (genericParam));
+ currentStack.Push (new StackSlot (nullableDam));
+ return;
+ case TypeReference underlyingTypeReference when ResolveToTypeDefinition (underlyingTypeReference) is TypeDefinition underlyingType:
+ var nullableType = new RuntimeTypeHandleForNullableSystemTypeValue (new TypeProxy (resolvedDefinition), new SystemTypeValue (underlyingType));
+ currentStack.Push (new StackSlot (nullableType));
+ return;
+ default:
+ PushUnknown (currentStack);
+ return;
+ }
+ } else {
+ var typeHandle = new RuntimeTypeHandleValue (new TypeProxy (resolvedDefinition));
+ currentStack.Push (new StackSlot (typeHandle));
return;
}
+ case MethodReference methodReference when _context.TryResolve (methodReference) is MethodDefinition resolvedMethod:
+ var method = new RuntimeMethodHandleValue (resolvedMethod);
+ currentStack.Push (new StackSlot (method));
+ return;
+ default:
+ PushUnknown (currentStack);
+ return;
}
-
- PushUnknown (currentStack);
}
private void ScanStloc (
@@ -767,22 +784,21 @@ namespace Mono.Linker.Dataflow
StackSlot valueToStore = PopUnknown (currentStack, 1, methodBody, operation.Offset);
StackSlot destination = PopUnknown (currentStack, 1, methodBody, operation.Offset);
- foreach (var uniqueDestination in destination.Value.UniqueValues ()) {
- if (uniqueDestination.Kind == ValueNodeKind.LoadField) {
- HandleStoreField (methodBody.Method, ((LoadFieldValue) uniqueDestination).Field, operation, valueToStore.Value);
- } else if (uniqueDestination.Kind == ValueNodeKind.MethodParameter) {
- HandleStoreParameter (methodBody.Method, ((MethodParameterValue) uniqueDestination).ParameterIndex, operation, valueToStore.Value);
+ foreach (var uniqueDestination in destination.Value) {
+ if (uniqueDestination is FieldValue fieldDestination) {
+ HandleStoreField (methodBody.Method, fieldDestination, operation, valueToStore.Value);
+ } else if (uniqueDestination is MethodParameterValue parameterDestination) {
+ HandleStoreParameter (methodBody.Method, parameterDestination, operation, valueToStore.Value);
}
}
}
- protected abstract ValueNode GetFieldValue (MethodDefinition method, FieldDefinition field);
+ protected abstract MultiValue GetFieldValue (FieldDefinition field);
private void ScanLdfld (
Instruction operation,
Stack<StackSlot> currentStack,
- MethodDefinition thisMethod,
MethodBody methodBody)
{
Code code = operation.OpCode.Code;
@@ -793,7 +809,7 @@ namespace Mono.Linker.Dataflow
FieldDefinition? field = _context.TryResolve ((FieldReference) operation.Operand);
if (field != null) {
- StackSlot slot = new StackSlot (GetFieldValue (thisMethod, field), isByRef);
+ StackSlot slot = new StackSlot (GetFieldValue (field), isByRef);
currentStack.Push (slot);
return;
}
@@ -801,11 +817,11 @@ namespace Mono.Linker.Dataflow
PushUnknown (currentStack);
}
- protected virtual void HandleStoreField (MethodDefinition method, FieldDefinition field, Instruction operation, ValueNode? valueToStore)
+ protected virtual void HandleStoreField (MethodDefinition method, FieldValue field, Instruction operation, MultiValue valueToStore)
{
}
- protected virtual void HandleStoreParameter (MethodDefinition method, int index, Instruction operation, ValueNode? valueToStore)
+ protected virtual void HandleStoreParameter (MethodDefinition method, MethodParameterValue parameter, Instruction operation, MultiValue valueToStore)
{
}
@@ -821,7 +837,14 @@ namespace Mono.Linker.Dataflow
FieldDefinition? field = _context.TryResolve ((FieldReference) operation.Operand);
if (field != null) {
- HandleStoreField (thisMethod, field, operation, valueToStoreSlot.Value);
+ foreach (var value in GetFieldValue (field)) {
+ // GetFieldValue may return different node types, in which case they can't be stored to.
+ // At least not yet.
+ if (value is not FieldValue fieldValue)
+ continue;
+
+ HandleStoreField (thisMethod, fieldValue, operation, valueToStoreSlot.Value);
+ }
}
}
@@ -841,7 +864,7 @@ namespace Mono.Linker.Dataflow
MethodReference methodCalled,
MethodBody containingMethodBody,
bool isNewObj, int ilOffset,
- out ValueNode? newObjValue)
+ out SingleValue? newObjValue)
{
newObjValue = null;
@@ -874,11 +897,11 @@ namespace Mono.Linker.Dataflow
bool isNewObj = operation.OpCode.Code == Code.Newobj;
- ValueNode? newObjValue;
+ SingleValue? newObjValue;
ValueNodeList methodParams = PopCallArguments (currentStack, calledMethod, callingMethodBody, isNewObj,
operation.Offset, out newObjValue);
- ValueNode? methodReturnValue;
+ MultiValue methodReturnValue;
bool handledFunction = HandleCall (
callingMethodBody,
calledMethod,
@@ -890,51 +913,36 @@ namespace Mono.Linker.Dataflow
if (!handledFunction) {
if (isNewObj) {
if (newObjValue == null)
- PushUnknown (currentStack);
+ methodReturnValue = new MultiValue (UnknownValue.Instance);
else
methodReturnValue = newObjValue;
} else {
- if (GetReturnTypeWithoutModifiers (calledMethod.ReturnType).MetadataType != MetadataType.Void) {
+ if (!calledMethod.ReturnsVoid ()) {
methodReturnValue = UnknownValue.Instance;
}
}
}
- if (methodReturnValue != null)
+ if (isNewObj || !calledMethod.ReturnsVoid ())
currentStack.Push (new StackSlot (methodReturnValue, calledMethod.ReturnType.IsByRefOrPointer ()));
foreach (var param in methodParams) {
- if (param is ArrayValue arr) {
- MarkArrayValuesAsUnknown (arr, curBasicBlock);
+ foreach (var v in param) {
+ if (v is ArrayValue arr) {
+ MarkArrayValuesAsUnknown (arr, curBasicBlock);
+ }
}
}
}
- protected static TypeReference GetReturnTypeWithoutModifiers (TypeReference returnType)
- {
- while (returnType is IModifierType) {
- returnType = ((IModifierType) returnType).ElementType;
- }
- return returnType;
- }
-
- // Array types that are dynamically accessed should resolve to System.Array instead of its element type - which is what Cecil resolves to.
- // Any data flow annotations placed on a type parameter which receives an array type apply to the array itself. None of the members in its
- // element type should be marked.
- public TypeDefinition? ResolveToTypeDefinition (TypeReference typeReference)
- {
- if (typeReference is ArrayType)
- return BCL.FindPredefinedType ("System", "Array", _context);
-
- return _context.TryResolve (typeReference);
- }
+ public TypeDefinition? ResolveToTypeDefinition (TypeReference typeReference) => typeReference.ResolveToTypeDefinition (_context);
public abstract bool HandleCall (
MethodBody callingMethodBody,
MethodReference calledMethod,
Instruction operation,
ValueNodeList methodParams,
- out ValueNode? methodReturnValue);
+ out MultiValue methodReturnValue);
// Limit tracking array values to 32 values for performance reasons. There are many arrays much longer than 32 elements in .NET, but the interesting ones for the linker are nearly always less than 32 elements.
private const int MaxTrackedArrayValues = 32;
@@ -959,7 +967,7 @@ namespace Mono.Linker.Dataflow
StackSlot indexToStoreAt = PopUnknown (currentStack, 1, methodBody, operation.Offset);
StackSlot arrayToStoreIn = PopUnknown (currentStack, 1, methodBody, operation.Offset);
int? indexToStoreAtInt = indexToStoreAt.Value.AsConstInt ();
- foreach (var array in arrayToStoreIn.Value.UniqueValues ()) {
+ foreach (var array in arrayToStoreIn.Value) {
if (array is ArrayValue arrValue) {
if (indexToStoreAtInt == null) {
MarkArrayValuesAsUnknown (arrValue, curBasicBlock);
@@ -979,7 +987,7 @@ namespace Mono.Linker.Dataflow
{
StackSlot indexToLoadFrom = PopUnknown (currentStack, 1, methodBody, operation.Offset);
StackSlot arrayToLoadFrom = PopUnknown (currentStack, 1, methodBody, operation.Offset);
- if (arrayToLoadFrom.Value is not ArrayValue arr) {
+ if (arrayToLoadFrom.Value.AsSingleValue () is not ArrayValue arr) {
PushUnknown (currentStack);
return;
}
@@ -994,15 +1002,10 @@ namespace Mono.Linker.Dataflow
return;
}
-
- ValueBasicBlockPair arrayIndexValue;
- arr.IndexValues.TryGetValue (index.Value, out arrayIndexValue);
- if (arrayIndexValue.Value != null) {
- ValueNode valueToPush = arrayIndexValue.Value;
- currentStack.Push (new StackSlot (valueToPush, isByRef));
- } else {
- currentStack.Push (new StackSlot (null, isByRef));
- }
+ if (arr.IndexValues.TryGetValue (index.Value, out ValueBasicBlockPair arrayIndexValue))
+ currentStack.Push (new StackSlot (arrayIndexValue.Value, isByRef));
+ else
+ PushUnknown (currentStack);
}
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodParameterValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodParameterValue.cs
new file mode 100644
index 00000000000..325b0285273
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodParameterValue.cs
@@ -0,0 +1,49 @@
+// 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.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.DataFlow;
+using Mono.Cecil;
+using Mono.Linker.Dataflow;
+using TypeDefinition = Mono.Cecil.TypeDefinition;
+
+
+namespace ILLink.Shared.TrimAnalysis
+{
+
+ /// <summary>
+ /// A value that came from a method parameter - such as the result of a ldarg.
+ /// </summary>
+ partial record MethodParameterValue : IValueWithStaticType
+ {
+ public MethodParameterValue (TypeDefinition? staticType, MethodDefinition method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ StaticType = staticType;
+ Method = method;
+ ParameterIndex = parameterIndex;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly MethodDefinition Method;
+
+ /// <summary>
+ /// This is the index of non-implicit parameter - so the index into MethodDefinition.Parameters array.
+ /// It's NOT the IL parameter index which could be offset by 1 if the method has an implicit this.
+ /// </summary>
+ public readonly int ParameterIndex;
+
+ public ParameterDefinition ParameterDefinition => Method.Parameters[ParameterIndex];
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => new string[] { DiagnosticUtilities.GetParameterNameForErrorMessage (ParameterDefinition), DiagnosticUtilities.GetMethodSignatureDisplayName (Method) };
+
+ public TypeDefinition? StaticType { get; }
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (Method, ParameterIndex, DynamicallyAccessedMemberTypes);
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodProxy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodProxy.cs
new file mode 100644
index 00000000000..6180b2bdb4f
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodProxy.cs
@@ -0,0 +1,55 @@
+// 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.Collections.Immutable;
+using Mono.Cecil;
+using Mono.Linker;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ readonly partial struct MethodProxy
+ {
+ public MethodProxy (MethodDefinition method) => Method = method;
+
+ public static implicit operator MethodProxy (MethodDefinition method) => new (method);
+
+ public readonly MethodDefinition Method;
+
+ public string Name { get => Method.Name; }
+
+ public string GetDisplayName () => Method.GetDisplayName ();
+
+ internal partial bool IsDeclaredOnType (string fullTypeName) => Method.IsDeclaredOnType (fullTypeName);
+
+ internal partial bool HasParameters () => Method.HasParameters;
+
+ internal partial int GetParametersCount () => Method.Parameters.Count;
+
+ internal partial bool HasParameterOfType (int parameterIndex, string fullTypeName) => Method.HasParameterOfType (parameterIndex, fullTypeName);
+
+ internal partial string GetParameterDisplayName (int parameterIndex) => Method.Parameters[parameterIndex].Name;
+
+ internal partial bool HasGenericParameters () => Method.HasGenericParameters;
+
+ internal partial bool HasGenericParametersCount (int genericParameterCount) => Method.GenericParameters.Count == genericParameterCount;
+
+ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ()
+ {
+ if (!Method.HasGenericParameters)
+ return ImmutableArray<GenericParameterProxy>.Empty;
+
+ var builder = ImmutableArray.CreateBuilder<GenericParameterProxy> (Method.GenericParameters.Count);
+ foreach (var genericParameter in Method.GenericParameters) {
+ builder.Add (new GenericParameterProxy (genericParameter));
+ }
+
+ return builder.ToImmutableArray ();
+ }
+
+ internal partial bool IsStatic () => Method.IsStatic;
+
+ internal partial bool ReturnsVoid () => Method.ReturnsVoid ();
+
+ public override string ToString () => Method.ToString ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodReturnValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodReturnValue.cs
new file mode 100644
index 00000000000..f6cb423c121
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodReturnValue.cs
@@ -0,0 +1,39 @@
+// 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.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.DataFlow;
+using Mono.Cecil;
+using Mono.Linker.Dataflow;
+using TypeDefinition = Mono.Cecil.TypeDefinition;
+
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// Return value from a method
+ /// </summary>
+ partial record MethodReturnValue : IValueWithStaticType
+ {
+ public MethodReturnValue (TypeDefinition? staticType, MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ StaticType = staticType;
+ Method = method;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly MethodDefinition Method;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => new string[] { DiagnosticUtilities.GetMethodSignatureDisplayName (Method) };
+
+ public TypeDefinition? StaticType { get; }
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (Method, DynamicallyAccessedMemberTypes);
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodThisParameterValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodThisParameterValue.cs
new file mode 100644
index 00000000000..c2f46d5996e
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodThisParameterValue.cs
@@ -0,0 +1,40 @@
+// 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.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.DataFlow;
+using Mono.Cecil;
+using Mono.Linker;
+using Mono.Linker.Dataflow;
+using TypeDefinition = Mono.Cecil.TypeDefinition;
+
+
+namespace ILLink.Shared.TrimAnalysis
+{
+
+ /// <summary>
+ /// A value that came from the implicit this parameter of a method
+ /// </summary>
+ partial record MethodThisParameterValue : IValueWithStaticType
+ {
+ public MethodThisParameterValue (MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ Method = method;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ }
+
+ public readonly MethodDefinition Method;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => new string[] { Method.GetDisplayName () };
+
+ public TypeDefinition? StaticType => Method.DeclaringType;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (Method, DynamicallyAccessedMemberTypes);
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/README.md b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/README.md
index 693097ed774..0fb01d85ff3 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/README.md
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/README.md
@@ -1 +1 @@
-Sources taken from https://github.com/dotnet/linker/tree/9996319f2a619c2911b02c164b4d6b1d20e29a39/src/linker/Linker.Dataflow.
+Sources taken from https://github.com/dotnet/linker/tree/9eb23e4a61c59b8dd12078e50fce3147b41171da/src/linker/Linker.Dataflow.
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMarker.cs
new file mode 100644
index 00000000000..51268fdfac8
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMarker.cs
@@ -0,0 +1,123 @@
+// 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.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using Mono.Cecil;
+using Mono.Linker.Steps;
+
+namespace Mono.Linker.Dataflow
+{
+ public readonly struct ReflectionMarker
+ {
+ readonly LinkContext _context;
+ readonly MarkStep _markStep;
+
+ public ReflectionMarker (LinkContext context, MarkStep markStep)
+ {
+ _context = context;
+ _markStep = markStep;
+ }
+
+ internal void MarkTypeForDynamicallyAccessedMembers (in MessageOrigin origin, TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, DependencyKind dependencyKind, bool declaredOnly = false)
+ {
+ foreach (var member in typeDefinition.GetDynamicallyAccessedMembers (_context, requiredMemberTypes, declaredOnly)) {
+ switch (member) {
+ case MethodDefinition method:
+ MarkMethod (origin, method, dependencyKind);
+ break;
+ case FieldDefinition field:
+ MarkField (origin, field, dependencyKind);
+ break;
+ case TypeDefinition nestedType:
+ MarkType (origin, nestedType, dependencyKind);
+ break;
+ case PropertyDefinition property:
+ MarkProperty (origin, property, dependencyKind);
+ break;
+ case EventDefinition @event:
+ MarkEvent (origin, @event, dependencyKind);
+ break;
+ case InterfaceImplementation interfaceImplementation:
+ MarkInterfaceImplementation (origin, interfaceImplementation, dependencyKind);
+ break;
+ }
+ }
+ }
+
+ internal bool TryResolveTypeNameAndMark (string typeName, MessageOrigin origin, bool needsAssemblyName, [NotNullWhen (true)] out TypeDefinition? type)
+ {
+ if (!_context.TypeNameResolver.TryResolveTypeName (typeName, origin.Provider, out TypeReference? typeRef, out AssemblyDefinition? typeAssembly, needsAssemblyName)
+ || typeRef.ResolveToTypeDefinition (_context) is not TypeDefinition foundType) {
+ type = default;
+ return false;
+ }
+
+ _markStep.MarkTypeVisibleToReflection (typeRef, foundType, new DependencyInfo (DependencyKind.AccessedViaReflection, origin.Provider), origin);
+ _context.MarkingHelpers.MarkMatchingExportedType (foundType, typeAssembly, new DependencyInfo (DependencyKind.DynamicallyAccessedMember, foundType), origin);
+
+ type = foundType;
+ return true;
+ }
+
+ internal void MarkType (in MessageOrigin origin, TypeDefinition type, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
+ {
+ _markStep.MarkTypeVisibleToReflection (type, type, new DependencyInfo (dependencyKind, origin.Provider), origin);
+ }
+
+ internal void MarkMethod (in MessageOrigin origin, MethodDefinition method, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
+ {
+ _markStep.MarkMethodVisibleToReflection (method, new DependencyInfo (dependencyKind, origin.Provider), origin);
+ }
+
+ void MarkField (in MessageOrigin origin, FieldDefinition field, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
+ {
+ _markStep.MarkFieldVisibleToReflection (field, new DependencyInfo (dependencyKind, origin.Provider), origin);
+ }
+
+ internal void MarkProperty (in MessageOrigin origin, PropertyDefinition property, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
+ {
+ _markStep.MarkPropertyVisibleToReflection (property, new DependencyInfo (dependencyKind, origin.Provider), origin);
+ }
+
+ void MarkEvent (in MessageOrigin origin, EventDefinition @event, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
+ {
+ _markStep.MarkEventVisibleToReflection (@event, new DependencyInfo (dependencyKind, origin.Provider), origin);
+ }
+
+ void MarkInterfaceImplementation (in MessageOrigin origin, InterfaceImplementation interfaceImplementation, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
+ {
+ _markStep.MarkInterfaceImplementation (interfaceImplementation, null, new DependencyInfo (dependencyKind, origin.Provider));
+ }
+
+ internal void MarkConstructorsOnType (in MessageOrigin origin, TypeDefinition type, Func<MethodDefinition, bool>? filter, BindingFlags? bindingFlags = null)
+ {
+ foreach (var ctor in type.GetConstructorsOnType (filter, bindingFlags))
+ MarkMethod (origin, ctor);
+ }
+
+ internal void MarkFieldsOnTypeHierarchy (in MessageOrigin origin, TypeDefinition type, Func<FieldDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
+ {
+ foreach (var field in type.GetFieldsOnTypeHierarchy (_context, filter, bindingFlags))
+ MarkField (origin, field);
+ }
+
+ internal void MarkPropertiesOnTypeHierarchy (in MessageOrigin origin, TypeDefinition type, Func<PropertyDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
+ {
+ foreach (var property in type.GetPropertiesOnTypeHierarchy (_context, filter, bindingFlags))
+ MarkProperty (origin, property);
+ }
+
+ internal void MarkEventsOnTypeHierarchy (in MessageOrigin origin, TypeDefinition type, Func<EventDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
+ {
+ foreach (var @event in type.GetEventsOnTypeHierarchy (_context, filter, bindingFlags))
+ MarkEvent (origin, @event);
+ }
+
+ internal void MarkStaticConstructor (in MessageOrigin origin, TypeDefinition type)
+ {
+ _markStep.MarkStaticConstructorVisibleToReflection (type, new DependencyInfo (DependencyKind.AccessedViaReflection, origin.Provider), origin);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMethodBodyScanner.cs
index 67ce51fe050..ee9cd02264c 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMethodBodyScanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionMethodBodyScanner.cs
@@ -1,35 +1,29 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using ILLink.Shared;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TrimAnalysis;
+using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Linker.Steps;
-
-using BindingFlags = System.Reflection.BindingFlags;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
namespace Mono.Linker.Dataflow
{
class ReflectionMethodBodyScanner : MethodBodyScanner
{
readonly MarkStep _markStep;
- readonly MarkScopeStack _scopeStack;
- static readonly DynamicallyAccessedMemberTypes[] AllDynamicallyAccessedMemberTypes = GetAllDynamicallyAccessedMemberTypes ();
-
- static DynamicallyAccessedMemberTypes[] GetAllDynamicallyAccessedMemberTypes ()
- {
- HashSet<DynamicallyAccessedMemberTypes> values = Enum.GetValues (typeof (DynamicallyAccessedMemberTypes))
- .Cast<DynamicallyAccessedMemberTypes> ()
- .ToHashSet ();
- if (!values.Contains (DynamicallyAccessedMemberTypesOverlay.Interfaces))
- values.Add (DynamicallyAccessedMemberTypesOverlay.Interfaces);
- return values.ToArray ();
- }
+ MessageOrigin _origin;
+ readonly FlowAnnotations _annotations;
+ readonly ReflectionMarker _reflectionMarker;
public static bool RequiresReflectionMethodBodyScannerForCallSite (LinkContext context, MethodReference calledMethod)
{
@@ -37,17 +31,16 @@ namespace Mono.Linker.Dataflow
if (methodDefinition == null)
return false;
- return GetIntrinsicIdForMethod (methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
+ return Intrinsics.GetIntrinsicIdForMethod (methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis (methodDefinition) ||
context.Annotations.DoesMethodRequireUnreferencedCode (methodDefinition, out _) ||
methodDefinition.IsPInvokeImpl;
}
- public static bool RequiresReflectionMethodBodyScannerForMethodBody (FlowAnnotations flowAnnotations, MethodDefinition methodDefinition)
+ public static bool RequiresReflectionMethodBodyScannerForMethodBody (LinkContext context, MethodDefinition methodDefinition)
{
- return
- GetIntrinsicIdForMethod (methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
- flowAnnotations.RequiresDataFlowAnalysis (methodDefinition);
+ return Intrinsics.GetIntrinsicIdForMethod (methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
+ context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis (methodDefinition);
}
public static bool RequiresReflectionMethodBodyScannerForAccess (LinkContext context, FieldReference field)
@@ -59,116 +52,117 @@ namespace Mono.Linker.Dataflow
return context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis (fieldDefinition);
}
- bool ShouldEnableReflectionPatternReporting ()
+ bool ShouldEnableReflectionPatternReporting (ICustomAttributeProvider? provider)
{
- if (_markStep.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode ())
+ if (_markStep.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode (provider))
return false;
return true;
}
- public ReflectionMethodBodyScanner (LinkContext context, MarkStep parent, MarkScopeStack scopeStack)
+ public ReflectionMethodBodyScanner (LinkContext context, MarkStep parent, MessageOrigin origin)
: base (context)
{
_markStep = parent;
- _scopeStack = scopeStack;
+ _origin = origin;
+ _annotations = context.Annotations.FlowAnnotations;
+ _reflectionMarker = new ReflectionMarker (context, parent);
}
public void ScanAndProcessReturnValue (MethodBody methodBody)
{
Scan (methodBody);
- if (GetReturnTypeWithoutModifiers (methodBody.Method.ReturnType).MetadataType != MetadataType.Void) {
+ if (!methodBody.Method.ReturnsVoid ()) {
var method = methodBody.Method;
- var requiredMemberTypes = _context.Annotations.FlowAnnotations.GetReturnParameterAnnotation (method);
- if (requiredMemberTypes != 0) {
- var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), _scopeStack.CurrentScope.Origin, method.MethodReturnType);
- reflectionContext.AnalyzingPattern ();
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, MethodReturnValue, method.MethodReturnType);
- reflectionContext.Dispose ();
+ var methodReturnValue = _annotations.GetMethodReturnValue (method);
+ if (methodReturnValue.DynamicallyAccessedMemberTypes != 0) {
+ var diagnosticContext = new DiagnosticContext (_origin, ShouldEnableReflectionPatternReporting (_origin.Provider), _context);
+ RequireDynamicallyAccessedMembers (diagnosticContext, ReturnValue, methodReturnValue);
}
}
}
public void ProcessAttributeDataflow (MethodDefinition method, IList<CustomAttributeArgument> arguments)
{
- int paramOffset = method.HasImplicitThis () ? 1 : 0;
-
for (int i = 0; i < method.Parameters.Count; i++) {
- var annotation = _context.Annotations.FlowAnnotations.GetParameterAnnotation (method, i + paramOffset);
- if (annotation != DynamicallyAccessedMemberTypes.None) {
- ValueNode valueNode = GetValueNodeForCustomAttributeArgument (arguments[i]);
- var methodParameter = method.Parameters[i];
- var reflectionContext = new ReflectionPatternContext (_context, true, _scopeStack.CurrentScope.Origin, methodParameter);
- reflectionContext.AnalyzingPattern ();
- RequireDynamicallyAccessedMembers (ref reflectionContext, annotation, valueNode, methodParameter);
- reflectionContext.Dispose ();
+ var parameterValue = _annotations.GetMethodParameterValue (method, i);
+ if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) {
+ MultiValue value = GetValueNodeForCustomAttributeArgument (arguments[i]);
+ var diagnosticContext = new DiagnosticContext (_origin, diagnosticsEnabled: true, _context);
+ RequireDynamicallyAccessedMembers (diagnosticContext, value, parameterValue);
}
}
}
public void ProcessAttributeDataflow (FieldDefinition field, CustomAttributeArgument value)
{
- var annotation = _context.Annotations.FlowAnnotations.GetFieldAnnotation (field);
- Debug.Assert (annotation != DynamicallyAccessedMemberTypes.None);
+ MultiValue valueNode = GetValueNodeForCustomAttributeArgument (value);
+ foreach (var fieldValueCandidate in GetFieldValue (field)) {
+ if (fieldValueCandidate is not ValueWithDynamicallyAccessedMembers fieldValue)
+ continue;
- ValueNode valueNode = GetValueNodeForCustomAttributeArgument (value);
- var reflectionContext = new ReflectionPatternContext (_context, true, _scopeStack.CurrentScope.Origin, field);
- reflectionContext.AnalyzingPattern ();
- RequireDynamicallyAccessedMembers (ref reflectionContext, annotation, valueNode, field);
- reflectionContext.Dispose ();
+ var diagnosticContext = new DiagnosticContext (_origin, diagnosticsEnabled: true, _context);
+ RequireDynamicallyAccessedMembers (diagnosticContext, valueNode, fieldValue);
+ }
}
- ValueNode GetValueNodeForCustomAttributeArgument (CustomAttributeArgument argument)
+ MultiValue GetValueNodeForCustomAttributeArgument (CustomAttributeArgument argument)
{
- ValueNode valueNode;
+ SingleValue value;
if (argument.Type.Name == "Type") {
TypeDefinition? referencedType = ResolveToTypeDefinition ((TypeReference) argument.Value);
if (referencedType == null)
- valueNode = UnknownValue.Instance;
+ value = UnknownValue.Instance;
else
- valueNode = new SystemTypeValue (referencedType);
+ value = new SystemTypeValue (referencedType);
} else if (argument.Type.MetadataType == MetadataType.String) {
- valueNode = new KnownStringValue ((string) argument.Value);
+ value = new KnownStringValue ((string) argument.Value);
} else {
// We shouldn't have gotten a non-null annotation for this from GetParameterAnnotation
throw new InvalidOperationException ();
}
- Debug.Assert (valueNode != null);
- return valueNode;
+ Debug.Assert (value != null);
+ return value;
}
public void ProcessGenericArgumentDataFlow (GenericParameter genericParameter, TypeReference genericArgument)
{
- var annotation = _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameter);
- Debug.Assert (annotation != DynamicallyAccessedMemberTypes.None);
+ var genericParameterValue = _annotations.GetGenericParameterValue (genericParameter);
+ Debug.Assert (genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None);
- ValueNode valueNode = GetTypeValueNodeFromGenericArgument (genericArgument);
- var currentScopeOrigin = _scopeStack.CurrentScope.Origin;
+ MultiValue genericArgumentValue = GetTypeValueNodeFromGenericArgument (genericArgument);
- var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), currentScopeOrigin, genericParameter);
- reflectionContext.AnalyzingPattern ();
- RequireDynamicallyAccessedMembers (ref reflectionContext, annotation, valueNode, genericParameter);
- reflectionContext.Dispose ();
+ var diagnosticContext = new DiagnosticContext (_origin, ShouldEnableReflectionPatternReporting (_origin.Provider), _context);
+ RequireDynamicallyAccessedMembers (diagnosticContext, genericArgumentValue, genericParameterValue);
}
- ValueNode GetTypeValueNodeFromGenericArgument (TypeReference genericArgument)
+ MultiValue GetTypeValueNodeFromGenericArgument (TypeReference genericArgument)
{
if (genericArgument is GenericParameter inputGenericParameter) {
// Technically this should be a new value node type as it's not a System.Type instance representation, but just the generic parameter
// That said we only use it to perform the dynamically accessed members checks and for that purpose treating it as System.Type is perfectly valid.
- return new SystemTypeForGenericParameterValue (inputGenericParameter, _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (inputGenericParameter));
- } else {
- TypeDefinition? genericArgumentTypeDef = ResolveToTypeDefinition (genericArgument);
- if (genericArgumentTypeDef != null) {
- return new SystemTypeValue (genericArgumentTypeDef);
- } else {
- // If we can't resolve the generic argument, it means we can't apply potential requirements on it
- // so track it as unknown value. If we later on hit this unknown value as being used somewhere
- // where we need to apply requirements on it, it will generate a warning.
- return UnknownValue.Instance;
+ return _annotations.GetGenericParameterValue (inputGenericParameter);
+ } else if (ResolveToTypeDefinition (genericArgument) is TypeDefinition genericArgumentType) {
+ if (genericArgumentType.IsTypeOf (WellKnownType.System_Nullable_T)) {
+ var innerGenericArgument = (genericArgument as IGenericInstance)?.GenericArguments.FirstOrDefault ();
+ switch (innerGenericArgument) {
+ case GenericParameter gp:
+ return new NullableValueWithDynamicallyAccessedMembers (genericArgumentType,
+ new GenericParameterValue (gp, _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (gp)));
+
+ case TypeReference underlyingType:
+ if (ResolveToTypeDefinition (underlyingType) is TypeDefinition underlyingTypeDefinition)
+ return new NullableSystemTypeValue (genericArgumentType, new SystemTypeValue (underlyingTypeDefinition));
+ else
+ return UnknownValue.Instance;
+ }
}
+ // All values except for Nullable<T>, including Nullable<> (with no type arguments)
+ return new SystemTypeValue (genericArgumentType);
+ } else {
+ return UnknownValue.Instance;
}
}
@@ -183,453 +177,60 @@ namespace Mono.Linker.Dataflow
Debug.Fail ("Invalid IL or a bug in the scanner");
}
- MethodReturnValue CreateMethodReturnValue (MethodReference method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes = DynamicallyAccessedMemberTypes.None)
- {
- return new MethodReturnValue (ResolveToTypeDefinition (method.ReturnType), dynamicallyAccessedMemberTypes, method.MethodReturnType);
- }
+ protected override ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, int parameterIndex)
+ => GetMethodParameterValue (method, parameterIndex, _context.Annotations.FlowAnnotations.GetParameterAnnotation (method, parameterIndex));
- protected override ValueNode GetMethodParameterValue (MethodDefinition method, int parameterIndex)
+ ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
{
- DynamicallyAccessedMemberTypes memberTypes = _context.Annotations.FlowAnnotations.GetParameterAnnotation (method, parameterIndex);
+ if (method.HasImplicitThis ()) {
+ if (parameterIndex == 0)
+ return _annotations.GetMethodThisParameterValue (method, dynamicallyAccessedMemberTypes);
- var staticType =
- !method.HasImplicitThis () ? ResolveToTypeDefinition (method.Parameters[parameterIndex].ParameterType) :
- parameterIndex == 0 ? method.DeclaringType :
- ResolveToTypeDefinition (method.Parameters[parameterIndex - 1].ParameterType);
+ parameterIndex--;
+ }
- return new MethodParameterValue (staticType, parameterIndex, memberTypes, DiagnosticUtilities.GetMethodParameterFromIndex (method, parameterIndex));
+ return _annotations.GetMethodParameterValue (method, parameterIndex, dynamicallyAccessedMemberTypes);
}
- protected override ValueNode GetFieldValue (MethodDefinition method, FieldDefinition field)
+ protected override MultiValue GetFieldValue (FieldDefinition field)
{
switch (field.Name) {
- case "EmptyTypes" when field.DeclaringType.IsTypeOf ("System", "Type"): {
- return new ArrayValue (new ConstIntValue (0), field.DeclaringType);
+ case "EmptyTypes" when field.DeclaringType.IsTypeOf (WellKnownType.System_Type): {
+ return ArrayValue.Create (0, field.DeclaringType);
}
- case "Empty" when field.DeclaringType.IsTypeOf ("System", "String"): {
+ case "Empty" when field.DeclaringType.IsTypeOf (WellKnownType.System_String): {
return new KnownStringValue (string.Empty);
}
default: {
DynamicallyAccessedMemberTypes memberTypes = _context.Annotations.FlowAnnotations.GetFieldAnnotation (field);
- return new LoadFieldValue (ResolveToTypeDefinition (field.FieldType), field, memberTypes);
+ return new FieldValue (ResolveToTypeDefinition (field.FieldType), field, memberTypes);
}
}
}
- protected override void HandleStoreField (MethodDefinition method, FieldDefinition field, Instruction operation, ValueNode? valueToStore)
+ protected override void HandleStoreField (MethodDefinition method, FieldValue field, Instruction operation, MultiValue valueToStore)
{
- var requiredMemberTypes = _context.Annotations.FlowAnnotations.GetFieldAnnotation (field);
- if (requiredMemberTypes != 0) {
- _scopeStack.UpdateCurrentScopeInstructionOffset (operation.Offset);
- var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), _scopeStack.CurrentScope.Origin, field, operation);
- reflectionContext.AnalyzingPattern ();
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, valueToStore, field);
- reflectionContext.Dispose ();
+ if (field.DynamicallyAccessedMemberTypes != 0) {
+ _origin = _origin.WithInstructionOffset (operation.Offset);
+ var diagnosticContext = new DiagnosticContext (_origin, ShouldEnableReflectionPatternReporting (_origin.Provider), _context);
+ RequireDynamicallyAccessedMembers (diagnosticContext, valueToStore, field);
}
}
- protected override void HandleStoreParameter (MethodDefinition method, int index, Instruction operation, ValueNode? valueToStore)
+ protected override void HandleStoreParameter (MethodDefinition method, MethodParameterValue parameter, Instruction operation, MultiValue valueToStore)
{
- var requiredMemberTypes = _context.Annotations.FlowAnnotations.GetParameterAnnotation (method, index);
- if (requiredMemberTypes != 0) {
- ParameterDefinition parameter = method.Parameters[index - (method.HasImplicitThis () ? 1 : 0)];
- _scopeStack.UpdateCurrentScopeInstructionOffset (operation.Offset);
- var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), _scopeStack.CurrentScope.Origin, parameter, operation);
- reflectionContext.AnalyzingPattern ();
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, valueToStore, parameter);
- reflectionContext.Dispose ();
+ if (parameter.DynamicallyAccessedMemberTypes != 0) {
+ _origin = _origin.WithInstructionOffset (operation.Offset);
+ var diagnosticContext = new DiagnosticContext (_origin, ShouldEnableReflectionPatternReporting (_origin.Provider), _context);
+ RequireDynamicallyAccessedMembers (diagnosticContext, valueToStore, parameter);
}
}
- enum IntrinsicId
- {
- None = 0,
- IntrospectionExtensions_GetTypeInfo,
- Type_GetTypeFromHandle,
- Type_get_TypeHandle,
- Object_GetType,
- TypeDelegator_Ctor,
- Array_Empty,
- TypeInfo_AsType,
- MethodBase_GetMethodFromHandle,
-
- // Anything above this marker will require the method to be run through
- // the reflection body scanner.
- RequiresReflectionBodyScanner_Sentinel = 1000,
- Type_MakeGenericType,
- Type_GetType,
- Type_GetConstructor,
- Type_GetConstructors,
- Type_GetMethod,
- Type_GetMethods,
- Type_GetField,
- Type_GetFields,
- Type_GetProperty,
- Type_GetProperties,
- Type_GetEvent,
- Type_GetEvents,
- Type_GetNestedType,
- Type_GetNestedTypes,
- Type_GetMember,
- Type_GetMembers,
- Type_GetInterface,
- Type_get_AssemblyQualifiedName,
- Type_get_UnderlyingSystemType,
- Type_get_BaseType,
- Expression_Call,
- Expression_Field,
- Expression_Property,
- Expression_New,
- Activator_CreateInstance_Type,
- Activator_CreateInstance_AssemblyName_TypeName,
- Activator_CreateInstanceFrom,
- Activator_CreateInstanceOfT,
- AppDomain_CreateInstance,
- AppDomain_CreateInstanceAndUnwrap,
- AppDomain_CreateInstanceFrom,
- AppDomain_CreateInstanceFromAndUnwrap,
- Assembly_CreateInstance,
- RuntimeReflectionExtensions_GetRuntimeEvent,
- RuntimeReflectionExtensions_GetRuntimeField,
- RuntimeReflectionExtensions_GetRuntimeMethod,
- RuntimeReflectionExtensions_GetRuntimeProperty,
- RuntimeHelpers_RunClassConstructor,
- MethodInfo_MakeGenericMethod,
- }
-
- static IntrinsicId GetIntrinsicIdForMethod (MethodDefinition calledMethod)
+ public override bool HandleCall (MethodBody callingMethodBody, MethodReference calledMethod, Instruction operation, ValueNodeList methodParams, out MultiValue methodReturnValue)
{
- return calledMethod.Name switch {
- // static System.Reflection.IntrospectionExtensions.GetTypeInfo (Type type)
- "GetTypeInfo" when calledMethod.IsDeclaredOnType ("System.Reflection", "IntrospectionExtensions") => IntrinsicId.IntrospectionExtensions_GetTypeInfo,
-
- // System.Reflection.TypeInfo.AsType ()
- "AsType" when calledMethod.IsDeclaredOnType ("System.Reflection", "TypeInfo") => IntrinsicId.TypeInfo_AsType,
-
- // System.Type.GetTypeInfo (Type type)
- "GetTypeFromHandle" when calledMethod.IsDeclaredOnType ("System", "Type") => IntrinsicId.Type_GetTypeFromHandle,
-
- // System.Type.GetTypeHandle (Type type)
- "get_TypeHandle" when calledMethod.IsDeclaredOnType ("System", "Type") => IntrinsicId.Type_get_TypeHandle,
-
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
- "GetMethodFromHandle" when calledMethod.IsDeclaredOnType ("System.Reflection", "MethodBase")
- && calledMethod.HasParameterOfType (0, "System", "RuntimeMethodHandle")
- && (calledMethod.Parameters.Count == 1 || calledMethod.Parameters.Count == 2)
- => IntrinsicId.MethodBase_GetMethodFromHandle,
-
- // static System.Type.MakeGenericType (Type [] typeArguments)
- "MakeGenericType" when calledMethod.IsDeclaredOnType ("System", "Type") => IntrinsicId.Type_MakeGenericType,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeEvent (this Type type, string name)
- "GetRuntimeEvent" when calledMethod.IsDeclaredOnType ("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System", "Type")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeField (this Type type, string name)
- "GetRuntimeField" when calledMethod.IsDeclaredOnType ("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System", "Type")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeMethod (this Type type, string name, Type[] parameters)
- "GetRuntimeMethod" when calledMethod.IsDeclaredOnType ("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System", "Type")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeProperty (this Type type, string name)
- "GetRuntimeProperty" when calledMethod.IsDeclaredOnType ("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System", "Type")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty,
-
- // static System.Linq.Expressions.Expression.Call (Type, String, Type[], Expression[])
- "Call" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions", "Expression")
- && calledMethod.HasParameterOfType (0, "System", "Type")
- && calledMethod.Parameters.Count == 4
- => IntrinsicId.Expression_Call,
-
- // static System.Linq.Expressions.Expression.Field (Expression, Type, String)
- "Field" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions", "Expression")
- && calledMethod.HasParameterOfType (1, "System", "Type")
- && calledMethod.Parameters.Count == 3
- => IntrinsicId.Expression_Field,
-
- // static System.Linq.Expressions.Expression.Property (Expression, Type, String)
- // static System.Linq.Expressions.Expression.Property (Expression, MethodInfo)
- "Property" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions", "Expression")
- && ((calledMethod.HasParameterOfType (1, "System", "Type") && calledMethod.Parameters.Count == 3)
- || (calledMethod.HasParameterOfType (1, "System.Reflection", "MethodInfo") && calledMethod.Parameters.Count == 2))
- => IntrinsicId.Expression_Property,
-
- // static System.Linq.Expressions.Expression.New (Type)
- "New" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions", "Expression")
- && calledMethod.HasParameterOfType (0, "System", "Type")
- && calledMethod.Parameters.Count == 1
- => IntrinsicId.Expression_New,
-
- // static System.Type.GetType (string)
- // static System.Type.GetType (string, Boolean)
- // static System.Type.GetType (string, Boolean, Boolean)
- // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>)
- // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
- // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
- "GetType" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- => IntrinsicId.Type_GetType,
-
- // System.Type.GetConstructor (Type[])
- // System.Type.GetConstructor (BindingFlags, Type[])
- // System.Type.GetConstructor (BindingFlags, Binder, Type[], ParameterModifier [])
- // System.Type.GetConstructor (BindingFlags, Binder, CallingConventions, Type[], ParameterModifier [])
- "GetConstructor" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasThis
- => IntrinsicId.Type_GetConstructor,
-
- // System.Type.GetConstructors (BindingFlags)
- "GetConstructors" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection", "BindingFlags")
- && calledMethod.Parameters.Count == 1
- && calledMethod.HasThis
- => IntrinsicId.Type_GetConstructors,
-
- // System.Type.GetMethod (string)
- // System.Type.GetMethod (string, BindingFlags)
- // System.Type.GetMethod (string, Type[])
- // System.Type.GetMethod (string, Type[], ParameterModifier[])
- // System.Type.GetMethod (string, BindingFlags, Type[])
- // System.Type.GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
- // System.Type.GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
- // System.Type.GetMethod (string, int, Type[])
- // System.Type.GetMethod (string, int, Type[], ParameterModifier[]?)
- // System.Type.GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
- // System.Type.GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
- "GetMethod" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasThis
- => IntrinsicId.Type_GetMethod,
-
- // System.Type.GetMethods (BindingFlags)
- "GetMethods" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection", "BindingFlags")
- && calledMethod.Parameters.Count == 1
- && calledMethod.HasThis
- => IntrinsicId.Type_GetMethods,
-
- // System.Type.GetField (string)
- // System.Type.GetField (string, BindingFlags)
- "GetField" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasThis
- => IntrinsicId.Type_GetField,
-
- // System.Type.GetFields (BindingFlags)
- "GetFields" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection", "BindingFlags")
- && calledMethod.Parameters.Count == 1
- && calledMethod.HasThis
- => IntrinsicId.Type_GetFields,
-
- // System.Type.GetEvent (string)
- // System.Type.GetEvent (string, BindingFlags)
- "GetEvent" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasThis
- => IntrinsicId.Type_GetEvent,
-
- // System.Type.GetEvents (BindingFlags)
- "GetEvents" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection", "BindingFlags")
- && calledMethod.Parameters.Count == 1
- && calledMethod.HasThis
- => IntrinsicId.Type_GetEvents,
-
- // System.Type.GetNestedType (string)
- // System.Type.GetNestedType (string, BindingFlags)
- "GetNestedType" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasThis
- => IntrinsicId.Type_GetNestedType,
-
- // System.Type.GetNestedTypes (BindingFlags)
- "GetNestedTypes" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection", "BindingFlags")
- && calledMethod.Parameters.Count == 1
- && calledMethod.HasThis
- => IntrinsicId.Type_GetNestedTypes,
-
- // System.Type.GetMember (String)
- // System.Type.GetMember (String, BindingFlags)
- // System.Type.GetMember (String, MemberTypes, BindingFlags)
- "GetMember" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasThis
- && (calledMethod.Parameters.Count == 1 ||
- (calledMethod.Parameters.Count == 2 && calledMethod.HasParameterOfType (1, "System.Reflection", "BindingFlags")) ||
- (calledMethod.Parameters.Count == 3 && calledMethod.HasParameterOfType (2, "System.Reflection", "BindingFlags")))
- => IntrinsicId.Type_GetMember,
-
- // System.Type.GetMembers (BindingFlags)
- "GetMembers" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection", "BindingFlags")
- && calledMethod.Parameters.Count == 1
- && calledMethod.HasThis
- => IntrinsicId.Type_GetMembers,
-
- // System.Type.GetInterface (string)
- // System.Type.GetInterface (string, bool)
- "GetInterface" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasThis
- && (calledMethod.Parameters.Count == 1 ||
- (calledMethod.Parameters.Count == 2 && calledMethod.HasParameterOfType (1, "System", "Boolean")))
- => IntrinsicId.Type_GetInterface,
-
- // System.Type.AssemblyQualifiedName
- "get_AssemblyQualifiedName" when calledMethod.IsDeclaredOnType ("System", "Type")
- && !calledMethod.HasParameters
- && calledMethod.HasThis
- => IntrinsicId.Type_get_AssemblyQualifiedName,
-
- // System.Type.UnderlyingSystemType
- "get_UnderlyingSystemType" when calledMethod.IsDeclaredOnType ("System", "Type")
- && !calledMethod.HasParameters
- && calledMethod.HasThis
- => IntrinsicId.Type_get_UnderlyingSystemType,
-
- // System.Type.BaseType
- "get_BaseType" when calledMethod.IsDeclaredOnType ("System", "Type")
- && !calledMethod.HasParameters
- && calledMethod.HasThis
- => IntrinsicId.Type_get_BaseType,
-
- // System.Type.GetProperty (string)
- // System.Type.GetProperty (string, BindingFlags)
- // System.Type.GetProperty (string, Type)
- // System.Type.GetProperty (string, Type[])
- // System.Type.GetProperty (string, Type, Type[])
- // System.Type.GetProperty (string, Type, Type[], ParameterModifier[])
- // System.Type.GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
- "GetProperty" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasThis
- => IntrinsicId.Type_GetProperty,
-
- // System.Type.GetProperties (BindingFlags)
- "GetProperties" when calledMethod.IsDeclaredOnType ("System", "Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection", "BindingFlags")
- && calledMethod.Parameters.Count == 1
- && calledMethod.HasThis
- => IntrinsicId.Type_GetProperties,
-
- // static System.Object.GetType ()
- "GetType" when calledMethod.IsDeclaredOnType ("System", "Object")
- => IntrinsicId.Object_GetType,
-
- ".ctor" when calledMethod.IsDeclaredOnType ("System.Reflection", "TypeDelegator")
- && calledMethod.HasParameterOfType (0, "System", "Type")
- => IntrinsicId.TypeDelegator_Ctor,
-
- "Empty" when calledMethod.IsDeclaredOnType ("System", "Array")
- => IntrinsicId.Array_Empty,
-
- // static System.Activator.CreateInstance (System.Type type)
- // static System.Activator.CreateInstance (System.Type type, bool nonPublic)
- // static System.Activator.CreateInstance (System.Type type, params object?[]? args)
- // static System.Activator.CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
- // static System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
- // static System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
- "CreateInstance" when calledMethod.IsDeclaredOnType ("System", "Activator")
- && !calledMethod.ContainsGenericParameter
- && calledMethod.HasParameterOfType (0, "System", "Type")
- => IntrinsicId.Activator_CreateInstance_Type,
-
- // static System.Activator.CreateInstance (string assemblyName, string typeName)
- // static System.Activator.CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
- // static System.Activator.CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
- "CreateInstance" when calledMethod.IsDeclaredOnType ("System", "Activator")
- && !calledMethod.ContainsGenericParameter
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName,
-
- // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName)
- // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- "CreateInstanceFrom" when calledMethod.IsDeclaredOnType ("System", "Activator")
- && !calledMethod.ContainsGenericParameter
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.Activator_CreateInstanceFrom,
-
- // static T System.Activator.CreateInstance<T> ()
- "CreateInstance" when calledMethod.IsDeclaredOnType ("System", "Activator")
- && calledMethod.ContainsGenericParameter
- && calledMethod.GenericParameters.Count == 1
- && calledMethod.Parameters.Count == 0
- => IntrinsicId.Activator_CreateInstanceOfT,
-
- // System.AppDomain.CreateInstance (string assemblyName, string typeName)
- // System.AppDomain.CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
- "CreateInstance" when calledMethod.IsDeclaredOnType ("System", "AppDomain")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstance,
-
- // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName)
- // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
- "CreateInstanceAndUnwrap" when calledMethod.IsDeclaredOnType ("System", "AppDomain")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstanceAndUnwrap,
-
- // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName)
- // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- "CreateInstanceFrom" when calledMethod.IsDeclaredOnType ("System", "AppDomain")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstanceFrom,
-
- // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
- // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
- "CreateInstanceFromAndUnwrap" when calledMethod.IsDeclaredOnType ("System", "AppDomain")
- && calledMethod.HasParameterOfType (0, "System", "String")
- && calledMethod.HasParameterOfType (1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap,
-
- // System.Reflection.Assembly.CreateInstance (string typeName)
- // System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase)
- // System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
- "CreateInstance" when calledMethod.IsDeclaredOnType ("System.Reflection", "Assembly")
- && calledMethod.HasParameterOfType (0, "System", "String")
- => IntrinsicId.Assembly_CreateInstance,
-
- // System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (RuntimeTypeHandle type)
- "RunClassConstructor" when calledMethod.IsDeclaredOnType ("System.Runtime.CompilerServices", "RuntimeHelpers")
- && calledMethod.HasParameterOfType (0, "System", "RuntimeTypeHandle")
- => IntrinsicId.RuntimeHelpers_RunClassConstructor,
-
- // System.Reflection.MethodInfo.MakeGenericMethod (Type[] typeArguments)
- "MakeGenericMethod" when calledMethod.IsDeclaredOnType ("System.Reflection", "MethodInfo")
- && calledMethod.HasThis
- && calledMethod.Parameters.Count == 1
- => IntrinsicId.MethodInfo_MakeGenericMethod,
-
- _ => IntrinsicId.None,
- };
- }
-
- public override bool HandleCall (MethodBody callingMethodBody, MethodReference calledMethod, Instruction operation, ValueNodeList methodParams, out ValueNode? methodReturnValue)
- {
- methodReturnValue = null;
+ methodReturnValue = new ();
+ MultiValue? maybeMethodReturnValue = null;
var reflectionProcessed = _markStep.ProcessReflectionDependency (callingMethodBody, operation);
if (reflectionProcessed)
@@ -640,1086 +241,69 @@ namespace Mono.Linker.Dataflow
if (calledMethodDefinition == null)
return false;
- _scopeStack.UpdateCurrentScopeInstructionOffset (operation.Offset);
- var reflectionContext = new ReflectionPatternContext (
- _context,
- ShouldEnableReflectionPatternReporting (),
- _scopeStack.CurrentScope.Origin,
- calledMethodDefinition,
- operation);
-
- DynamicallyAccessedMemberTypes returnValueDynamicallyAccessedMemberTypes = 0;
-
- try {
-
- bool requiresDataFlowAnalysis = _context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis (calledMethodDefinition);
- returnValueDynamicallyAccessedMemberTypes = requiresDataFlowAnalysis ?
- _context.Annotations.FlowAnnotations.GetReturnParameterAnnotation (calledMethodDefinition) : 0;
-
- switch (GetIntrinsicIdForMethod (calledMethodDefinition)) {
- case IntrinsicId.IntrospectionExtensions_GetTypeInfo: {
- // typeof(Foo).GetTypeInfo()... will be commonly present in code targeting
- // the dead-end reflection refactoring. The call doesn't do anything and we
- // don't want to lose the annotation.
- methodReturnValue = methodParams[0];
- }
- break;
-
- case IntrinsicId.TypeInfo_AsType: {
- // someType.AsType()... will be commonly present in code targeting
- // the dead-end reflection refactoring. The call doesn't do anything and we
- // don't want to lose the annotation.
- methodReturnValue = methodParams[0];
- }
- break;
-
- case IntrinsicId.TypeDelegator_Ctor: {
- // This is an identity function for analysis purposes
- if (operation.OpCode == OpCodes.Newobj)
- methodReturnValue = methodParams[1];
- }
- break;
-
- case IntrinsicId.Array_Empty: {
- methodReturnValue = new ArrayValue (new ConstIntValue (0), ((GenericInstanceMethod) calledMethod).GenericArguments[0]);
- }
- break;
-
- case IntrinsicId.Type_GetTypeFromHandle: {
- // Infrastructure piece to support "typeof(Foo)"
- if (methodParams[0] is RuntimeTypeHandleValue typeHandle)
- methodReturnValue = new SystemTypeValue (typeHandle.TypeRepresented);
- else if (methodParams[0] is RuntimeTypeHandleForGenericParameterValue typeHandleForGenericParameter) {
- methodReturnValue = new SystemTypeForGenericParameterValue (
- typeHandleForGenericParameter.GenericParameter,
- _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (typeHandleForGenericParameter.GenericParameter));
- }
- }
- break;
-
- case IntrinsicId.Type_get_TypeHandle: {
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue typeValue)
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new RuntimeTypeHandleValue (typeValue.TypeRepresented));
- else if (value == NullValue.Instance)
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, value);
- else
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, UnknownValue.Instance);
- }
- }
- break;
-
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
- case IntrinsicId.MethodBase_GetMethodFromHandle: {
- // Infrastructure piece to support "ldtoken method -> GetMethodFromHandle"
- if (methodParams[0] is RuntimeMethodHandleValue methodHandle)
- methodReturnValue = new SystemReflectionMethodBaseValue (methodHandle.MethodRepresented);
- }
- break;
-
- //
- // System.Type
- //
- // Type MakeGenericType (params Type[] typeArguments)
- //
- case IntrinsicId.Type_MakeGenericType: {
- reflectionContext.AnalyzingPattern ();
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue typeValue) {
- if (AnalyzeGenericInstantiationTypeArray (methodParams[1], ref reflectionContext, calledMethodDefinition, typeValue.TypeRepresented.GenericParameters)) {
- reflectionContext.RecordHandledPattern ();
- } else {
- bool hasUncheckedAnnotation = false;
- foreach (var genericParameter in typeValue.TypeRepresented.GenericParameters) {
- if (_context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameter) != DynamicallyAccessedMemberTypes.None ||
- (genericParameter.HasDefaultConstructorConstraint && !typeValue.TypeRepresented.IsTypeOf ("System", "Nullable`1"))) {
- // If we failed to analyze the array, we go through the analyses again
- // and intentionally ignore one particular annotation:
- // Special case: Nullable<T> where T : struct
- // The struct constraint in C# implies new() constraints, but Nullable doesn't make a use of that part.
- // There are several places even in the framework where typeof(Nullable<>).MakeGenericType would warn
- // without any good reason to do so.
- hasUncheckedAnnotation = true;
- break;
- }
- }
- if (hasUncheckedAnnotation) {
- reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericType,
- new DiagnosticString (DiagnosticId.MakeGenericType).GetMessage (calledMethodDefinition.GetDisplayName ()));
- }
- }
-
- // We haven't found any generic parameters with annotations, so there's nothing to validate.
- reflectionContext.RecordHandledPattern ();
- } else if (value == NullValue.Instance)
- reflectionContext.RecordHandledPattern ();
- else {
- // We have no way to "include more" to fix this if we don't know, so we have to warn
- reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericType,
- new DiagnosticString (DiagnosticId.MakeGenericType).GetMessage (calledMethodDefinition.GetDisplayName ()));
- }
- }
-
- // We don't want to lose track of the type
- // in case this is e.g. Activator.CreateInstance(typeof(Foo<>).MakeGenericType(...));
- methodReturnValue = methodParams[0];
- }
- break;
-
- //
- // System.Reflection.RuntimeReflectionExtensions
- //
- // static GetRuntimeEvent (this Type type, string name)
- // static GetRuntimeField (this Type type, string name)
- // static GetRuntimeMethod (this Type type, string name, Type[] parameters)
- // static GetRuntimeProperty (this Type type, string name)
- //
- case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty: {
-
- reflectionContext.AnalyzingPattern ();
- BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
- DynamicallyAccessedMemberTypes requiredMemberTypes = getRuntimeMember switch {
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent => DynamicallyAccessedMemberTypes.PublicEvents,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField => DynamicallyAccessedMemberTypes.PublicFields,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod => DynamicallyAccessedMemberTypes.PublicMethods,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty => DynamicallyAccessedMemberTypes.PublicProperties,
- _ => throw new InternalErrorException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
-
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1].UniqueValues ()) {
- if (stringParam is KnownStringValue stringValue) {
- switch (getRuntimeMember) {
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent:
- MarkEventsOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, e => e.Name == stringValue.Contents, bindingFlags);
- reflectionContext.RecordHandledPattern ();
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField:
- MarkFieldsOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, f => f.Name == stringValue.Contents, bindingFlags);
- reflectionContext.RecordHandledPattern ();
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod:
- ProcessGetMethodByName (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, bindingFlags, ref methodReturnValue);
- reflectionContext.RecordHandledPattern ();
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
- MarkPropertiesOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, p => p.Name == stringValue.Contents, bindingFlags);
- reflectionContext.RecordHandledPattern ();
- break;
- default:
- throw new InternalErrorException ($"Error processing reflection call '{calledMethod.GetDisplayName ()}' inside {callingMethodDefinition.GetDisplayName ()}. Unexpected member kind.");
- }
- } else {
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethod.Parameters[0]);
- }
- }
- } else {
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethod.Parameters[0]);
- }
- }
- }
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static Call (Type, String, Type[], Expression[])
- //
- case IntrinsicId.Expression_Call: {
- reflectionContext.AnalyzingPattern ();
- BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
-
- bool hasTypeArguments = (methodParams[2] as ArrayValue)?.Size.AsConstInt () != 0;
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1].UniqueValues ()) {
- if (stringParam is KnownStringValue stringValue) {
- foreach (var method in systemTypeValue.TypeRepresented.GetMethodsOnTypeHierarchy (_context, m => m.Name == stringValue.Contents, bindingFlags)) {
- ValidateGenericMethodInstantiation (ref reflectionContext, method, methodParams[2], calledMethod);
- MarkMethod (ref reflectionContext, method);
- }
-
- reflectionContext.RecordHandledPattern ();
- } else {
- if (hasTypeArguments) {
- // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
- // that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
- new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
- }
-
- RequireDynamicallyAccessedMembers (
- ref reflectionContext,
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags),
- value,
- calledMethod.Parameters[0]);
- }
- }
- } else {
- if (hasTypeArguments) {
- // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
- // that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
- new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
- }
-
- RequireDynamicallyAccessedMembers (
- ref reflectionContext,
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags),
- value,
- calledMethod.Parameters[0]);
- }
- }
- }
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static Property (Expression, MethodInfo)
- //
- case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection", "MethodInfo"): {
- reflectionContext.AnalyzingPattern ();
-
- foreach (var value in methodParams[1].UniqueValues ()) {
- if (value is SystemReflectionMethodBaseValue methodBaseValue) {
- // We have one of the accessors for the property. The Expression.Property will in this case search
- // for the matching PropertyInfo and store that. So to be perfectly correct we need to mark the
- // respective PropertyInfo as "accessed via reflection".
- if (methodBaseValue.MethodRepresented.TryGetProperty (out PropertyDefinition? propertyDefinition)) {
- MarkProperty (ref reflectionContext, propertyDefinition);
- continue;
- }
- } else if (value == NullValue.Instance) {
- reflectionContext.RecordHandledPattern ();
- continue;
- }
-
- // In all other cases we may not even know which type this is about, so there's nothing we can do
- // report it as a warning.
- reflectionContext.RecordUnrecognizedPattern (
- 2103, string.Format (Resources.Strings.IL2103,
- DiagnosticUtilities.GetParameterNameForErrorMessage (calledMethod.Parameters[1]),
- DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
- }
- }
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static Field (Expression, Type, String)
- // static Property (Expression, Type, String)
- //
- case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property: {
- reflectionContext.AnalyzingPattern ();
- DynamicallyAccessedMemberTypes memberTypes = fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property
- ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties
- : DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields;
-
- foreach (var value in methodParams[1].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[2].UniqueValues ()) {
- if (stringParam is KnownStringValue stringValue) {
- BindingFlags bindingFlags = methodParams[0]?.Kind == ValueNodeKind.Null ? BindingFlags.Static : BindingFlags.Default;
- if (fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property) {
- MarkPropertiesOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, filter: p => p.Name == stringValue.Contents, bindingFlags);
- } else {
- MarkFieldsOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, filter: f => f.Name == stringValue.Contents, bindingFlags);
- }
-
- reflectionContext.RecordHandledPattern ();
- } else {
- RequireDynamicallyAccessedMembers (ref reflectionContext, memberTypes, value, calledMethod.Parameters[2]);
- }
- }
- } else {
- RequireDynamicallyAccessedMembers (ref reflectionContext, memberTypes, value, calledMethod.Parameters[1]);
- }
- }
- }
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static New (Type)
- //
- case IntrinsicId.Expression_New: {
- reflectionContext.AnalyzingPattern ();
-
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- MarkConstructorsOnType (ref reflectionContext, systemTypeValue.TypeRepresented, null, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- reflectionContext.RecordHandledPattern ();
- } else {
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, value, calledMethod.Parameters[0]);
- }
- }
- }
- break;
-
- //
- // System.Object
- //
- // GetType()
- //
- case IntrinsicId.Object_GetType: {
- foreach (var valueNode in methodParams[0].UniqueValues ()) {
- // Note that valueNode can be statically typed in IL as some generic argument type.
- // For example:
- // void Method<T>(T instance) { instance.GetType().... }
- // Currently this case will end up with null StaticType - since there's no typedef for the generic argument type.
- // But it could be that T is annotated with for example PublicMethods:
- // void Method<[DAM(PublicMethods)] T>(T instance) { instance.GetType().GetMethod("Test"); }
- // In this case it's in theory possible to handle it, by treating the T basically as a base class
- // for the actual type of "instance". But the analysis for this would be pretty complicated (as the marking
- // has to happen on the callsite, which doesn't know that GetType() will be used...).
- // For now we're intentionally ignoring this case - it will produce a warning.
- // The counter example is:
- // Method<Base>(new Derived);
- // In this case to get correct results, trimmer would have to mark all public methods on Derived. Which
- // currently it won't do.
-
- TypeDefinition? staticType = valueNode.StaticType;
- 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
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethod));
- } else if (staticType.IsSealed || staticType.IsTypeOf ("System", "Delegate")) {
- // We can treat this one the same as if it was a typeof() expression
-
- // We can allow Object.GetType to be modeled as System.Delegate because we keep all methods
- // on delegates anyway so reflection on something this approximation would miss is actually safe.
-
- // We ignore the fact that the type can be annotated (see below for handling of annotated types)
- // This means the annotations (if any) won't be applied - instead we rely on the exact knowledge
- // of the type. So for example even if the type is annotated with PublicMethods
- // but the code calls GetProperties on it - it will work - mark properties, don't mark methods
- // since we ignored the fact that it's annotated.
- // This can be seen a little bit as a violation of the annotation, but we already have similar cases
- // where a parameter is annotated and if something in the method sets a specific known type to it
- // we will also make it just work, even if the annotation doesn't match the usage.
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new SystemTypeValue (staticType));
- } else {
- reflectionContext.AnalyzingPattern ();
-
- // Make sure the type is marked (this will mark it as used via reflection, which is sort of true)
- // This should already be true for most cases (method params, fields, ...), but just in case
- MarkType (ref reflectionContext, staticType);
-
- var annotation = _markStep.DynamicallyAccessedMembersTypeHierarchy
- .ApplyDynamicallyAccessedMembersToTypeHierarchy (this, staticType);
-
- reflectionContext.RecordHandledPattern ();
-
- // 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.
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethod, annotation));
- }
- }
- }
- break;
-
- //
- // System.Type
- //
- // GetType (string)
- // GetType (string, Boolean)
- // GetType (string, Boolean, Boolean)
- // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>)
- // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
- // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
- //
- case IntrinsicId.Type_GetType: {
- reflectionContext.AnalyzingPattern ();
-
- var parameters = calledMethod.Parameters;
- if ((parameters.Count == 3 && parameters[2].ParameterType.MetadataType == MetadataType.Boolean && methodParams[2].AsConstInt () != 0) ||
- (parameters.Count == 5 && methodParams[4].AsConstInt () != 0)) {
- reflectionContext.RecordUnrecognizedPattern (2096, $"Call to '{calledMethod.GetDisplayName ()}' can perform case insensitive lookup of the type, currently ILLink can not guarantee presence of all the matching types");
- break;
- }
- foreach (var typeNameValue in methodParams[0].UniqueValues ()) {
- if (typeNameValue is KnownStringValue knownStringValue) {
- if (!_context.TypeNameResolver.TryResolveTypeName (knownStringValue.Contents, callingMethodDefinition, out TypeReference? foundTypeRef, out AssemblyDefinition? typeAssembly, false)
- || ResolveToTypeDefinition (foundTypeRef) is not TypeDefinition foundType) {
- // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
- reflectionContext.RecordHandledPattern ();
- } else {
- reflectionContext.RecordRecognizedPattern (foundType, () => _markStep.MarkTypeVisibleToReflection (foundTypeRef, foundType, new DependencyInfo (DependencyKind.AccessedViaReflection, callingMethodDefinition)));
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new SystemTypeValue (foundType));
- _context.MarkingHelpers.MarkMatchingExportedType (foundType, typeAssembly, new DependencyInfo (DependencyKind.AccessedViaReflection, foundType), reflectionContext.Origin);
- }
- } else if (typeNameValue == NullValue.Instance) {
- reflectionContext.RecordHandledPattern ();
- } else if (typeNameValue is LeafValueWithDynamicallyAccessedMemberNode valueWithDynamicallyAccessedMember && valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes != 0) {
- // Propagate the annotation from the type name to the return value. Annotation on a string value will be fullfilled 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.
- reflectionContext.RecordHandledPattern ();
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethodDefinition, valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes));
- } else {
- reflectionContext.RecordUnrecognizedPattern (2057, $"Unrecognized value passed to the parameter 'typeName' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type.");
- }
- }
-
- }
- break;
-
- //
- // GetConstructor (Type[])
- // GetConstructor (BindingFlags, Type[])
- // GetConstructor (BindingFlags, Binder, Type[], ParameterModifier [])
- // GetConstructor (BindingFlags, Binder, CallingConventions, Type[], ParameterModifier [])
- //
- case IntrinsicId.Type_GetConstructor: {
- reflectionContext.AnalyzingPattern ();
-
- var parameters = calledMethod.Parameters;
- BindingFlags? bindingFlags;
- if (parameters.Count > 1 && calledMethod.Parameters[0].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[1]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Public | BindingFlags.Instance;
-
- int? ctorParameterCount = parameters.Count switch {
- 1 => (methodParams[1] as ArrayValue)?.Size.AsConstInt (),
- 2 => (methodParams[2] as ArrayValue)?.Size.AsConstInt (),
- 4 => (methodParams[3] as ArrayValue)?.Size.AsConstInt (),
- 5 => (methodParams[4] as ArrayValue)?.Size.AsConstInt (),
- _ => null,
- };
-
- // Go over all types we've seen
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- if (BindingFlagsAreUnsupported (bindingFlags)) {
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors, value, calledMethodDefinition);
- } else {
- if (HasBindingFlag (bindingFlags, BindingFlags.Public) && !HasBindingFlag (bindingFlags, BindingFlags.NonPublic)
- && ctorParameterCount == 0) {
- MarkConstructorsOnType (ref reflectionContext, systemTypeValue.TypeRepresented, m => m.IsPublic && m.Parameters.Count == 0, bindingFlags);
- } else {
- MarkConstructorsOnType (ref reflectionContext, systemTypeValue.TypeRepresented, null, bindingFlags);
- }
- }
- reflectionContext.RecordHandledPattern ();
- } else {
- // Otherwise fall back to the bitfield requirements
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags);
- // We can scope down the public constructors requirement if we know the number of parameters is 0
- if (requiredMemberTypes == DynamicallyAccessedMemberTypes.PublicConstructors && ctorParameterCount == 0)
- requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethodDefinition);
- }
- }
- }
- break;
-
- //
- // GetMethod (string)
- // GetMethod (string, BindingFlags)
- // GetMethod (string, Type[])
- // GetMethod (string, Type[], ParameterModifier[])
- // GetMethod (string, BindingFlags, Type[])
- // GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
- // GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
- // GetMethod (string, int, Type[])
- // GetMethod (string, int, Type[], ParameterModifier[]?)
- // GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
- // GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
- //
- case IntrinsicId.Type_GetMethod: {
- reflectionContext.AnalyzingPattern ();
-
- BindingFlags? bindingFlags;
- if (calledMethod.Parameters.Count > 1 && calledMethod.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else if (calledMethod.Parameters.Count > 2 && calledMethod.Parameters[2].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[3]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags);
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1].UniqueValues ()) {
- if (stringParam is KnownStringValue stringValue) {
- if (BindingFlagsAreUnsupported (bindingFlags)) {
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods, value, calledMethodDefinition);
- } else {
- ProcessGetMethodByName (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, bindingFlags, ref methodReturnValue);
- }
-
- reflectionContext.RecordHandledPattern ();
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethodDefinition);
- }
- }
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethodDefinition);
- }
- }
- }
- break;
-
- //
- // GetNestedType (string)
- // GetNestedType (string, BindingFlags)
- //
- case IntrinsicId.Type_GetNestedType: {
- reflectionContext.AnalyzingPattern ();
-
- BindingFlags? bindingFlags;
- if (calledMethod.Parameters.Count > 1 && calledMethod.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags);
- bool everyParentTypeHasAll = true;
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1].UniqueValues ()) {
- if (stringParam is KnownStringValue stringValue) {
- if (BindingFlagsAreUnsupported (bindingFlags))
- // We have chosen not to populate the methodReturnValue for now
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes, value, calledMethodDefinition);
- else {
- TypeDefinition[]? matchingNestedTypes = MarkNestedTypesOnType (ref reflectionContext, systemTypeValue.TypeRepresented, m => m.Name == stringValue.Contents, bindingFlags);
-
- if (matchingNestedTypes != null) {
- for (int i = 0; i < matchingNestedTypes.Length; i++)
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new SystemTypeValue (matchingNestedTypes[i]));
- }
- }
- reflectionContext.RecordHandledPattern ();
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethodDefinition);
- }
- }
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethodDefinition);
- }
-
- if (value is LeafValueWithDynamicallyAccessedMemberNode leafValueWithDynamicallyAccessedMember) {
- if (leafValueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.All)
- everyParentTypeHasAll = false;
- } else if (!(value is NullValue || value is SystemTypeValue)) {
- // Known Type values are always OK - either they're fully resolved above and thus the return value
- // is set to the known resolved type, or if they're not resolved, they won't exist at runtime
- // and will cause exceptions - and thus don't introduce new requirements on marking.
- // nulls are intentionally ignored as they will lead to exceptions at runtime
- // and thus don't introduce new requirements on marking.
- everyParentTypeHasAll = false;
- }
- }
-
- // If the parent type (all the possible values) has DynamicallyAccessedMemberTypes.All it means its nested types are also fully marked
- // (see MarkStep.MarkEntireType - it will recursively mark entire type on nested types). In that case we can annotate
- // the returned type (the nested type) with DynamicallyAccessedMemberTypes.All as well.
- // Note it's OK to blindly overwrite any potential annotation on the return value from the method definition
- // since DynamicallyAccessedMemberTypes.All is a superset of any other annotation.
- if (everyParentTypeHasAll && methodReturnValue == null)
- methodReturnValue = CreateMethodReturnValue (calledMethodDefinition, DynamicallyAccessedMemberTypes.All);
- }
- break;
-
- //
- // AssemblyQualifiedName
- //
- case IntrinsicId.Type_get_AssemblyQualifiedName: {
- ValueNode? transformedResult = null;
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is LeafValueWithDynamicallyAccessedMemberNode dynamicallyAccessedThing) {
- var annotatedString = new AnnotatedStringValue (dynamicallyAccessedThing.SourceContext, dynamicallyAccessedThing.DynamicallyAccessedMemberTypes);
- transformedResult = MergePointValue.MergeValues (transformedResult, annotatedString);
- } else {
- transformedResult = null;
- break;
- }
- }
-
- if (transformedResult != null) {
- methodReturnValue = transformedResult;
- }
- }
- break;
-
- //
- // UnderlyingSystemType
- //
- case IntrinsicId.Type_get_UnderlyingSystemType: {
- // This is identity for the purposes of the analysis.
- methodReturnValue = methodParams[0];
- }
- break;
-
- //
- // Type.BaseType
- //
- case IntrinsicId.Type_get_BaseType: {
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is LeafValueWithDynamicallyAccessedMemberNode dynamicallyAccessedMemberNode) {
- DynamicallyAccessedMemberTypes propagatedMemberTypes = DynamicallyAccessedMemberTypes.None;
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
- propagatedMemberTypes = DynamicallyAccessedMemberTypes.All;
- else {
- // PublicConstructors are not propagated to base type
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicEvents))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicEvents;
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicFields))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicFields;
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicMethods))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicMethods;
-
- // PublicNestedTypes are not propagated to base type
-
- // PublicParameterlessConstructor is not propagated to base type
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicProperties))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicProperties;
- }
-
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethod, propagatedMemberTypes));
- } else if (value is SystemTypeValue systemTypeValue) {
- if (systemTypeValue.TypeRepresented.BaseType is TypeReference baseTypeRef && _context.TryResolve (baseTypeRef) is TypeDefinition baseTypeDefinition)
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new SystemTypeValue (baseTypeDefinition));
- else
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethod));
- } else if (value == NullValue.Instance) {
- // Ignore nulls - null.BaseType will fail at runtime, but it has no effect on static analysis
- continue;
- } else {
- // Unknown input - propagate a return value without any annotation - we know it's a Type but we know nothing about it
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethod));
- }
- }
- }
- break;
-
- //
- // GetField (string)
- // GetField (string, BindingFlags)
- // GetEvent (string)
- // GetEvent (string, BindingFlags)
- // GetProperty (string)
- // GetProperty (string, BindingFlags)
- // GetProperty (string, Type)
- // GetProperty (string, Type[])
- // GetProperty (string, Type, Type[])
- // GetProperty (string, Type, Type[], ParameterModifier[])
- // GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
- //
- case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
- && calledMethod.DeclaringType.Namespace == "System"
- && calledMethod.DeclaringType.Name == "Type"
- && calledMethod.Parameters[0].ParameterType.FullName == "System.String"
- && calledMethod.HasThis: {
-
- reflectionContext.AnalyzingPattern ();
- BindingFlags? bindingFlags;
- if (calledMethod.Parameters.Count > 1 && calledMethod.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- DynamicallyAccessedMemberTypes memberTypes = fieldPropertyOrEvent switch {
- IntrinsicId.Type_GetEvent => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
- IntrinsicId.Type_GetField => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
- IntrinsicId.Type_GetProperty => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
- _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
-
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1].UniqueValues ()) {
- if (stringParam is KnownStringValue stringValue) {
- switch (fieldPropertyOrEvent) {
- case IntrinsicId.Type_GetEvent:
- if (BindingFlagsAreUnsupported (bindingFlags))
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents, value, calledMethodDefinition);
- else
- MarkEventsOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, filter: e => e.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.Type_GetField:
- if (BindingFlagsAreUnsupported (bindingFlags))
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields, value, calledMethodDefinition);
- else
- MarkFieldsOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, filter: f => f.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.Type_GetProperty:
- if (BindingFlagsAreUnsupported (bindingFlags))
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties, value, calledMethodDefinition);
- else
- MarkPropertiesOnTypeHierarchy (ref reflectionContext, systemTypeValue.TypeRepresented, filter: p => p.Name == stringValue.Contents, bindingFlags);
- break;
- default:
- Debug.Fail ("Unreachable.");
- break;
- }
- reflectionContext.RecordHandledPattern ();
- } else {
- RequireDynamicallyAccessedMembers (ref reflectionContext, memberTypes, value, calledMethodDefinition);
- }
- }
- } else {
- RequireDynamicallyAccessedMembers (ref reflectionContext, memberTypes, value, calledMethodDefinition);
- }
- }
- }
- break;
-
- //
- // GetConstructors (BindingFlags)
- // GetMethods (BindingFlags)
- // GetFields (BindingFlags)
- // GetEvents (BindingFlags)
- // GetProperties (BindingFlags)
- // GetNestedTypes (BindingFlags)
- // GetMembers (BindingFlags)
- //
- case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
- callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
- && calledMethod.DeclaringType.Namespace == "System"
- && calledMethod.DeclaringType.Name == "Type"
- && calledMethod.Parameters[0].ParameterType.FullName == "System.Reflection.BindingFlags"
- && calledMethod.HasThis: {
-
- reflectionContext.AnalyzingPattern ();
- BindingFlags? bindingFlags;
- bindingFlags = GetBindingFlagsFromValue (methodParams[1]);
- DynamicallyAccessedMemberTypes memberTypes = DynamicallyAccessedMemberTypes.None;
- if (BindingFlagsAreUnsupported (bindingFlags)) {
- memberTypes = callType switch {
- IntrinsicId.Type_GetConstructors => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors,
- IntrinsicId.Type_GetMethods => DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods,
- IntrinsicId.Type_GetEvents => DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents,
- IntrinsicId.Type_GetFields => DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields,
- IntrinsicId.Type_GetProperties => DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties,
- IntrinsicId.Type_GetNestedTypes => DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
- IntrinsicId.Type_GetMembers => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
- DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
- DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
- DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
- DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
- DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
- _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
- } else {
- memberTypes = callType switch {
- IntrinsicId.Type_GetConstructors => GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags),
- IntrinsicId.Type_GetMethods => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags),
- IntrinsicId.Type_GetEvents => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
- IntrinsicId.Type_GetFields => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
- IntrinsicId.Type_GetProperties => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
- IntrinsicId.Type_GetNestedTypes => GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags),
- IntrinsicId.Type_GetMembers => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags),
- _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
- }
-
- foreach (var value in methodParams[0].UniqueValues ()) {
- RequireDynamicallyAccessedMembers (ref reflectionContext, memberTypes, value, calledMethodDefinition);
- }
- }
- break;
-
-
- //
- // GetMember (String)
- // GetMember (String, BindingFlags)
- // GetMember (String, MemberTypes, BindingFlags)
- //
- case IntrinsicId.Type_GetMember: {
- reflectionContext.AnalyzingPattern ();
- var parameters = calledMethod.Parameters;
- BindingFlags? bindingFlags;
- if (parameters.Count == 1) {
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Public | BindingFlags.Instance;
- } else if (parameters.Count == 2 && calledMethod.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else if (parameters.Count == 3 && calledMethod.Parameters[2].ParameterType.Name == "BindingFlags") {
- bindingFlags = GetBindingFlagsFromValue (methodParams[3]);
- } else // Non recognized intrinsic
- throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is an unexpected intrinsic.");
-
- DynamicallyAccessedMemberTypes requiredMemberTypes = DynamicallyAccessedMemberTypes.None;
- if (BindingFlagsAreUnsupported (bindingFlags)) {
- requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
- DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
- DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
- DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
- DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
- DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
- } else {
- requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags);
- }
- // Go over all types we've seen
- foreach (var value in methodParams[0].UniqueValues ()) {
- // Mark based on bitfield requirements
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethodDefinition);
- }
- }
- break;
-
- //
- // GetInterface (String)
- // GetInterface (String, bool)
- //
- case IntrinsicId.Type_GetInterface: {
- reflectionContext.AnalyzingPattern ();
-
- foreach (var value in methodParams[0].UniqueValues ()) {
- // For now no support for marking a single interface by name. We would have to correctly support
- // mangled names for generics to do that correctly. Simply mark all interfaces on the type for now.
-
- // Require Interfaces annotation
- RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberTypesOverlay.Interfaces, value, calledMethodDefinition);
-
- // Interfaces is transitive, so the return values will always have at least Interfaces annotation
- DynamicallyAccessedMemberTypes returnMemberTypes = DynamicallyAccessedMemberTypesOverlay.Interfaces;
-
- // Propagate All annotation across the call - All is a superset of Interfaces
- if (value is LeafValueWithDynamicallyAccessedMemberNode annotatedNode
- && annotatedNode.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
- returnMemberTypes = DynamicallyAccessedMemberTypes.All;
-
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethod, returnMemberTypes));
- }
- }
- break;
-
- //
- // System.Activator
- //
- // static CreateInstance (System.Type type)
- // static CreateInstance (System.Type type, bool nonPublic)
- // static CreateInstance (System.Type type, params object?[]? args)
- // static CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
- // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
- // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
- //
- case IntrinsicId.Activator_CreateInstance_Type: {
- var parameters = calledMethod.Parameters;
-
- reflectionContext.AnalyzingPattern ();
-
- int? ctorParameterCount = null;
- BindingFlags bindingFlags = BindingFlags.Instance;
- if (parameters.Count > 1) {
- if (parameters[1].ParameterType.MetadataType == MetadataType.Boolean) {
- // The overload that takes a "nonPublic" bool
- bool nonPublic = true;
- if (methodParams[1] is ConstIntValue constInt) {
- nonPublic = constInt.Value != 0;
- }
-
- if (nonPublic)
- bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
- else
- bindingFlags |= BindingFlags.Public;
- ctorParameterCount = 0;
- } else {
- // Overload that has the parameters as the second or fourth argument
- int argsParam = parameters.Count == 2 || parameters.Count == 3 ? 1 : 3;
-
- if (methodParams.Count > argsParam) {
- if (methodParams[argsParam] is ArrayValue arrayValue &&
- arrayValue.Size.AsConstInt () != null)
- ctorParameterCount = arrayValue.Size.AsConstInt ();
- else if (methodParams[argsParam] is NullValue)
- ctorParameterCount = 0;
- }
-
- if (parameters.Count > 3) {
- if (methodParams[1].AsConstInt () is int constInt)
- bindingFlags |= (BindingFlags) constInt;
- else
- bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
- } else {
- bindingFlags |= BindingFlags.Public;
- }
- }
- } else {
- // The overload with a single System.Type argument
- ctorParameterCount = 0;
- bindingFlags |= BindingFlags.Public;
- }
-
- // Go over all types we've seen
- foreach (var value in methodParams[0].UniqueValues ()) {
- if (value is SystemTypeValue systemTypeValue) {
- // Special case known type values as we can do better by applying exact binding flags and parameter count.
- MarkConstructorsOnType (ref reflectionContext, systemTypeValue.TypeRepresented,
- ctorParameterCount == null ? null : m => m.Parameters.Count == ctorParameterCount, bindingFlags);
- reflectionContext.RecordHandledPattern ();
- } else {
- // Otherwise fall back to the bitfield requirements
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags);
-
- // Special case the public parameterless constructor if we know that there are 0 args passed in
- if (ctorParameterCount == 0 && requiredMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors)) {
- requiredMemberTypes &= ~DynamicallyAccessedMemberTypes.PublicConstructors;
- requiredMemberTypes |= DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
- }
-
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, value, calledMethod.Parameters[0]);
- }
- }
- }
- break;
-
- //
- // System.Activator
- //
- // static CreateInstance (string assemblyName, string typeName)
- // static CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
- // static CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
- //
- case IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName:
- ProcessCreateInstanceByName (ref reflectionContext, calledMethodDefinition, methodParams);
- break;
-
- //
- // System.Activator
- //
- // static CreateInstanceFrom (string assemblyFile, string typeName)
- // static CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // static CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- //
- case IntrinsicId.Activator_CreateInstanceFrom:
- ProcessCreateInstanceByName (ref reflectionContext, calledMethodDefinition, methodParams);
- break;
-
- //
- // System.Activator
- //
- // static T CreateInstance<T> ()
- //
- // Note: If the when condition returns false it would be an overload which we don't recognize, so just fall through to the default case
- case IntrinsicId.Activator_CreateInstanceOfT when
- calledMethod is GenericInstanceMethod genericCalledMethod && genericCalledMethod.GenericArguments.Count == 1: {
- reflectionContext.AnalyzingPattern ();
-
- if (genericCalledMethod.GenericArguments[0] is GenericParameter genericParameter &&
- genericParameter.HasDefaultConstructorConstraint) {
- // This is safe, the linker would have marked the default .ctor already
- reflectionContext.RecordHandledPattern ();
- break;
- }
-
- RequireDynamicallyAccessedMembers (
- ref reflectionContext,
- DynamicallyAccessedMemberTypes.PublicParameterlessConstructor,
- GetTypeValueNodeFromGenericArgument (genericCalledMethod.GenericArguments[0]),
- calledMethodDefinition.GenericParameters[0]);
- }
- break;
-
- //
- // System.AppDomain
- //
- // CreateInstance (string assemblyName, string typeName)
- // CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
- //
- // CreateInstanceAndUnwrap (string assemblyName, string typeName)
- // CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
- //
- // CreateInstanceFrom (string assemblyFile, string typeName)
- // CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- //
- // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
- // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
- //
- case var appDomainCreateInstance when appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstance
- || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceAndUnwrap
- || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFrom
- || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap:
- ProcessCreateInstanceByName (ref reflectionContext, calledMethodDefinition, methodParams);
- break;
-
- //
- // System.Reflection.Assembly
- //
- // CreateInstance (string typeName)
- // CreateInstance (string typeName, bool ignoreCase)
- // CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
- //
- case IntrinsicId.Assembly_CreateInstance:
- // For now always fail since we don't track assemblies (dotnet/linker/issues/1947)
- reflectionContext.AnalyzingPattern ();
- reflectionContext.RecordUnrecognizedPattern (2058, $"Parameters passed to method '{calledMethodDefinition.GetDisplayName ()}' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead.");
- break;
-
- //
- // System.Runtime.CompilerServices.RuntimeHelpers
- //
- // RunClassConstructor (RuntimeTypeHandle type)
- //
- case IntrinsicId.RuntimeHelpers_RunClassConstructor: {
- reflectionContext.AnalyzingPattern ();
- foreach (var typeHandleValue in methodParams[0].UniqueValues ()) {
- if (typeHandleValue is RuntimeTypeHandleValue runtimeTypeHandleValue) {
- _markStep.MarkStaticConstructorVisibleToReflection (runtimeTypeHandleValue.TypeRepresented, new DependencyInfo (DependencyKind.AccessedViaReflection, reflectionContext.Source));
- reflectionContext.RecordHandledPattern ();
- } else if (typeHandleValue == NullValue.Instance)
- reflectionContext.RecordHandledPattern ();
- else {
- reflectionContext.RecordUnrecognizedPattern (2059, $"Unrecognized value passed to the parameter 'type' of method '{calledMethodDefinition.GetDisplayName ()}'. It's not possible to guarantee the availability of the target static constructor.");
- }
- }
- }
- break;
-
- //
- // System.Reflection.MethodInfo
- //
- // MakeGenericMethod (Type[] typeArguments)
- //
- case IntrinsicId.MethodInfo_MakeGenericMethod: {
- reflectionContext.AnalyzingPattern ();
-
- foreach (var methodValue in methodParams[0].UniqueValues ()) {
- if (methodValue is SystemReflectionMethodBaseValue methodBaseValue) {
- ValidateGenericMethodInstantiation (ref reflectionContext, methodBaseValue.MethodRepresented, methodParams[1], calledMethod);
- } else if (methodValue == NullValue.Instance) {
- reflectionContext.RecordHandledPattern ();
- } else {
- // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
- // that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
- new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
- }
- }
-
- // MakeGenericMethod doesn't change the identity of the MethodBase we're tracking so propagate to the return value
- methodReturnValue = methodParams[0];
- }
- break;
-
- default:
+ bool requiresDataFlowAnalysis = _context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis (calledMethodDefinition);
+ DynamicallyAccessedMemberTypes returnValueDynamicallyAccessedMemberTypes = requiresDataFlowAnalysis ?
+ _context.Annotations.FlowAnnotations.GetReturnParameterAnnotation (calledMethodDefinition) : 0;
+
+ _origin = _origin.WithInstructionOffset (operation.Offset);
+ bool diagnosticsEnabled = ShouldEnableReflectionPatternReporting (_origin.Provider);
+ var diagnosticContext = new DiagnosticContext (_origin, diagnosticsEnabled, _context);
+ var handleCallAction = new HandleCallAction (_context, _reflectionMarker, diagnosticContext, callingMethodDefinition);
+ switch (Intrinsics.GetIntrinsicIdForMethod (calledMethodDefinition)) {
+ case IntrinsicId.IntrospectionExtensions_GetTypeInfo:
+ case IntrinsicId.TypeInfo_AsType:
+ case IntrinsicId.Type_get_UnderlyingSystemType:
+ case IntrinsicId.Type_GetTypeFromHandle:
+ case IntrinsicId.Type_get_TypeHandle:
+ case IntrinsicId.Type_GetInterface:
+ case IntrinsicId.Type_get_AssemblyQualifiedName:
+ case IntrinsicId.RuntimeHelpers_RunClassConstructor:
+ case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
+ callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
+ && calledMethod.DeclaringType.IsTypeOf (WellKnownType.System_Type)
+ && calledMethod.Parameters[0].ParameterType.FullName == "System.Reflection.BindingFlags"
+ && calledMethod.HasThis:
+ case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
+ && calledMethod.DeclaringType.IsTypeOf (WellKnownType.System_Type)
+ && calledMethod.Parameters[0].ParameterType.IsTypeOf (WellKnownType.System_String)
+ && calledMethod.HasThis:
+ case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
+ case IntrinsicId.Type_GetMember:
+ case IntrinsicId.Type_GetMethod:
+ case IntrinsicId.Type_GetNestedType:
+ case IntrinsicId.Nullable_GetUnderlyingType:
+ case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo"):
+ case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property:
+ case IntrinsicId.Type_get_BaseType:
+ case IntrinsicId.Type_GetConstructor:
+ case IntrinsicId.MethodBase_GetMethodFromHandle:
+ case IntrinsicId.MethodBase_get_MethodHandle:
+ case IntrinsicId.Type_MakeGenericType:
+ case IntrinsicId.MethodInfo_MakeGenericMethod:
+ case IntrinsicId.Expression_Call:
+ case IntrinsicId.Expression_New:
+ case IntrinsicId.Type_GetType:
+ case IntrinsicId.Activator_CreateInstance_Type:
+ case IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName:
+ case IntrinsicId.Activator_CreateInstanceFrom:
+ case var appDomainCreateInstance when appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstance
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceAndUnwrap
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFrom
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap:
+ case IntrinsicId.Assembly_CreateInstance: {
+ var instanceValue = MultiValueLattice.Top;
+ IReadOnlyList<MultiValue> parameterValues = methodParams;
+ if (calledMethodDefinition.HasImplicitThis ()) {
+ instanceValue = methodParams[0];
+ parameterValues = parameterValues.Skip (1).ToImmutableList ();
+ }
+ return handleCallAction.Invoke (calledMethodDefinition, instanceValue, parameterValues, out methodReturnValue, out _);
+ }
+ case IntrinsicId.None: {
if (calledMethodDefinition.IsPInvokeImpl) {
// Is the PInvoke dangerous?
bool comDangerousMethod = IsComInterop (calledMethodDefinition.MethodReturnType, calledMethodDefinition.ReturnType);
@@ -1728,62 +312,114 @@ namespace Mono.Linker.Dataflow
}
if (comDangerousMethod) {
- reflectionContext.AnalyzingPattern ();
- reflectionContext.RecordUnrecognizedPattern (2050, $"P/invoke method '{calledMethodDefinition.GetDisplayName ()}' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed.");
+ diagnosticContext.AddDiagnostic (DiagnosticId.CorrectnessOfCOMCannotBeGuaranteed, calledMethodDefinition.GetDisplayName ());
}
}
+ _markStep.CheckAndReportRequiresUnreferencedCode (calledMethodDefinition, _origin);
- if (requiresDataFlowAnalysis) {
- reflectionContext.AnalyzingPattern ();
- for (int parameterIndex = 0; parameterIndex < methodParams.Count; parameterIndex++) {
- var requiredMemberTypes = _context.Annotations.FlowAnnotations.GetParameterAnnotation (calledMethodDefinition, parameterIndex);
- if (requiredMemberTypes != 0) {
- IMetadataTokenProvider targetContext;
- if (calledMethodDefinition.HasImplicitThis ()) {
- if (parameterIndex == 0)
- targetContext = calledMethodDefinition;
- else
- targetContext = calledMethodDefinition.Parameters[parameterIndex - 1];
- } else {
- targetContext = calledMethodDefinition.Parameters[parameterIndex];
- }
+ var instanceValue = MultiValueLattice.Top;
+ IReadOnlyList<MultiValue> parameterValues = methodParams;
+ if (calledMethodDefinition.HasImplicitThis ()) {
+ instanceValue = methodParams[0];
+ parameterValues = parameterValues.Skip (1).ToImmutableList ();
+ }
+ return handleCallAction.Invoke (calledMethodDefinition, instanceValue, parameterValues, out methodReturnValue, out _);
+ }
- RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, methodParams[parameterIndex], targetContext);
- }
- }
+ case IntrinsicId.TypeDelegator_Ctor: {
+ // This is an identity function for analysis purposes
+ if (operation.OpCode == OpCodes.Newobj)
+ AddReturnValue (methodParams[1]);
+ }
+ break;
- reflectionContext.RecordHandledPattern ();
- }
+ case IntrinsicId.Array_Empty: {
+ AddReturnValue (ArrayValue.Create (0, ((GenericInstanceMethod) calledMethod).GenericArguments[0]));
+ }
+ break;
- _markStep.CheckAndReportRequiresUnreferencedCode (calledMethodDefinition);
+ //
+ // System.Object
+ //
+ // GetType()
+ //
+ case IntrinsicId.Object_GetType: {
+ foreach (var valueNode in methodParams[0]) {
+ // Note that valueNode can be statically typed in IL as some generic argument type.
+ // For example:
+ // void Method<T>(T instance) { instance.GetType().... }
+ // Currently this case will end up with null StaticType - since there's no typedef for the generic argument type.
+ // But it could be that T is annotated with for example PublicMethods:
+ // void Method<[DAM(PublicMethods)] T>(T instance) { instance.GetType().GetMethod("Test"); }
+ // In this case it's in theory possible to handle it, by treating the T basically as a base class
+ // for the actual type of "instance". But the analysis for this would be pretty complicated (as the marking
+ // has to happen on the callsite, which doesn't know that GetType() will be used...).
+ // For now we're intentionally ignoring this case - it will produce a warning.
+ // The counter example is:
+ // Method<Base>(new Derived);
+ // In this case to get correct results, trimmer would have to mark all public methods on Derived. Which
+ // currently it won't do.
+
+ TypeDefinition? staticType = (valueNode as IValueWithStaticType)?.StaticType;
+ 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 (_annotations.GetMethodReturnValue (calledMethodDefinition));
+ } else if (staticType.IsSealed || staticType.IsTypeOf ("System", "Delegate")) {
+ // We can treat this one the same as if it was a typeof() expression
+
+ // We can allow Object.GetType to be modeled as System.Delegate because we keep all methods
+ // on delegates anyway so reflection on something this approximation would miss is actually safe.
+
+ // We ignore the fact that the type can be annotated (see below for handling of annotated types)
+ // This means the annotations (if any) won't be applied - instead we rely on the exact knowledge
+ // of the type. So for example even if the type is annotated with PublicMethods
+ // but the code calls GetProperties on it - it will work - mark properties, don't mark methods
+ // since we ignored the fact that it's annotated.
+ // This can be seen a little bit as a violation of the annotation, but we already have similar cases
+ // where a parameter is annotated and if something in the method sets a specific known type to it
+ // we will also make it just work, even if the annotation doesn't match the usage.
+ AddReturnValue (new SystemTypeValue (staticType));
+ } else {
+ // Make sure the type is marked (this will mark it as used via reflection, which is sort of true)
+ // This should already be true for most cases (method params, fields, ...), but just in case
+ _reflectionMarker.MarkType (_origin, staticType);
- // To get good reporting of errors we need to track the origin of the value for all method calls
- // but except Newobj as those are special.
- if (GetReturnTypeWithoutModifiers (calledMethodDefinition.ReturnType).MetadataType != MetadataType.Void) {
- methodReturnValue = CreateMethodReturnValue (calledMethodDefinition, returnValueDynamicallyAccessedMemberTypes);
+ var annotation = _markStep.DynamicallyAccessedMembersTypeHierarchy
+ .ApplyDynamicallyAccessedMembersToTypeHierarchy (_reflectionMarker, staticType);
- return true;
+ // 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 (_annotations.GetMethodReturnValue (calledMethodDefinition, annotation));
+ }
}
-
- return false;
}
- } finally {
- reflectionContext.Dispose ();
+ break;
+
+ // Note about Activator.CreateInstance<T>
+ // There are 2 interesting cases:
+ // - The generic argument for T is either specific type or annotated - in that case generic instantiation will handle this
+ // since from .NET 6+ the T is annotated with PublicParameterlessConstructor annotation, so the linker would apply this as for any other method.
+ // - The generic argument for T is unannotated type - the generic instantiantion handling has a special case for handling PublicParameterlessConstructor requirement
+ // in such that if the generic argument type has the "new" constraint it will not warn (as it is effectively the same thing semantically).
+ // For all other cases, the linker would have already produced a warning.
+
+ default:
+ throw new NotImplementedException ("Unhandled instrinsic");
}
// If we get here, we handled this as an intrinsic. 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.
- if (methodReturnValue == null) {
- if (GetReturnTypeWithoutModifiers (calledMethod.ReturnType).MetadataType != MetadataType.Void) {
- methodReturnValue = CreateMethodReturnValue (calledMethodDefinition, returnValueDynamicallyAccessedMemberTypes);
- }
- }
+ bool returnsVoid = calledMethod.ReturnsVoid ();
+ methodReturnValue = maybeMethodReturnValue ?? (returnsVoid ?
+ MultiValueLattice.Top :
+ _annotations.GetMethodReturnValue (calledMethodDefinition, returnValueDynamicallyAccessedMemberTypes));
// Validate that the return value has the correct annotations as per the method return value annotations
if (returnValueDynamicallyAccessedMemberTypes != 0) {
- foreach (var uniqueValue in methodReturnValue.UniqueValues ()) {
- if (uniqueValue is LeafValueWithDynamicallyAccessedMemberNode methodReturnValueWithMemberTypes) {
+ foreach (var uniqueValue in methodReturnValue) {
+ if (uniqueValue is ValueWithDynamicallyAccessedMembers methodReturnValueWithMemberTypes) {
if (!methodReturnValueWithMemberTypes.DynamicallyAccessedMemberTypes.HasFlag (returnValueDynamicallyAccessedMemberTypes))
throw new InvalidOperationException ($"Internal linker error: processing of call from {callingMethodDefinition.GetDisplayName ()} to {calledMethod.GetDisplayName ()} returned value which is not correctly annotated with the expected dynamic member access kinds.");
} else if (uniqueValue is SystemTypeValue) {
@@ -1796,6 +432,11 @@ namespace Mono.Linker.Dataflow
}
return true;
+
+ void AddReturnValue (MultiValue value)
+ {
+ maybeMethodReturnValue = (maybeMethodReturnValue is null) ? value : MultiValueLattice.Meet ((MultiValue) maybeMethodReturnValue, value);
+ }
}
bool IsComInterop (IMarshalInfoProvider marshalInfoProvider, TypeReference parameterType)
@@ -1822,10 +463,10 @@ namespace Mono.Linker.Dataflow
var parameterTypeDef = _context.TryResolve (parameterType);
if (parameterTypeDef != null) {
- if (parameterTypeDef.IsTypeOf ("System", "Array")) {
+ if (parameterTypeDef.IsTypeOf (WellKnownType.System_Array)) {
// System.Array marshals as IUnknown by default
return true;
- } else if (parameterTypeDef.IsTypeOf ("System", "String") ||
+ } else if (parameterTypeDef.IsTypeOf (WellKnownType.System_String) ||
parameterTypeDef.IsTypeOf ("System.Text", "StringBuilder")) {
// String and StringBuilder are special cased by interop
return false;
@@ -1856,609 +497,10 @@ namespace Mono.Linker.Dataflow
return false;
}
- bool AnalyzeGenericInstantiationTypeArray (ValueNode? arrayParam, ref ReflectionPatternContext reflectionContext, MethodReference calledMethod, IList<GenericParameter> genericParameters)
- {
- bool hasRequirements = false;
- foreach (var genericParameter in genericParameters) {
- if (_context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameter) != DynamicallyAccessedMemberTypes.None) {
- hasRequirements = true;
- break;
- }
- }
-
- // If there are no requirements, then there's no point in warning
- if (!hasRequirements)
- return true;
-
- foreach (var typesValue in arrayParam.UniqueValues ()) {
- if (typesValue.Kind != ValueNodeKind.Array) {
- return false;
- }
- ArrayValue array = (ArrayValue) typesValue;
- int? size = array.Size.AsConstInt ();
- if (size == null || size != genericParameters.Count) {
- return false;
- }
- bool allIndicesKnown = true;
- for (int i = 0; i < size.Value; i++) {
- if (!array.IndexValues.TryGetValue (i, out ValueBasicBlockPair value) || value.Value is null or { Kind: ValueNodeKind.Unknown }) {
- allIndicesKnown = false;
- break;
- }
- }
-
- if (!allIndicesKnown) {
- return false;
- }
-
- for (int i = 0; i < size.Value; i++) {
- if (array.IndexValues.TryGetValue (i, out ValueBasicBlockPair value)) {
- RequireDynamicallyAccessedMembers (
- ref reflectionContext,
- _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameters[i]),
- value.Value,
- calledMethod.Resolve ());
- }
- }
- }
- return true;
- }
-
- void ProcessCreateInstanceByName (ref ReflectionPatternContext reflectionContext, MethodDefinition calledMethod, ValueNodeList methodParams)
- {
- reflectionContext.AnalyzingPattern ();
-
- BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
- bool parameterlessConstructor = true;
- if (calledMethod.Parameters.Count == 8 && calledMethod.Parameters[2].ParameterType.MetadataType == MetadataType.Boolean) {
- parameterlessConstructor = false;
- bindingFlags = BindingFlags.Instance;
- if (methodParams[3].AsConstInt () is int bindingFlagsInt)
- bindingFlags |= (BindingFlags) bindingFlagsInt;
- else
- bindingFlags |= BindingFlags.Public | BindingFlags.NonPublic;
- }
-
- int methodParamsOffset = calledMethod.HasImplicitThis () ? 1 : 0;
-
- foreach (var assemblyNameValue in methodParams[methodParamsOffset].UniqueValues ()) {
- if (assemblyNameValue is KnownStringValue assemblyNameStringValue) {
- foreach (var typeNameValue in methodParams[methodParamsOffset + 1].UniqueValues ()) {
- if (typeNameValue is KnownStringValue typeNameStringValue) {
- var resolvedAssembly = _context.TryResolve (assemblyNameStringValue.Contents);
- if (resolvedAssembly == null) {
- reflectionContext.RecordUnrecognizedPattern (2061, $"The assembly name '{assemblyNameStringValue.Contents}' passed to method '{calledMethod.GetDisplayName ()}' references assembly which is not available.");
- continue;
- }
-
- if (!_context.TypeNameResolver.TryResolveTypeName (resolvedAssembly, typeNameStringValue.Contents, out TypeReference? typeRef)
- || _context.TryResolve (typeRef) is not TypeDefinition resolvedType
- || typeRef is ArrayType) {
- // It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case
- // Note that we did find the assembly, so it's not a linker config problem, it's either intentional, or wrong versions of assemblies
- // but linker can't know that. In case a user tries to create an array using System.Activator we should simply ignore it, the user
- // might expect an exception to be thrown.
- reflectionContext.RecordHandledPattern ();
- continue;
- }
-
- MarkConstructorsOnType (ref reflectionContext, resolvedType, parameterlessConstructor ? m => m.Parameters.Count == 0 : null, bindingFlags);
- } else {
- reflectionContext.RecordUnrecognizedPattern (2032, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[1].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type.");
- }
- }
- } else {
- reflectionContext.RecordUnrecognizedPattern (2032, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[0].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type.");
- }
- }
- }
-
- void ProcessGetMethodByName (
- ref ReflectionPatternContext reflectionContext,
- TypeDefinition typeDefinition,
- string methodName,
- BindingFlags? bindingFlags,
- ref ValueNode? methodReturnValue)
- {
- bool foundAny = false;
- foreach (var method in typeDefinition.GetMethodsOnTypeHierarchy (_context, m => m.Name == methodName, bindingFlags)) {
- MarkMethod (ref reflectionContext, method);
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new SystemReflectionMethodBaseValue (method));
- foundAny = true;
- }
-
- // If there were no methods found the API will return null at runtime, so we should
- // track the null as a return value as well.
- // This also prevents warnings in such case, since if we don't set the return value it will be
- // "unknown" and consumers may warn.
- if (!foundAny)
- methodReturnValue = MergePointValue.MergeValues (methodReturnValue, NullValue.Instance);
- }
-
- public static DynamicallyAccessedMemberTypes GetMissingMemberTypes (DynamicallyAccessedMemberTypes requiredMemberTypes, DynamicallyAccessedMemberTypes availableMemberTypes)
- {
- if (availableMemberTypes.HasFlag (requiredMemberTypes))
- return DynamicallyAccessedMemberTypes.None;
-
- if (requiredMemberTypes == DynamicallyAccessedMemberTypes.All)
- return DynamicallyAccessedMemberTypes.All;
-
- var missingMemberTypes = requiredMemberTypes & ~availableMemberTypes;
-
- // PublicConstructors is a special case since its value is 3 - so PublicParameterlessConstructor (1) | _PublicConstructor_WithMoreThanOneParameter_ (2)
- // The above bit logic only works for value with single bit set.
- if (requiredMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors) &&
- !availableMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors))
- missingMemberTypes |= DynamicallyAccessedMemberTypes.PublicConstructors;
-
- return missingMemberTypes;
- }
-
- string GetMemberTypesString (DynamicallyAccessedMemberTypes memberTypes)
- {
- Debug.Assert (memberTypes != DynamicallyAccessedMemberTypes.None);
-
- if (memberTypes == DynamicallyAccessedMemberTypes.All)
- return $"'{nameof (DynamicallyAccessedMemberTypes)}.{nameof (DynamicallyAccessedMemberTypes.All)}'";
-
- var memberTypesList = AllDynamicallyAccessedMemberTypes
- .Where (damt => (memberTypes & damt) == damt && damt != DynamicallyAccessedMemberTypes.None)
- .ToList ();
-
- if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors))
- memberTypesList.Remove (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
-
- return string.Join (", ", memberTypesList.Select (mt => {
- string mtName = mt == DynamicallyAccessedMemberTypesOverlay.Interfaces
- ? nameof (DynamicallyAccessedMemberTypesOverlay.Interfaces)
- : mt.ToString ();
-
- return $"'{nameof (DynamicallyAccessedMemberTypes)}.{mtName}'";
- }));
- }
-
- void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionContext, DynamicallyAccessedMemberTypes requiredMemberTypes, ValueNode? value, IMetadataTokenProvider targetContext)
- {
- foreach (var uniqueValue in value.UniqueValues ()) {
- if (requiredMemberTypes == DynamicallyAccessedMemberTypes.PublicParameterlessConstructor
- && uniqueValue is SystemTypeForGenericParameterValue genericParam
- && genericParam.GenericParameter.HasDefaultConstructorConstraint) {
- // We allow a new() constraint on a generic parameter to satisfy DynamicallyAccessedMemberTypes.PublicParameterlessConstructor
- reflectionContext.RecordHandledPattern ();
- } else if (uniqueValue is LeafValueWithDynamicallyAccessedMemberNode valueWithDynamicallyAccessedMember) {
- var availableMemberTypes = valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes;
- var missingMemberTypesValue = GetMissingMemberTypes (requiredMemberTypes, availableMemberTypes);
- if (missingMemberTypesValue != DynamicallyAccessedMemberTypes.None) {
- var missingMemberTypes = GetMemberTypesString (missingMemberTypesValue);
-
- switch ((valueWithDynamicallyAccessedMember.SourceContext, targetContext)) {
- case (ParameterDefinition sourceParameter, ParameterDefinition targetParameter):
- reflectionContext.RecordUnrecognizedPattern (2067, string.Format (Resources.Strings.IL2067,
- DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method),
- DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterDefinition sourceParameter, MethodReturnType targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern (2068, string.Format (Resources.Strings.IL2068,
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method),
- DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterDefinition sourceParameter, FieldDefinition targetField):
- reflectionContext.RecordUnrecognizedPattern (2069, string.Format (Resources.Strings.IL2069,
- targetField.GetDisplayName (),
- DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterDefinition sourceParameter, MethodDefinition targetMethod):
- reflectionContext.RecordUnrecognizedPattern (2070, string.Format (Resources.Strings.IL2070,
- targetMethod.GetDisplayName (),
- DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterDefinition sourceParameter, GenericParameter targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern (2071, string.Format (Resources.Strings.IL2071,
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter),
- DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method),
- missingMemberTypes));
- break;
-
- case (MethodReturnType sourceMethodReturnType, ParameterDefinition targetParameter):
- reflectionContext.RecordUnrecognizedPattern (2072, string.Format (Resources.Strings.IL2072,
- DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnType sourceMethodReturnType, MethodReturnType targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern (2073, string.Format (Resources.Strings.IL2073,
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnType sourceMethodReturnType, FieldDefinition targetField):
- reflectionContext.RecordUnrecognizedPattern (2074, string.Format (Resources.Strings.IL2074,
- targetField.GetDisplayName (),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnType sourceMethodReturnType, MethodDefinition targetMethod):
- reflectionContext.RecordUnrecognizedPattern (2075, string.Format (Resources.Strings.IL2075,
- targetMethod.GetDisplayName (),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnType sourceMethodReturnType, GenericParameter targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern (2076, string.Format (Resources.Strings.IL2076,
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
-
- case (FieldDefinition sourceField, ParameterDefinition targetParameter):
- reflectionContext.RecordUnrecognizedPattern (2077, string.Format (Resources.Strings.IL2077,
- DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method),
- sourceField.GetDisplayName (),
- missingMemberTypes));
- break;
- case (FieldDefinition sourceField, MethodReturnType targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern (2078, string.Format (Resources.Strings.IL2078,
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method),
- sourceField.GetDisplayName (),
- missingMemberTypes));
- break;
- case (FieldDefinition sourceField, FieldDefinition targetField):
- reflectionContext.RecordUnrecognizedPattern (2079, string.Format (Resources.Strings.IL2079,
- targetField.GetDisplayName (),
- sourceField.GetDisplayName (),
- missingMemberTypes));
- break;
- case (FieldDefinition sourceField, MethodDefinition targetMethod):
- reflectionContext.RecordUnrecognizedPattern (2080, string.Format (Resources.Strings.IL2080,
- targetMethod.GetDisplayName (),
- sourceField.GetDisplayName (),
- missingMemberTypes));
- break;
- case (FieldDefinition sourceField, GenericParameter targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern (2081, string.Format (Resources.Strings.IL2081,
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter),
- sourceField.GetDisplayName (),
- missingMemberTypes));
- break;
-
- case (MethodDefinition sourceMethod, ParameterDefinition targetParameter):
- reflectionContext.RecordUnrecognizedPattern (2082, string.Format (Resources.Strings.IL2082,
- DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method),
- sourceMethod.GetDisplayName (),
- missingMemberTypes));
- break;
- case (MethodDefinition sourceMethod, MethodReturnType targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern (2083, string.Format (Resources.Strings.IL2083,
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method),
- sourceMethod.GetDisplayName (),
- missingMemberTypes));
- break;
- case (MethodDefinition sourceMethod, FieldDefinition targetField):
- reflectionContext.RecordUnrecognizedPattern (2084, string.Format (Resources.Strings.IL2084,
- targetField.GetDisplayName (),
- sourceMethod.GetDisplayName (),
- missingMemberTypes));
- break;
- case (MethodDefinition sourceMethod, MethodDefinition targetMethod):
- reflectionContext.RecordUnrecognizedPattern (2085, string.Format (Resources.Strings.IL2085,
- targetMethod.GetDisplayName (),
- sourceMethod.GetDisplayName (),
- missingMemberTypes));
- break;
- case (MethodDefinition sourceMethod, GenericParameter targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern (2086, string.Format (Resources.Strings.IL2086,
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter),
- sourceMethod.GetDisplayName (),
- missingMemberTypes));
- break;
-
- case (GenericParameter sourceGenericParameter, ParameterDefinition targetParameter):
- reflectionContext.RecordUnrecognizedPattern (2087, string.Format (Resources.Strings.IL2087,
- DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameter sourceGenericParameter, MethodReturnType targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern (2088, string.Format (Resources.Strings.IL2088,
- DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameter sourceGenericParameter, FieldDefinition targetField):
- reflectionContext.RecordUnrecognizedPattern (2089, string.Format (Resources.Strings.IL2089,
- targetField.GetDisplayName (),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameter sourceGenericParameter, MethodDefinition targetMethod):
- // Currently this is never generated, it might be possible one day if we try to validate annotations on results of reflection
- // For example code like this should ideally one day generate the warning
- // void TestMethod<T>()
- // {
- // // This passes the T as the "this" parameter to Type.GetMethods()
- // typeof(Type).GetMethod("GetMethods").Invoke(typeof(T), new object[] {});
- // }
- reflectionContext.RecordUnrecognizedPattern (2090, string.Format (Resources.Strings.IL2090,
- targetMethod.GetDisplayName (),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameter sourceGenericParameter, GenericParameter targetGenericParameter):
- reflectionContext.RecordUnrecognizedPattern (2091, string.Format (Resources.Strings.IL2091,
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter),
- missingMemberTypes));
- break;
-
- default:
- throw new NotImplementedException ($"unsupported source context {valueWithDynamicallyAccessedMember.SourceContext} or target context {targetContext}");
- };
- } else {
- reflectionContext.RecordHandledPattern ();
- }
- } else if (uniqueValue is SystemTypeValue systemTypeValue) {
- MarkTypeForDynamicallyAccessedMembers (ref reflectionContext, systemTypeValue.TypeRepresented, requiredMemberTypes, DependencyKind.DynamicallyAccessedMember);
- } else if (uniqueValue is KnownStringValue knownStringValue) {
- if (!_context.TypeNameResolver.TryResolveTypeName (knownStringValue.Contents, reflectionContext.Source, out TypeReference? typeRef, out AssemblyDefinition? typeAssembly)
- || ResolveToTypeDefinition (typeRef) is not TypeDefinition foundType) {
- // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
- reflectionContext.RecordHandledPattern ();
- } else {
- MarkType (ref reflectionContext, typeRef);
- MarkTypeForDynamicallyAccessedMembers (ref reflectionContext, foundType, requiredMemberTypes, DependencyKind.DynamicallyAccessedMember);
- _context.MarkingHelpers.MarkMatchingExportedType (foundType, typeAssembly, new DependencyInfo (DependencyKind.DynamicallyAccessedMember, foundType), reflectionContext.Origin);
- }
- } else if (uniqueValue == NullValue.Instance) {
- // Ignore - probably unreachable path as it would fail at runtime anyway.
- } else {
- switch (targetContext) {
- case ParameterDefinition parameterDefinition:
- reflectionContext.RecordUnrecognizedPattern (
- 2062,
- $"Value passed to parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (parameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (parameterDefinition.Method)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case MethodReturnType methodReturnType:
- reflectionContext.RecordUnrecognizedPattern (
- 2063,
- $"Value returned from method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodReturnType.Method)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case FieldDefinition fieldDefinition:
- reflectionContext.RecordUnrecognizedPattern (
- 2064,
- $"Value assigned to {fieldDefinition.GetDisplayName ()} can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case MethodDefinition methodDefinition:
- reflectionContext.RecordUnrecognizedPattern (
- 2065,
- $"Value passed to implicit 'this' parameter of method '{methodDefinition.GetDisplayName ()}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case GenericParameter genericParameter:
- // Unknown value to generic parameter - this is possible if the generic argument fails to resolve
- reflectionContext.RecordUnrecognizedPattern (
- 2066,
- $"Type passed to generic parameter '{genericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameter)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- default: throw new NotImplementedException ($"unsupported target context {targetContext.GetType ()}");
- };
- }
- }
-
- reflectionContext.RecordHandledPattern ();
- }
-
- static BindingFlags? GetBindingFlagsFromValue (ValueNode? parameter) => (BindingFlags?) parameter.AsConstInt ();
-
- static bool BindingFlagsAreUnsupported (BindingFlags? bindingFlags)
- {
- if (bindingFlags == null)
- return true;
-
- // Binding flags we understand
- const BindingFlags UnderstoodBindingFlags =
- BindingFlags.DeclaredOnly |
- BindingFlags.Instance |
- BindingFlags.Static |
- BindingFlags.Public |
- BindingFlags.NonPublic |
- BindingFlags.FlattenHierarchy |
- BindingFlags.ExactBinding;
-
- // Binding flags that don't affect binding outside InvokeMember (that we don't analyze).
- const BindingFlags IgnorableBindingFlags =
- BindingFlags.InvokeMethod |
- BindingFlags.CreateInstance |
- BindingFlags.GetField |
- BindingFlags.SetField |
- BindingFlags.GetProperty |
- BindingFlags.SetProperty;
-
- BindingFlags flags = bindingFlags.Value;
- return (flags & ~(UnderstoodBindingFlags | IgnorableBindingFlags)) != 0;
- }
-
- static bool HasBindingFlag (BindingFlags? bindingFlags, BindingFlags? search) => bindingFlags != null && (bindingFlags & search) == search;
-
- public void MarkTypeForDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, DependencyKind dependencyKind, bool declaredOnly = false)
+ void RequireDynamicallyAccessedMembers (in DiagnosticContext diagnosticContext, in MultiValue value, ValueWithDynamicallyAccessedMembers targetValue)
{
- foreach (var member in typeDefinition.GetDynamicallyAccessedMembers (_context, requiredMemberTypes, declaredOnly)) {
- switch (member) {
- case MethodDefinition method:
- MarkMethod (ref reflectionContext, method, dependencyKind);
- break;
- case FieldDefinition field:
- MarkField (ref reflectionContext, field, dependencyKind);
- break;
- case TypeDefinition nestedType:
- MarkType (ref reflectionContext, nestedType, dependencyKind);
- break;
- case PropertyDefinition property:
- MarkProperty (ref reflectionContext, property, dependencyKind);
- break;
- case EventDefinition @event:
- MarkEvent (ref reflectionContext, @event, dependencyKind);
- break;
- case InterfaceImplementation interfaceImplementation:
- MarkInterfaceImplementation (ref reflectionContext, interfaceImplementation, dependencyKind);
- break;
- }
- }
+ var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (_context, _reflectionMarker, diagnosticContext);
+ requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
-
- void MarkType (ref ReflectionPatternContext reflectionContext, TypeReference typeReference, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
- {
- var dependencyInfo = new DependencyInfo (dependencyKind, reflectionContext.Source);
- if (_context.TryResolve (typeReference) is TypeDefinition type)
- reflectionContext.RecordRecognizedPattern (type, () => _markStep.MarkTypeVisibleToReflection (typeReference, type, dependencyInfo));
- }
-
- void MarkMethod (ref ReflectionPatternContext reflectionContext, MethodDefinition method, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
- {
- var dependencyInfo = new DependencyInfo (dependencyKind, reflectionContext.Source);
- reflectionContext.RecordRecognizedPattern (method, () => _markStep.MarkMethodVisibleToReflection (method, dependencyInfo));
- }
-
- void MarkField (ref ReflectionPatternContext reflectionContext, FieldDefinition field, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
- {
- var dependencyInfo = new DependencyInfo (dependencyKind, reflectionContext.Source);
- reflectionContext.RecordRecognizedPattern (field, () => _markStep.MarkFieldVisibleToReflection (field, dependencyInfo));
- }
-
- void MarkProperty (ref ReflectionPatternContext reflectionContext, PropertyDefinition property, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
- {
- var dependencyInfo = new DependencyInfo (dependencyKind, reflectionContext.Source);
- reflectionContext.RecordRecognizedPattern (property, () => { _markStep.MarkPropertyVisibleToReflection (property, dependencyInfo); });
- }
-
- void MarkEvent (ref ReflectionPatternContext reflectionContext, EventDefinition @event, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
- {
- var dependencyInfo = new DependencyInfo (dependencyKind, reflectionContext.Source);
- reflectionContext.RecordRecognizedPattern (@event, () => { _markStep.MarkEventVisibleToReflection (@event, dependencyInfo); });
- }
-
- void MarkInterfaceImplementation (ref ReflectionPatternContext reflectionContext, InterfaceImplementation interfaceImplementation, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
- {
- var dependencyInfo = new DependencyInfo (dependencyKind, reflectionContext.Source);
- reflectionContext.RecordRecognizedPattern (interfaceImplementation, () => _markStep.MarkInterfaceImplementation (interfaceImplementation, null, dependencyInfo));
- }
-
- void MarkConstructorsOnType (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func<MethodDefinition, bool>? filter, BindingFlags? bindingFlags = null)
- {
- foreach (var ctor in type.GetConstructorsOnType (filter, bindingFlags))
- MarkMethod (ref reflectionContext, ctor);
- }
-
- void MarkFieldsOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func<FieldDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- foreach (var field in type.GetFieldsOnTypeHierarchy (_context, filter, bindingFlags))
- MarkField (ref reflectionContext, field);
- }
-
- TypeDefinition[]? MarkNestedTypesOnType (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func<TypeDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- var result = new ArrayBuilder<TypeDefinition> ();
-
- foreach (var nestedType in type.GetNestedTypesOnType (filter, bindingFlags)) {
- result.Add (nestedType);
- MarkType (ref reflectionContext, nestedType);
- }
-
- return result.ToArray ();
- }
-
- void MarkPropertiesOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func<PropertyDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- foreach (var property in type.GetPropertiesOnTypeHierarchy (_context, filter, bindingFlags))
- MarkProperty (ref reflectionContext, property);
- }
-
- void MarkEventsOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func<EventDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- foreach (var @event in type.GetEventsOnTypeHierarchy (_context, filter, bindingFlags))
- MarkEvent (ref reflectionContext, @event);
- }
-
- void ValidateGenericMethodInstantiation (
- ref ReflectionPatternContext reflectionContext,
- MethodDefinition genericMethod,
- ValueNode? genericParametersArray,
- MethodReference reflectionMethod)
- {
- if (!genericMethod.HasGenericParameters) {
- reflectionContext.RecordHandledPattern ();
- return;
- }
-
- if (!AnalyzeGenericInstantiationTypeArray (genericParametersArray, ref reflectionContext, reflectionMethod, genericMethod.GenericParameters)) {
- reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
- new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (reflectionMethod)));
- } else {
- reflectionContext.RecordHandledPattern ();
- }
- }
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicConstructors : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicMethods : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicFields : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicProperties : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicEvents : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None);
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (BindingFlags? bindingFlags) =>
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags);
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionPatternContext.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionPatternContext.cs
deleted file mode 100644
index 1cd64ce438f..00000000000
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ReflectionPatternContext.cs
+++ /dev/null
@@ -1,106 +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.Diagnostics;
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-
-namespace Mono.Linker.Dataflow
-{
- /// <summary>
- /// Helper struct to pass around context information about reflection pattern
- /// as a single parameter (and have a way to extend this in the future if we need to easily).
- /// Also implements a simple validation mechanism to check that the code does report patter recognition
- /// results for all methods it works on.
- /// The promise of the pattern recorder is that for a given reflection method, it will either not talk
- /// about it ever, or it will always report recognized/unrecognized.
- /// </summary>
- struct ReflectionPatternContext : IDisposable
- {
- readonly LinkContext _context;
-#if DEBUG
- bool _patternAnalysisAttempted;
- bool _patternReported;
-#endif
-
- public MessageOrigin Origin { get; init; }
- public ICustomAttributeProvider? Source { get => Origin.Provider; }
- public IMetadataTokenProvider MemberWithRequirements { get; init; }
- public Instruction? Instruction { get; init; }
- public bool ReportingEnabled { get; init; }
-
- public ReflectionPatternContext (
- LinkContext context,
- bool reportingEnabled,
- in MessageOrigin origin,
- IMetadataTokenProvider memberWithRequirements,
- Instruction? instruction = null)
- {
- _context = context;
- ReportingEnabled = reportingEnabled;
- Origin = origin;
- MemberWithRequirements = memberWithRequirements;
- Instruction = instruction;
-
-#if DEBUG
- _patternAnalysisAttempted = false;
- _patternReported = false;
-#endif
- }
-
-#pragma warning disable CA1822
- [Conditional ("DEBUG")]
- public void AnalyzingPattern ()
- {
-#if DEBUG
- _patternAnalysisAttempted = true;
-#endif
- }
-
- [Conditional ("DEBUG")]
- public void RecordHandledPattern ()
- {
-#if DEBUG
- _patternReported = true;
-#endif
- }
-#pragma warning restore CA1822
-
- public void RecordRecognizedPattern (IMetadataTokenProvider accessedItem, Action mark)
- {
-#if DEBUG
- if (!_patternAnalysisAttempted)
- throw new InvalidOperationException ($"Internal error: To correctly report all patterns, when starting to analyze a pattern the AnalyzingPattern must be called first. {Source} -> {MemberWithRequirements}");
-
- _patternReported = true;
-#endif
-
- mark ();
-
- if (ReportingEnabled)
- _context.ReflectionPatternRecorder.RecognizedReflectionAccessPattern (Source, Instruction, accessedItem);
- }
-
- public void RecordUnrecognizedPattern (int messageCode, string message)
- {
-#if DEBUG
- if (!_patternAnalysisAttempted)
- throw new InvalidOperationException ($"Internal error: To correctly report all patterns, when starting to analyze a pattern the AnalyzingPattern must be called first. {Source} -> {MemberWithRequirements}");
-
- _patternReported = true;
-#endif
-
- if (ReportingEnabled)
- _context.ReflectionPatternRecorder.UnrecognizedReflectionAccessPattern (Origin, Source, Instruction, MemberWithRequirements, message, messageCode);
- }
-
- public void Dispose ()
- {
-#if DEBUG
- if (_patternAnalysisAttempted && !_patternReported)
- throw new InvalidOperationException ($"Internal error: A reflection pattern was analyzed, but no result was reported. {Source} -> {MemberWithRequirements}");
-#endif
- }
- }
-}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/RequireDynamicallyAccessedMembersAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/RequireDynamicallyAccessedMembersAction.cs
new file mode 100644
index 00000000000..d2fe33783b6
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/RequireDynamicallyAccessedMembersAction.cs
@@ -0,0 +1,43 @@
+// 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.Diagnostics.CodeAnalysis;
+using ILLink.Shared.TypeSystemProxy;
+using Mono.Cecil;
+using Mono.Linker;
+using Mono.Linker.Dataflow;
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ partial struct RequireDynamicallyAccessedMembersAction
+ {
+ readonly LinkContext _context;
+ readonly ReflectionMarker _reflectionMarker;
+
+ public RequireDynamicallyAccessedMembersAction (
+ LinkContext context,
+ ReflectionMarker reflectionMarker,
+ in DiagnosticContext diagnosticContext)
+ {
+ _context = context;
+ _reflectionMarker = reflectionMarker;
+ _diagnosticContext = diagnosticContext;
+ }
+
+ public partial bool TryResolveTypeNameAndMark (string typeName, bool needsAssemblyName, out TypeProxy type)
+ {
+ if (_reflectionMarker.TryResolveTypeNameAndMark (typeName, _diagnosticContext.Origin, needsAssemblyName, out TypeDefinition? foundType)) {
+ type = new (foundType);
+ return true;
+ } else {
+ type = default;
+ return false;
+ }
+ }
+
+ private partial void MarkTypeForDynamicallyAccessedMembers (in TypeProxy type, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ _reflectionMarker.MarkTypeForDynamicallyAccessedMembers (_diagnosticContext.Origin, type.Type, dynamicallyAccessedMemberTypes, DependencyKind.DynamicallyAccessedMember);
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ScannerExtensions.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ScannerExtensions.cs
index 0b7a2af8421..166a968b66a 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ScannerExtensions.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ScannerExtensions.cs
@@ -1,5 +1,5 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/SingleValueExtensions.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/SingleValueExtensions.cs
new file mode 100644
index 00000000000..c0024c1ccc1
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/SingleValueExtensions.cs
@@ -0,0 +1,87 @@
+// 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 ILLink.Shared.DataFlow;
+using Mono.Linker.Dataflow;
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ // These are extension methods because we want to allow the use of them on null 'this' pointers.
+ internal static class SingleValueExtensions
+ {
+ /// <summary>
+ /// Returns true if a ValueNode graph contains a cycle
+ /// </summary>
+ /// <param name="node">Node to evaluate</param>
+ /// <param name="seenNodes">Set of nodes previously seen on the current arc. Callers may pass a non-empty set
+ /// to test whether adding that set to this node would create a cycle. Contents will be modified by the walk
+ /// and should not be used by the caller after returning</param>
+ /// <param name="allNodesSeen">Optional. The set of all nodes encountered during a walk after DetectCycle returns</param>
+ /// <returns></returns>
+ public static bool DetectCycle (this SingleValue node, HashSet<SingleValue> seenNodes, HashSet<SingleValue>? allNodesSeen)
+ {
+ if (node == null)
+ return false;
+
+ if (seenNodes.Contains (node))
+ return true;
+
+ seenNodes.Add (node);
+
+ if (allNodesSeen != null) {
+ allNodesSeen.Add (node);
+ }
+
+ bool foundCycle = false;
+ switch (node) {
+ //
+ // Leaf nodes
+ //
+ case UnknownValue:
+ case NullValue:
+ case SystemTypeValue:
+ case RuntimeTypeHandleValue:
+ case KnownStringValue:
+ case ConstIntValue:
+ case MethodParameterValue:
+ case MethodThisParameterValue:
+ case MethodReturnValue:
+ case GenericParameterValue:
+ case RuntimeTypeHandleForGenericParameterValue:
+ case SystemReflectionMethodBaseValue:
+ case RuntimeMethodHandleValue:
+ case FieldValue:
+ break;
+
+ //
+ // Nodes with children
+ //
+ case ArrayValue:
+ ArrayValue av = (ArrayValue) node;
+ foundCycle = av.Size.DetectCycle (seenNodes, allNodesSeen);
+ foreach (ValueBasicBlockPair pair in av.IndexValues.Values) {
+ foreach (var v in pair.Value) {
+ foundCycle |= v.DetectCycle (seenNodes, allNodesSeen);
+ }
+ }
+ break;
+
+ case RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers value:
+ foundCycle = value.UnderlyingTypeValue.DetectCycle (seenNodes, allNodesSeen);
+ break;
+
+ case NullableValueWithDynamicallyAccessedMembers value:
+ foundCycle = value.UnderlyingTypeValue.DetectCycle (seenNodes, allNodesSeen);
+ break;
+
+ default:
+ throw new Exception (String.Format ("Unknown node type: {0}", node.GetType ().Name));
+ }
+ seenNodes.Remove (node);
+
+ return foundCycle;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/TypeProxy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/TypeProxy.cs
new file mode 100644
index 00000000000..52a43ec6a49
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/TypeProxy.cs
@@ -0,0 +1,43 @@
+// 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.Collections.Immutable;
+using Mono.Cecil;
+using Mono.Linker;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal readonly partial struct TypeProxy
+ {
+ public TypeProxy (TypeDefinition type) => Type = type;
+
+ public static implicit operator TypeProxy (TypeDefinition type) => new (type);
+
+ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ()
+ {
+ if (!Type.HasGenericParameters)
+ return ImmutableArray<GenericParameterProxy>.Empty;
+
+ var builder = ImmutableArray.CreateBuilder<GenericParameterProxy> (Type.GenericParameters.Count);
+ foreach (var genericParameter in Type.GenericParameters) {
+ builder.Add (new GenericParameterProxy (genericParameter));
+ }
+
+ return builder.ToImmutableArray ();
+ }
+
+ public TypeDefinition Type { get; }
+
+ public string Name { get => Type.Name; }
+
+ public string? Namespace { get => Type.Namespace; }
+
+ public bool IsTypeOf (string @namespace, string name) => Type.IsTypeOf (@namespace, name);
+
+ public bool IsTypeOf (WellKnownType wellKnownType) => Type.IsTypeOf (wellKnownType);
+
+ public string GetDisplayName () => Type.GetDisplayName ();
+
+ public override string ToString () => Type.ToString ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ValueNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ValueNode.cs
index 5e3349db6f8..5a0df8f3476 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ValueNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ValueNode.cs
@@ -1,1295 +1,13 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Text;
-using Mono.Cecil;
-using FieldDefinition = Mono.Cecil.FieldDefinition;
-using GenericParameter = Mono.Cecil.GenericParameter;
-using TypeDefinition = Mono.Cecil.TypeDefinition;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
namespace Mono.Linker.Dataflow
{
- public enum ValueNodeKind
- {
- Invalid, // in case the Kind field is not initialized properly
-
- Unknown, // unknown value, has StaticType from context
-
- Null, // known value
- SystemType, // known value - TypeRepresented
- RuntimeTypeHandle, // known value - TypeRepresented
- KnownString, // known value - Contents
- ConstInt, // known value - Int32
- AnnotatedString, // string with known annotation
-
- MethodParameter, // symbolic placeholder
- MethodReturn, // symbolic placeholder
-
- RuntimeMethodHandle, // known value - MethodRepresented
- SystemReflectionMethodBase, // known value - MethodRepresented
-
- RuntimeTypeHandleForGenericParameter, // symbolic placeholder for generic parameter
- SystemTypeForGenericParameter, // symbolic placeholder for generic parameter
-
- MergePoint, // structural, multiplexer - Values
- GetTypeFromString, // structural, could be known value - KnownString
- Array, // structural, could be known value - Array
-
- LoadField, // structural, could be known value - InstanceValue
- }
-
- /// <summary>
- /// A ValueNode represents a value in the IL dataflow analysis. It may not contain complete information as it is a
- /// best-effort representation. Additionally, as the analysis is linear and does not account for control flow, any
- /// given ValueNode may represent multiple values simultaneously. (This occurs, for example, at control flow join
- /// points when both paths yield values on the IL stack or in a local.)
- /// </summary>
- public abstract class ValueNode : IEquatable<ValueNode>
- {
- public ValueNode ()
- {
-#if false // Helpful for debugging a cycle that has inadvertently crept into the graph
- if (this.DetectCycle(new HashSet<ValueNode>()))
- {
- throw new Exception("Found a cycle");
- }
-#endif
- }
-
- /// <summary>
- /// The 'kind' of value node -- this represents the most-derived type and allows us to switch over and do
- /// equality checks without the cost of casting. Intermediate non-leaf types in the ValueNode hierarchy should
- /// be abstract.
- /// </summary>
- public ValueNodeKind Kind { get; protected set; }
-
- /// <summary>
- /// The IL type of the value, represented as closely as possible, but not always exact. It can be null, for
- /// example, when the analysis is imprecise or operating on malformed IL.
- /// </summary>
- public TypeDefinition? StaticType { get; protected set; }
-
- /// <summary>
- /// Allows the enumeration of the direct children of this node. The ChildCollection struct returned here
- /// supports 'foreach' without allocation.
- /// </summary>
- public ChildCollection Children { get { return new ChildCollection (this); } }
-
- /// <summary>
- /// This property allows you to enumerate all 'unique values' represented by a given ValueNode. The basic idea
- /// is that there will be no MergePointValues in the returned ValueNodes and all structural operations will be
- /// applied so that each 'unique value' can be considered on its own without regard to the structure that led to
- /// it.
- /// </summary>
- public UniqueValueCollection UniqueValuesInternal {
- get {
- return new UniqueValueCollection (this);
- }
- }
-
- /// <summary>
- /// This protected method is how nodes implement the UniqueValues property. It is protected because it returns
- /// an IEnumerable and we want to avoid allocating an enumerator for the exceedingly common case of there being
- /// only one value in the enumeration. The UniqueValueCollection returned by the UniqueValues property handles
- /// this detail.
- /// </summary>
- protected abstract IEnumerable<ValueNode> EvaluateUniqueValues ();
-
- /// <summary>
- /// RepresentsExactlyOneValue is used by the UniqueValues property to allow us to bypass allocating an
- /// enumerator to return just one value. If a node returns 'true' from RepresentsExactlyOneValue, it must also
- /// return that one value from GetSingleUniqueValue. If it always returns 'false', it doesn't need to implement
- /// GetSingleUniqueValue.
- /// </summary>
- protected virtual bool RepresentsExactlyOneValue { get { return false; } }
-
- /// <summary>
- /// GetSingleUniqueValue is called if, and only if, RepresentsExactlyOneValue returns true. It allows us to
- /// bypass the allocation of an enumerator for the common case of returning exactly one value.
- /// </summary>
- protected virtual ValueNode GetSingleUniqueValue ()
- {
- // Not implemented because RepresentsExactlyOneValue returns false and, therefore, this method should be
- // unreachable.
- throw new NotImplementedException ();
- }
-
- protected abstract int NumChildren { get; }
- protected abstract ValueNode ChildAt (int index);
-
- public virtual bool Equals (ValueNode? other)
- {
- return other != null && this.Kind == other.Kind && this.StaticType == other.StaticType;
- }
-
- public abstract override int GetHashCode ();
-
- /// <summary>
- /// Each node type must implement this to stringize itself. The expectation is that it is implemented using
- /// ValueNodeDump.ValueNodeToString(), passing any non-ValueNode properties of interest (e.g.
- /// SystemTypeValue.TypeRepresented). Properties that are invariant on a particular node type
- /// should be omitted for clarity.
- /// </summary>
- protected abstract string NodeToString ();
-
- public override string ToString ()
- {
- return NodeToString ();
- }
-
- public override bool Equals (object? other)
- {
- if (!(other is ValueNode))
- return false;
-
- return this.Equals ((ValueNode) other);
- }
-
- #region Specialized Collection Nested Types
- /// <summary>
- /// ChildCollection struct is used to wrap the operations on a node involving its children. In particular, the
- /// struct implements a GetEnumerator method that is used to allow "foreach (ValueNode node in myNode.Children)"
- /// without heap allocations.
- /// </summary>
- public struct ChildCollection : IEnumerable<ValueNode>
- {
- /// <summary>
- /// Enumerator for children of a ValueNode. Allows foreach(var child in node.Children) to work without
- /// allocating a heap-based enumerator.
- /// </summary>
- public struct Enumerator : IEnumerator<ValueNode>
- {
- int _index;
- readonly ValueNode _parent;
-
- public Enumerator (ValueNode parent)
- {
- _parent = parent;
- _index = -1;
- }
-
- public ValueNode Current { get { return _parent.ChildAt (_index); } }
-
- object System.Collections.IEnumerator.Current { get { return Current; } }
-
- public bool MoveNext ()
- {
- _index++;
- return (_parent != null) ? (_index < _parent.NumChildren) : false;
- }
-
- public void Reset ()
- {
- _index = -1;
- }
-
- public void Dispose ()
- {
- }
- }
-
- readonly ValueNode _parentNode;
-
- public ChildCollection (ValueNode parentNode) { _parentNode = parentNode; }
-
- // Used by C# 'foreach', when strongly typed, to avoid allocation.
- public Enumerator GetEnumerator ()
- {
- return new Enumerator (_parentNode);
- }
-
- IEnumerator<ValueNode> IEnumerable<ValueNode>.GetEnumerator ()
- {
- // note the boxing!
- return new Enumerator (_parentNode);
- }
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
- {
- // note the boxing!
- return new Enumerator (_parentNode);
- }
-
- public int Count { get { return (_parentNode != null) ? _parentNode.NumChildren : 0; } }
- }
-
- /// <summary>
- /// UniqueValueCollection is used to wrap calls to ValueNode.EvaluateUniqueValues. If a ValueNode represents
- /// only one value, then foreach(ValueNode value in node.UniqueValues) will not allocate a heap-based enumerator.
- ///
- /// This is implented by having each ValueNode tell us whether or not it represents exactly one value or not.
- /// If it does, we fetch it with ValueNode.GetSingleUniqueValue(), otherwise, we fall back to the usual heap-
- /// based IEnumerable returned by ValueNode.EvaluateUniqueValues.
- /// </summary>
- public struct UniqueValueCollection : IEnumerable<ValueNode>
- {
- readonly IEnumerable<ValueNode>? _multiValueEnumerable;
- readonly ValueNode? _treeNode;
-
- public UniqueValueCollection (ValueNode node)
- {
- if (node.RepresentsExactlyOneValue) {
- _multiValueEnumerable = null;
- _treeNode = node;
- } else {
- _multiValueEnumerable = node.EvaluateUniqueValues ();
- _treeNode = null;
- }
- }
-
- public Enumerator GetEnumerator ()
- {
- return new Enumerator (_treeNode, _multiValueEnumerable);
- }
-
- IEnumerator<ValueNode> IEnumerable<ValueNode>.GetEnumerator ()
- {
- if (_multiValueEnumerable != null) {
- return _multiValueEnumerable.GetEnumerator ();
- }
-
- // note the boxing!
- return GetEnumerator ();
- }
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
- {
- if (_multiValueEnumerable != null) {
- return _multiValueEnumerable.GetEnumerator ();
- }
-
- // note the boxing!
- return GetEnumerator ();
- }
-
-
- public struct Enumerator : IEnumerator<ValueNode>
- {
- readonly IEnumerator<ValueNode>? _multiValueEnumerator;
- readonly ValueNode? _singleValueNode;
- int _index;
-
- public Enumerator (ValueNode? treeNode, IEnumerable<ValueNode>? multiValueEnumerable)
- {
- Debug.Assert (treeNode != null || multiValueEnumerable != null);
- _singleValueNode = treeNode?.GetSingleUniqueValue ();
- _multiValueEnumerator = multiValueEnumerable?.GetEnumerator ();
- _index = -1;
- }
-
- public void Reset ()
- {
- if (_multiValueEnumerator != null) {
- _multiValueEnumerator.Reset ();
- return;
- }
-
- _index = -1;
- }
-
- public bool MoveNext ()
- {
- if (_multiValueEnumerator != null)
- return _multiValueEnumerator.MoveNext ();
-
- _index++;
- return _index == 0;
- }
-
- public ValueNode Current {
- get {
- if (_multiValueEnumerator != null)
- return _multiValueEnumerator.Current;
-
- if (_index == 0)
- return _singleValueNode!;
-
- throw new InvalidOperationException ();
- }
- }
-
- object System.Collections.IEnumerator.Current { get { return Current; } }
-
- public void Dispose ()
- {
- }
- }
- }
- #endregion
- }
-
- /// <summary>
- /// LeafValueNode represents a 'leaf' in the expression tree. In other words, the node has no ValueNode children.
- /// It *may* still have non-ValueNode 'properties' that are interesting. This class serves, primarily, as a way to
- /// collect up the very common implmentation of NumChildren/ChildAt for leaf nodes and the "represents exactly one
- /// value" optimization. These things aren't on the ValueNode base class because, otherwise, new node types
- /// deriving from ValueNode may 'forget' to implement these things. So this class allows them to remain abstract in
- /// ValueNode while still having a common implementation for all the leaf nodes.
- /// </summary>
- public abstract class LeafValueNode : ValueNode
- {
- protected override int NumChildren { get { return 0; } }
- protected override ValueNode ChildAt (int index) { throw new InvalidOperationException (); }
-
- protected override bool RepresentsExactlyOneValue { get { return true; } }
-
- protected override ValueNode GetSingleUniqueValue () { return this; }
-
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues ()
- {
- // Leaf values should not represent more than one value. This method should be unreachable as long as
- // RepresentsExactlyOneValue returns true.
- throw new NotImplementedException ();
- }
- }
-
- // These are extension methods because we want to allow the use of them on null 'this' pointers.
- internal static class ValueNodeExtensions
- {
- /// <summary>
- /// Returns true if a ValueNode graph contains a cycle
- /// </summary>
- /// <param name="node">Node to evaluate</param>
- /// <param name="seenNodes">Set of nodes previously seen on the current arc. Callers may pass a non-empty set
- /// to test whether adding that set to this node would create a cycle. Contents will be modified by the walk
- /// and should not be used by the caller after returning</param>
- /// <param name="allNodesSeen">Optional. The set of all nodes encountered during a walk after DetectCycle returns</param>
- /// <returns></returns>
- public static bool DetectCycle (this ValueNode? node, HashSet<ValueNode> seenNodes, HashSet<ValueNode>? allNodesSeen)
- {
- if (node == null)
- return false;
-
- if (seenNodes.Contains (node))
- return true;
-
- seenNodes.Add (node);
-
- if (allNodesSeen != null) {
- allNodesSeen.Add (node);
- }
-
- bool foundCycle = false;
- switch (node.Kind) {
- //
- // Leaf nodes
- //
- case ValueNodeKind.Unknown:
- case ValueNodeKind.Null:
- case ValueNodeKind.SystemType:
- case ValueNodeKind.RuntimeTypeHandle:
- case ValueNodeKind.KnownString:
- case ValueNodeKind.AnnotatedString:
- case ValueNodeKind.ConstInt:
- case ValueNodeKind.MethodParameter:
- case ValueNodeKind.MethodReturn:
- case ValueNodeKind.SystemTypeForGenericParameter:
- case ValueNodeKind.RuntimeTypeHandleForGenericParameter:
- case ValueNodeKind.SystemReflectionMethodBase:
- case ValueNodeKind.RuntimeMethodHandle:
- case ValueNodeKind.LoadField:
- break;
-
- //
- // Nodes with children
- //
- case ValueNodeKind.MergePoint:
- foreach (ValueNode val in ((MergePointValue) node).Values) {
- if (val.DetectCycle (seenNodes, allNodesSeen)) {
- foundCycle = true;
- }
- }
- break;
-
- case ValueNodeKind.GetTypeFromString:
- GetTypeFromStringValue gtfsv = (GetTypeFromStringValue) node;
- foundCycle = gtfsv.AssemblyIdentity.DetectCycle (seenNodes, allNodesSeen);
- foundCycle |= gtfsv.NameString.DetectCycle (seenNodes, allNodesSeen);
- break;
-
- case ValueNodeKind.Array:
- ArrayValue av = (ArrayValue) node;
- foundCycle = av.Size.DetectCycle (seenNodes, allNodesSeen);
- foreach (ValueBasicBlockPair pair in av.IndexValues.Values) {
- foundCycle |= pair.Value.DetectCycle (seenNodes, allNodesSeen);
- }
- break;
-
- default:
- throw new Exception (String.Format ("Unknown node kind: {0}", node.Kind));
- }
- seenNodes.Remove (node);
-
- return foundCycle;
- }
-
- public static ValueNode.UniqueValueCollection UniqueValues (this ValueNode? node)
- {
- if (node == null)
- return new ValueNode.UniqueValueCollection (UnknownValue.Instance);
-
- return node.UniqueValuesInternal;
- }
-
- public static int? AsConstInt (this ValueNode? node)
- {
- if (node is ConstIntValue constInt)
- return constInt.Value;
- return null;
- }
- }
-
- internal static class ValueNodeDump
- {
- internal static string ValueNodeToString (ValueNode? node, params object[] args)
- {
- if (node == null)
- return "<null>";
-
- StringBuilder sb = new StringBuilder ();
- sb.Append (node.Kind.ToString ());
- sb.Append ("(");
- if (args != null) {
- for (int i = 0; i < args.Length; i++) {
- if (i > 0)
- sb.Append (",");
- sb.Append (args[i] == null ? "<null>" : args[i].ToString ());
- }
- }
- sb.Append (")");
- return sb.ToString ();
- }
-
- static string GetIndent (int level)
- {
- StringBuilder sb = new StringBuilder (level * 2);
- for (int i = 0; i < level; i++)
- sb.Append (" ");
- return sb.ToString ();
- }
-
- public static void DumpTree (this ValueNode node, System.IO.TextWriter? writer = null, int indentLevel = 0)
- {
- if (writer == null)
- writer = Console.Out;
-
- writer.Write (GetIndent (indentLevel));
- if (node == null) {
- writer.WriteLine ("<null>");
- return;
- }
-
- writer.WriteLine (node);
- foreach (ValueNode child in node.Children) {
- child.DumpTree (writer, indentLevel + 1);
- }
- }
- }
-
- /// <summary>
- /// Represents an unknown value.
- /// </summary>
- class UnknownValue : LeafValueNode
- {
- private UnknownValue ()
- {
- Kind = ValueNodeKind.Unknown;
- StaticType = null;
- }
-
- public static UnknownValue Instance { get; } = new UnknownValue ();
-
- public override bool Equals (ValueNode? other)
- {
- return base.Equals (other);
- }
-
- public override int GetHashCode ()
- {
- // All instances of UnknownValue are equivalent, so they all hash to the same hashcode. This one was
- // chosen for no particular reason at all.
- return 0x98052;
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this);
- }
- }
-
- class NullValue : LeafValueNode
- {
- private NullValue ()
- {
- Kind = ValueNodeKind.Null;
- StaticType = null;
- }
-
- public override bool Equals (ValueNode? other)
- {
- return base.Equals (other);
- }
-
- public static NullValue Instance { get; } = new NullValue ();
-
- public override int GetHashCode ()
- {
- // All instances of NullValue are equivalent, so they all hash to the same hashcode. This one was
- // chosen for no particular reason at all.
- return 0x90210;
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this);
- }
- }
-
- /// <summary>
- /// This is a known System.Type value. TypeRepresented is the 'value' of the System.Type.
- /// </summary>
- class SystemTypeValue : LeafValueNode
- {
- public SystemTypeValue (TypeDefinition typeRepresented)
- {
- Kind = ValueNodeKind.SystemType;
-
- // Should be System.Type - but we don't have any use case where tracking it like that would matter
- StaticType = null;
-
- TypeRepresented = typeRepresented;
- }
-
- public TypeDefinition TypeRepresented { get; private set; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- return Equals (this.TypeRepresented, ((SystemTypeValue) other).TypeRepresented);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, TypeRepresented);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, TypeRepresented);
- }
- }
-
- /// <summary>
- /// This is the System.RuntimeTypeHandle equivalent to a <see cref="SystemTypeValue"/> node.
- /// </summary>
- class RuntimeTypeHandleValue : LeafValueNode
- {
- public RuntimeTypeHandleValue (TypeDefinition typeRepresented)
- {
- Kind = ValueNodeKind.RuntimeTypeHandle;
-
- // Should be System.RuntimeTypeHandle, but we don't have a use case for it like that
- StaticType = null;
-
- TypeRepresented = typeRepresented;
- }
-
- public TypeDefinition TypeRepresented { get; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- return Equals (this.TypeRepresented, ((RuntimeTypeHandleValue) other).TypeRepresented);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, TypeRepresented);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, TypeRepresented);
- }
- }
-
- /// <summary>
- /// This is a System.Type value which represents generic parameter (basically result of typeof(T))
- /// Its actual type is unknown, but it can have annotations.
- /// </summary>
- class SystemTypeForGenericParameterValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public SystemTypeForGenericParameterValue (GenericParameter genericParameter, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- : base (genericParameter)
- {
- Kind = ValueNodeKind.SystemTypeForGenericParameter;
-
- // Should be System.Type, but we don't have a use case for it
- StaticType = null;
-
- GenericParameter = genericParameter;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- }
-
- public GenericParameter GenericParameter { get; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- var otherValue = (SystemTypeForGenericParameterValue) other;
- return this.GenericParameter == otherValue.GenericParameter && this.DynamicallyAccessedMemberTypes == otherValue.DynamicallyAccessedMemberTypes;
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, GenericParameter, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, GenericParameter, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// This is the System.RuntimeTypeHandle equivalent to a <see cref="SystemTypeForGenericParameterValue"/> node.
- /// </summary>
- class RuntimeTypeHandleForGenericParameterValue : LeafValueNode
- {
- public RuntimeTypeHandleForGenericParameterValue (GenericParameter genericParameter)
- {
- Kind = ValueNodeKind.RuntimeTypeHandleForGenericParameter;
-
- // Should be System.RuntimeTypeHandle, but we don't have a use case for it
- StaticType = null;
-
- GenericParameter = genericParameter;
- }
-
- public GenericParameter GenericParameter { get; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- return Equals (this.GenericParameter, ((RuntimeTypeHandleForGenericParameterValue) other).GenericParameter);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, GenericParameter);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, GenericParameter);
- }
- }
-
- /// <summary>
- /// This is the System.RuntimeMethodHandle equivalent to a <see cref="SystemReflectionMethodBaseValue"/> node.
- /// </summary>
- class RuntimeMethodHandleValue : LeafValueNode
- {
- public RuntimeMethodHandleValue (MethodDefinition methodRepresented)
- {
- Kind = ValueNodeKind.RuntimeMethodHandle;
-
- // Should be System.RuntimeMethodHandle, but we don't have a use case for it
- StaticType = null;
-
- MethodRepresented = methodRepresented;
- }
-
- public MethodDefinition MethodRepresented { get; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- return Equals (this.MethodRepresented, ((RuntimeMethodHandleValue) other).MethodRepresented);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, MethodRepresented);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, MethodRepresented);
- }
- }
-
- /// <summary>
- /// This is a known System.Reflection.MethodBase value. MethodRepresented is the 'value' of the MethodBase.
- /// </summary>
- class SystemReflectionMethodBaseValue : LeafValueNode
- {
- public SystemReflectionMethodBaseValue (MethodDefinition methodRepresented)
- {
- Kind = ValueNodeKind.SystemReflectionMethodBase;
-
- // Should be System.Reflection.MethodBase, but we don't have a use case for it
- StaticType = null;
-
- MethodRepresented = methodRepresented;
- }
-
- public MethodDefinition MethodRepresented { get; private set; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- return Equals (this.MethodRepresented, ((SystemReflectionMethodBaseValue) other).MethodRepresented);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, MethodRepresented);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, MethodRepresented);
- }
- }
-
- /// <summary>
- /// A known string - such as the result of a ldstr.
- /// </summary>
- class KnownStringValue : LeafValueNode
- {
- public KnownStringValue (string contents)
- {
- Kind = ValueNodeKind.KnownString;
-
- // Should be System.String, but we don't have a use case for it
- StaticType = null;
-
- Contents = contents;
- }
-
- public string Contents { get; private set; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- return this.Contents == ((KnownStringValue) other).Contents;
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, Contents);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, "\"" + Contents + "\"");
- }
- }
-
- /// <summary>
- /// Base class for all nodes which can have dynamically accessed member annotation.
- /// </summary>
- abstract class LeafValueWithDynamicallyAccessedMemberNode : LeafValueNode
- {
- public LeafValueWithDynamicallyAccessedMemberNode (IMetadataTokenProvider sourceContext)
- {
- SourceContext = sourceContext;
- }
-
- public IMetadataTokenProvider SourceContext { get; private set; }
-
- /// <summary>
- /// The bitfield of dynamically accessed member types the node guarantees
- /// </summary>
- public DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; protected set; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- var otherValue = (LeafValueWithDynamicallyAccessedMemberNode) other;
- return SourceContext == otherValue.SourceContext
- && DynamicallyAccessedMemberTypes == otherValue.DynamicallyAccessedMemberTypes;
- }
- }
-
- /// <summary>
- /// A value that came from a method parameter - such as the result of a ldarg.
- /// </summary>
- class MethodParameterValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public MethodParameterValue (TypeDefinition? staticType, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, IMetadataTokenProvider sourceContext)
- : base (sourceContext)
- {
- Kind = ValueNodeKind.MethodParameter;
- StaticType = staticType;
- ParameterIndex = parameterIndex;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- }
-
- public int ParameterIndex { get; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- var otherValue = (MethodParameterValue) other;
- return this.ParameterIndex == otherValue.ParameterIndex;
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, ParameterIndex, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, ParameterIndex, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// String with a known annotation.
- /// </summary>
- class AnnotatedStringValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public AnnotatedStringValue (IMetadataTokenProvider sourceContext, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- : base (sourceContext)
- {
- Kind = ValueNodeKind.AnnotatedString;
-
- // Should be System.String, but we don't have a use case for it
- StaticType = null;
-
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- }
-
- public override bool Equals (ValueNode? other)
- {
- return base.Equals (other);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// Return value from a method
- /// </summary>
- class MethodReturnValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public MethodReturnValue (TypeDefinition? staticType, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, IMetadataTokenProvider sourceContext)
- : base (sourceContext)
- {
- Kind = ValueNodeKind.MethodReturn;
- StaticType = staticType;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- }
-
- public override bool Equals (ValueNode? other)
- {
- return base.Equals (other);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// A merge point commonly occurs due to control flow in a method body. It represents a set of values
- /// from different paths through the method. It is the reason for EvaluateUniqueValues, which essentially
- /// provides an enumeration over all the concrete values represented by a given ValueNode after 'erasing'
- /// the merge point nodes.
- /// </summary>
- class MergePointValue : ValueNode
- {
- private MergePointValue (ValueNode one, ValueNode two)
- {
- Kind = ValueNodeKind.MergePoint;
- StaticType = null;
- m_values = new ValueNodeHashSet ();
-
- if (one.Kind == ValueNodeKind.MergePoint) {
- MergePointValue mpvOne = (MergePointValue) one;
- foreach (ValueNode value in mpvOne.Values)
- m_values.Add (value);
- } else
- m_values.Add (one);
-
- if (two.Kind == ValueNodeKind.MergePoint) {
- MergePointValue mpvTwo = (MergePointValue) two;
- foreach (ValueNode value in mpvTwo.Values)
- m_values.Add (value);
- } else
- m_values.Add (two);
- }
-
- public MergePointValue ()
- {
- Kind = ValueNodeKind.MergePoint;
- m_values = new ValueNodeHashSet ();
- }
-
- public void AddValue (ValueNode node)
- {
- // we are mutating our state, so we must invalidate any cached knowledge
- //InvalidateIsOpen ();
-
- if (node.Kind == ValueNodeKind.MergePoint) {
- foreach (ValueNode value in ((MergePointValue) node).Values)
- m_values.Add (value);
- } else
- m_values.Add (node);
-
-#if false
- if (this.DetectCycle(new HashSet<ValueNode>()))
- {
- throw new Exception("Found a cycle");
- }
-#endif
- }
-
- readonly ValueNodeHashSet m_values;
-
- public ValueNodeHashSet Values { get { return m_values; } }
-
- protected override int NumChildren { get { return Values.Count; } }
- protected override ValueNode ChildAt (int index)
- {
- if (index < NumChildren)
- return Values.ElementAt (index);
- throw new InvalidOperationException ();
- }
-
- public static ValueNode? MergeValues (ValueNode? one, ValueNode? two)
- {
- if (one == null)
- return two;
- else if (two == null)
- return one;
- else if (one.Equals (two))
- return one;
- else
- return new MergePointValue (one, two);
- }
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues ()
- {
- foreach (ValueNode value in Values) {
- foreach (ValueNode uniqueValue in value.UniqueValuesInternal) {
- yield return uniqueValue;
- }
- }
- }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- MergePointValue otherMpv = (MergePointValue) other;
- if (this.Values.Count != otherMpv.Values.Count)
- return false;
-
- foreach (ValueNode value in this.Values) {
- if (!otherMpv.Values.Contains (value))
- return false;
- }
- return true;
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, Values);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this);
- }
- }
-
- delegate TypeDefinition TypeResolver (string assemblyString, string typeString);
-
- /// <summary>
- /// The result of a Type.GetType.
- /// AssemblyIdentity is the scope in which to resolve if the type name string is not assembly-qualified.
- /// </summary>
-
-#pragma warning disable CA1812 // GetTypeFromStringValue is never instantiated
- class GetTypeFromStringValue : ValueNode
- {
- private readonly TypeResolver _resolver;
-
- public GetTypeFromStringValue (TypeResolver resolver, ValueNode assemblyIdentity, ValueNode nameString)
- {
- _resolver = resolver;
- Kind = ValueNodeKind.GetTypeFromString;
-
- // Should be System.Type, but we don't have a use case for it
- StaticType = null;
-
- AssemblyIdentity = assemblyIdentity;
- NameString = nameString;
- }
-
- public ValueNode AssemblyIdentity { get; private set; }
-
- public ValueNode NameString { get; private set; }
-
- protected override int NumChildren { get { return 2; } }
- protected override ValueNode ChildAt (int index)
- {
- if (index == 0) return AssemblyIdentity;
- if (index == 1) return NameString;
- throw new InvalidOperationException ();
- }
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues ()
- {
- HashSet<string>? names = null;
-
- foreach (ValueNode nameStringValue in NameString.UniqueValuesInternal) {
- if (nameStringValue.Kind == ValueNodeKind.KnownString) {
- if (names == null) {
- names = new HashSet<string> ();
- }
-
- string typeName = ((KnownStringValue) nameStringValue).Contents;
- names.Add (typeName);
- }
- }
-
- bool foundAtLeastOne = false;
-
- if (names != null) {
- foreach (ValueNode assemblyValue in AssemblyIdentity.UniqueValuesInternal) {
- if (assemblyValue.Kind == ValueNodeKind.KnownString) {
- string assemblyName = ((KnownStringValue) assemblyValue).Contents;
-
- foreach (string name in names) {
- TypeDefinition typeDefinition = _resolver (assemblyName, name);
- if (typeDefinition != null) {
- foundAtLeastOne = true;
- yield return new SystemTypeValue (typeDefinition);
- }
- }
- }
- }
- }
-
- if (!foundAtLeastOne)
- yield return UnknownValue.Instance;
- }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- GetTypeFromStringValue otherGtfs = (GetTypeFromStringValue) other;
-
- return this.AssemblyIdentity.Equals (otherGtfs.AssemblyIdentity) &&
- this.NameString.Equals (otherGtfs.NameString);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, AssemblyIdentity, NameString);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, NameString);
- }
- }
-
- /// <summary>
- /// A representation of a ldfld. Note that we don't have a representation of objects containing fields
- /// so there isn't much that can be done with this node type yet.
- /// </summary>
- class LoadFieldValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public LoadFieldValue (TypeDefinition? staticType, FieldDefinition fieldToLoad, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- : base (fieldToLoad)
- {
- Kind = ValueNodeKind.LoadField;
- StaticType = staticType;
- Field = fieldToLoad;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- }
-
- public FieldDefinition Field { get; private set; }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- LoadFieldValue otherLfv = (LoadFieldValue) other;
- return Equals (this.Field, otherLfv.Field);
- }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, Field, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, Field, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// Represents a ldc on an int32.
- /// </summary>
- class ConstIntValue : LeafValueNode
- {
- public ConstIntValue (int value)
- {
- Kind = ValueNodeKind.ConstInt;
-
- // Should be System.Int32, but we don't have a usecase for it right now
- StaticType = null;
-
- Value = value;
- }
-
- public int Value { get; private set; }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, Value);
- }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- ConstIntValue otherCiv = (ConstIntValue) other;
- return Value == otherCiv.Value;
- }
-
- protected override string NodeToString ()
- {
- return ValueNodeDump.ValueNodeToString (this, Value);
- }
- }
-
- class ArrayValue : ValueNode
- {
- protected override int NumChildren => 1 + IndexValues.Count;
-
- /// <summary>
- /// Constructs an array value of the given size
- /// </summary>
- public ArrayValue (ValueNode? size, TypeReference elementType)
- {
- Kind = ValueNodeKind.Array;
-
- // Should be System.Array (or similar), but we don't have a use case for it
- StaticType = null;
-
- Size = size ?? UnknownValue.Instance;
- ElementType = elementType;
- IndexValues = new Dictionary<int, ValueBasicBlockPair> ();
- }
-
- private ArrayValue (ValueNode size, TypeReference elementType, Dictionary<int, ValueBasicBlockPair> indexValues)
- : this (size, elementType)
- {
- IndexValues = indexValues;
- }
-
- public ValueNode Size { get; }
- public TypeReference ElementType { get; }
- public Dictionary<int, ValueBasicBlockPair> IndexValues { get; }
-
- public override int GetHashCode ()
- {
- return HashCode.Combine (Kind, Size);
- }
-
- public override bool Equals (ValueNode? other)
- {
- if (!base.Equals (other))
- return false;
-
- ArrayValue otherArr = (ArrayValue) other;
- bool equals = Size.Equals (otherArr.Size);
- equals &= IndexValues.Count == otherArr.IndexValues.Count;
- if (!equals)
- return false;
-
- // If both sets T and O are the same size and "T intersect O" is empty, then T == O.
- HashSet<KeyValuePair<int, ValueBasicBlockPair>> thisValueSet = new (IndexValues);
- HashSet<KeyValuePair<int, ValueBasicBlockPair>> otherValueSet = new (otherArr.IndexValues);
- thisValueSet.ExceptWith (otherValueSet);
- return thisValueSet.Count == 0;
- }
-
- protected override string NodeToString ()
- {
- // TODO: Use StringBuilder and remove Linq usage.
- return $"(Array Size:{ValueNodeDump.ValueNodeToString (this, Size)}, Values:({string.Join (',', IndexValues.Select (v => $"({v.Key},{ValueNodeDump.ValueNodeToString (v.Value.Value)})"))})";
- }
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues ()
- {
- foreach (var sizeConst in Size.UniqueValuesInternal)
- yield return new ArrayValue (sizeConst, ElementType, IndexValues);
- }
-
- protected override ValueNode ChildAt (int index)
- {
- if (index == 0) return Size;
- if (index - 1 <= IndexValues.Count)
- return IndexValues.Values.ElementAt (index - 1).Value!;
-
- throw new InvalidOperationException ();
- }
- }
-
- #region ValueNode Collections
- public class ValueNodeList : List<ValueNode?>
+ public class ValueNodeList : List<MultiValue>
{
public ValueNodeList ()
{
@@ -1300,14 +18,17 @@ namespace Mono.Linker.Dataflow
{
}
- public ValueNodeList (List<ValueNode> other)
+ public ValueNodeList (List<MultiValue> other)
: base (other)
{
}
public override int GetHashCode ()
{
- return HashUtils.CalcHashCodeEnumerable (this);
+ HashCode hashCode = new HashCode ();
+ foreach (var item in this)
+ hashCode.Add (item.GetHashCode ());
+ return hashCode.ToHashCode ();
}
public override bool Equals (object? other)
@@ -1319,56 +40,22 @@ namespace Mono.Linker.Dataflow
return false;
for (int i = 0; i < Count; i++) {
- if (!(otherList[i]?.Equals (this[i]) ?? (this[i] is null)))
- return false;
- }
- return true;
- }
- }
-
- class ValueNodeHashSet : HashSet<ValueNode>
- {
- public override int GetHashCode ()
- {
- return HashUtils.CalcHashCodeEnumerable (this);
- }
-
- public override bool Equals (object? other)
- {
- if (!(other is ValueNodeHashSet otherSet))
- return false;
-
- if (otherSet.Count != Count)
- return false;
-
- IEnumerator<ValueNode> thisEnumerator = this.GetEnumerator ();
- IEnumerator<ValueNode> otherEnumerator = otherSet.GetEnumerator ();
-
- for (int i = 0; i < Count; i++) {
- thisEnumerator.MoveNext ();
- otherEnumerator.MoveNext ();
- if (!thisEnumerator.Current.Equals (otherEnumerator.Current))
+ if (!otherList[i].Equals (this[i]))
return false;
}
return true;
}
}
- #endregion
- static class HashUtils
+ public struct ValueBasicBlockPair
{
- public static int CalcHashCodeEnumerable<T> (IEnumerable<T> list) where T : class?
+ public ValueBasicBlockPair (MultiValue value, int basicBlockIndex)
{
- HashCode hashCode = new HashCode ();
- foreach (var item in list)
- hashCode.Add (item);
- return hashCode.ToHashCode ();
+ Value = value;
+ BasicBlockIndex = basicBlockIndex;
}
- }
- public struct ValueBasicBlockPair
- {
- public ValueNode? Value;
- public int BasicBlockIndex;
+ public MultiValue Value { get; }
+ public int BasicBlockIndex { get; }
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs
new file mode 100644
index 00000000000..3b19dbfcf1a
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs
@@ -0,0 +1,197 @@
+// 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.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using ILCompiler.DependencyAnalysis;
+using ILCompiler.Logging;
+using ILLink.Shared;
+using ILLink.Shared.TrimAnalysis;
+using Internal.TypeSystem;
+
+using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
+
+#nullable enable
+
+namespace ILCompiler.Dataflow
+{
+ internal class ReflectionMarker
+ {
+ private DependencyList _dependencies = new DependencyList();
+ private readonly Logger _logger;
+ private readonly NodeFactory _factory;
+ private readonly FlowAnnotations _annotations;
+ private bool _typeHierarchyDataFlow;
+ private const string RequiresUnreferencedCodeAttribute = nameof(RequiresUnreferencedCodeAttribute);
+
+ public DependencyList Dependencies { get => _dependencies; }
+
+ public ReflectionMarker(Logger logger, NodeFactory factory, FlowAnnotations annotations, bool typeHierarchyDataFlow)
+ {
+ _logger = logger;
+ _factory = factory;
+ _annotations = annotations;
+ _typeHierarchyDataFlow = typeHierarchyDataFlow;
+ }
+
+ internal void MarkTypeForDynamicallyAccessedMembers(in MessageOrigin origin, TypeDesc typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, Origin memberWithRequirements, bool declaredOnly = false)
+ {
+ foreach (var member in typeDefinition.GetDynamicallyAccessedMembers(requiredMemberTypes, declaredOnly))
+ {
+ switch (member)
+ {
+ case MethodDesc method:
+ MarkMethod(origin, method, memberWithRequirements);
+ break;
+ case FieldDesc field:
+ MarkField(origin, field, memberWithRequirements);
+ break;
+ case MetadataType nestedType:
+ MarkType(origin, nestedType, memberWithRequirements);
+ break;
+ case PropertyPseudoDesc property:
+ MarkProperty(origin, property, memberWithRequirements);
+ break;
+ case EventPseudoDesc @event:
+ MarkEvent(origin, @event, memberWithRequirements);
+ break;
+ // case InterfaceImplementation
+ // Nothing to do currently as Native AOT will presere all interfaces on a preserved type
+ }
+ }
+ }
+
+ internal bool TryResolveTypeNameAndMark(string typeName, MessageOrigin origin, bool needsAssemblyName, Origin memberWithRequirements, [NotNullWhen(true)] out TypeDesc? type)
+ {
+ ModuleDesc? callingModule = ((origin.MemberDefinition as MethodDesc)?.OwningType as MetadataType)?.Module;
+
+ if (!ILCompiler.DependencyAnalysis.ReflectionMethodBodyScanner.ResolveType(typeName, callingModule, origin.MemberDefinition.Context, out TypeDesc foundType, out ModuleDesc referenceModule))
+ {
+ type = default;
+ return false;
+ }
+
+ // Also add module metadata in case this reference was through a type forward
+ if (_factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
+ _dependencies.Add(_factory.ModuleMetadata(referenceModule), memberWithRequirements.ToString());
+
+ MarkType(origin, foundType, memberWithRequirements);
+
+ type = foundType;
+ return true;
+ }
+
+ internal void MarkType(in MessageOrigin origin, TypeDesc type, Origin memberWithRequirements)
+ {
+ RootingHelpers.TryGetDependenciesForReflectedType(ref _dependencies, _factory, type, memberWithRequirements.ToString());
+ }
+
+ internal void MarkMethod(in MessageOrigin origin, MethodDesc method, Origin memberWithRequirements)
+ {
+ if (method.DoesMethodRequire(RequiresUnreferencedCodeAttribute, out _))
+ {
+ if (_typeHierarchyDataFlow)
+ {
+ _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode,
+ ((TypeOrigin)memberWithRequirements).GetDisplayName(), method.GetDisplayName());
+ }
+ }
+
+ if (_annotations.ShouldWarnWhenAccessedForReflection(method) && !ReflectionMethodBodyScanner.ShouldSuppressAnalysisWarningsForRequires(method, RequiresUnreferencedCodeAttribute))
+ {
+ WarnOnReflectionAccess(origin, method, memberWithRequirements);
+ }
+
+ RootingHelpers.TryGetDependenciesForReflectedMethod(ref _dependencies, _factory, method, memberWithRequirements.ToString());
+ }
+
+ void MarkField(in MessageOrigin origin, FieldDesc field, Origin memberWithRequirements)
+ {
+ if (_annotations.ShouldWarnWhenAccessedForReflection(field) && !ReflectionMethodBodyScanner.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, RequiresUnreferencedCodeAttribute))
+ {
+ WarnOnReflectionAccess(origin, field, memberWithRequirements);
+ }
+
+ RootingHelpers.TryGetDependenciesForReflectedField(ref _dependencies, _factory, field, memberWithRequirements.ToString());
+ }
+
+ internal void MarkProperty(in MessageOrigin origin, PropertyPseudoDesc property, Origin memberWithRequirements)
+ {
+ if (property.GetMethod != null)
+ MarkMethod(origin, property.GetMethod, memberWithRequirements);
+ if (property.SetMethod != null)
+ MarkMethod(origin, property.SetMethod, memberWithRequirements);
+ }
+
+ void MarkEvent(in MessageOrigin origin, EventPseudoDesc @event, Origin memberWithRequirements)
+ {
+ if (@event.AddMethod != null)
+ MarkMethod(origin, @event.AddMethod, memberWithRequirements);
+ if (@event.RemoveMethod != null)
+ MarkMethod(origin, @event.RemoveMethod, memberWithRequirements);
+ }
+
+ internal void MarkConstructorsOnType(in MessageOrigin origin, TypeDesc type, Func<MethodDesc, bool>? filter, Origin memberWithRequirements, BindingFlags? bindingFlags = null)
+ {
+ foreach (var ctor in type.GetConstructorsOnType(filter, bindingFlags))
+ MarkMethod(origin, ctor, memberWithRequirements);
+ }
+
+ internal void MarkFieldsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<FieldDesc, bool> filter, Origin memberWithRequirements, BindingFlags? bindingFlags = BindingFlags.Default)
+ {
+ foreach (var field in type.GetFieldsOnTypeHierarchy(filter, bindingFlags))
+ MarkField(origin, field, memberWithRequirements);
+ }
+
+ internal void MarkPropertiesOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<PropertyPseudoDesc, bool> filter, Origin memberWithRequirements, BindingFlags? bindingFlags = BindingFlags.Default)
+ {
+ foreach (var property in type.GetPropertiesOnTypeHierarchy(filter, bindingFlags))
+ MarkProperty(origin, property, memberWithRequirements);
+ }
+
+ internal void MarkEventsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<EventPseudoDesc, bool> filter, Origin memberWithRequirements, BindingFlags? bindingFlags = BindingFlags.Default)
+ {
+ foreach (var @event in type.GetEventsOnTypeHierarchy(filter, bindingFlags))
+ MarkEvent(origin, @event, memberWithRequirements);
+ }
+
+ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
+ {
+ if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
+ {
+ _dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
+ }
+ }
+
+ void WarnOnReflectionAccess(in MessageOrigin origin, TypeSystemEntity entity, Origin memberWithRequirements)
+ {
+ if (_typeHierarchyDataFlow)
+ {
+ // Don't check whether the current scope is a RUC type or RUC method because these warnings
+ // are not suppressed in RUC scopes. Here the scope represents the DynamicallyAccessedMembers
+ // annotation on a type, not a callsite which uses the annotation. We always want to warn about
+ // possible reflection access indicated by these annotations.
+ _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers,
+ ((TypeOrigin)memberWithRequirements).GetDisplayName(), entity.GetDisplayName());
+ }
+ else
+ {
+ if (!ReflectionMethodBodyScanner.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, RequiresUnreferencedCodeAttribute))
+ {
+ if (entity is FieldDesc)
+ {
+ _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection, entity.GetDisplayName());
+ }
+ else
+ {
+ Debug.Assert(entity is MethodDesc);
+
+ _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection, entity.GetDisplayName());
+ }
+ }
+ }
+ }
+ }
+}
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 c754c50ed99..f584f7c5b20 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
@@ -1,44 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection.Metadata;
-using ILLink.Shared;
-
using ILCompiler.Logging;
+using ILLink.Shared;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TrimAnalysis;
using Internal.IL;
using Internal.TypeSystem;
-using BindingFlags = System.Reflection.BindingFlags;
-using NodeFactory = ILCompiler.DependencyAnalysis.NodeFactory;
-using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
-using CustomAttributeValue = System.Reflection.Metadata.CustomAttributeValue<Internal.TypeSystem.TypeDesc>;
-using CustomAttributeTypedArgument = System.Reflection.Metadata.CustomAttributeTypedArgument<Internal.TypeSystem.TypeDesc>;
using CustomAttributeNamedArgumentKind = System.Reflection.Metadata.CustomAttributeNamedArgumentKind;
+using CustomAttributeValue = System.Reflection.Metadata.CustomAttributeValue<Internal.TypeSystem.TypeDesc>;
+using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
using InteropTypes = Internal.TypeSystem.Interop.InteropTypes;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+using NodeFactory = ILCompiler.DependencyAnalysis.NodeFactory;
+using WellKnownType = ILLink.Shared.TypeSystemProxy.WellKnownType;
+
+#nullable enable
namespace ILCompiler.Dataflow
{
class ReflectionMethodBodyScanner : MethodBodyScanner
{
- private readonly FlowAnnotations _flowAnnotations;
+ private readonly FlowAnnotations _annotations;
private readonly Logger _logger;
private readonly NodeFactory _factory;
- private DependencyList _dependencies = new DependencyList();
+ private readonly ReflectionMarker _reflectionMarker;
private const string RequiresUnreferencedCodeAttribute = nameof(RequiresUnreferencedCodeAttribute);
private const string RequiresDynamicCodeAttribute = nameof(RequiresDynamicCodeAttribute);
private const string RequiresAssemblyFilesAttribute = nameof(RequiresAssemblyFilesAttribute);
public static bool RequiresReflectionMethodBodyScannerForCallSite(FlowAnnotations flowAnnotations, MethodDesc methodDefinition)
{
- return
- GetIntrinsicIdForMethod(methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
+ return Intrinsics.GetIntrinsicIdForMethod(methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
flowAnnotations.RequiresDataflowAnalysis(methodDefinition) ||
methodDefinition.DoesMethodRequire(RequiresUnreferencedCodeAttribute, out _) ||
methodDefinition.DoesMethodRequire(RequiresDynamicCodeAttribute, out _) ||
@@ -47,8 +49,7 @@ namespace ILCompiler.Dataflow
public static bool RequiresReflectionMethodBodyScannerForMethodBody(FlowAnnotations flowAnnotations, MethodDesc methodDefinition)
{
- return
- GetIntrinsicIdForMethod(methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
+ return Intrinsics.GetIntrinsicIdForMethod(methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
flowAnnotations.RequiresDataflowAnalysis(methodDefinition);
}
@@ -77,10 +78,10 @@ namespace ILCompiler.Dataflow
_ => throw new NotImplementedException($"{requiresAttributeName} is not a valid supported Requires attribute"),
};
- ReportRequires(calledMember.GetDisplayName(), origin, diagnosticId, requiresAttribute);
+ ReportRequires(calledMember.GetDisplayName(), origin, diagnosticId, requiresAttribute.Value);
}
- static bool ShouldSuppressAnalysisWarningsForRequires(TypeSystemEntity originMember, string requiresAttribute)
+ internal static bool ShouldSuppressAnalysisWarningsForRequires(TypeSystemEntity originMember, string requiresAttribute)
{
// Check if the current scope method has Requires on it
// since that attribute automatically suppresses all trim analysis warnings.
@@ -103,7 +104,7 @@ namespace ILCompiler.Dataflow
return false;
}
- void ReportRequires(string displayName, in MessageOrigin currentOrigin, DiagnosticId diagnosticId, CustomAttributeValue<TypeDesc>? requiresAttribute)
+ void ReportRequires(string displayName, in MessageOrigin currentOrigin, DiagnosticId diagnosticId, CustomAttributeValue<TypeDesc> requiresAttribute)
{
string arg1 = MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage((CustomAttributeValue<TypeDesc>)requiresAttribute));
string arg2 = MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl((CustomAttributeValue<TypeDesc>)requiresAttribute));
@@ -119,17 +120,18 @@ namespace ILCompiler.Dataflow
private ScanningPurpose _purpose;
- private ReflectionMethodBodyScanner(NodeFactory factory, FlowAnnotations flowAnnotations, Logger logger, ScanningPurpose purpose = ScanningPurpose.Default)
+ private ReflectionMethodBodyScanner(NodeFactory factory, FlowAnnotations annotations, Logger logger, ScanningPurpose purpose = ScanningPurpose.Default)
{
- _flowAnnotations = flowAnnotations;
+ _annotations = annotations;
_logger = logger;
_factory = factory;
_purpose = purpose;
+ _reflectionMarker = new ReflectionMarker(logger, factory, annotations, purpose == ScanningPurpose.GetTypeDataflow);
}
- public static DependencyList ScanAndProcessReturnValue(NodeFactory factory, FlowAnnotations flowAnnotations, Logger logger, MethodIL methodBody)
+ public static DependencyList ScanAndProcessReturnValue(NodeFactory factory, FlowAnnotations annotations, Logger logger, MethodIL methodBody)
{
- var scanner = new ReflectionMethodBodyScanner(factory, flowAnnotations, logger);
+ var scanner = new ReflectionMethodBodyScanner(factory, annotations, logger);
Debug.Assert(methodBody.GetMethodILDefinition() == methodBody);
if (methodBody.OwningMethod.HasInstantiation || methodBody.OwningMethod.OwningType.HasInstantiation)
@@ -156,53 +158,34 @@ namespace ILCompiler.Dataflow
if (!methodBody.OwningMethod.Signature.ReturnType.IsVoid)
{
var method = methodBody.OwningMethod;
- var requiredMemberTypes = scanner._flowAnnotations.GetReturnParameterAnnotation(method);
- if (requiredMemberTypes != 0)
+ var methodReturnValue = scanner._annotations.GetMethodReturnValue(method);
+ if (methodReturnValue.DynamicallyAccessedMemberTypes != 0)
{
- var targetContext = new MethodReturnOrigin(method);
- bool shouldEnableReflectionWarnings = !ShouldSuppressAnalysisWarningsForRequires(method, RequiresUnreferencedCodeAttribute);
- var reflectionContext = new ReflectionPatternContext(scanner._logger,
- shouldEnableReflectionWarnings,
- method,
- targetContext);
- reflectionContext.AnalyzingPattern();
- scanner.RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, scanner.MethodReturnValue, targetContext);
- reflectionContext.Dispose();
+ var diagnosticContext = new DiagnosticContext(new MessageOrigin(method), !ShouldSuppressAnalysisWarningsForRequires(method, RequiresUnreferencedCodeAttribute), scanner._logger);
+ scanner.RequireDynamicallyAccessedMembers(diagnosticContext, scanner.ReturnValue, methodReturnValue, new MethodReturnOrigin(method));
}
}
- return scanner._dependencies;
+ return scanner._reflectionMarker.Dependencies;
}
- public static DependencyList ProcessAttributeDataflow(NodeFactory factory, FlowAnnotations flowAnnotations, Logger logger, MethodDesc method, CustomAttributeValue arguments)
+ public static DependencyList? ProcessAttributeDataflow(NodeFactory factory, FlowAnnotations annotations, Logger logger, MethodDesc method, CustomAttributeValue arguments)
{
- DependencyList result = null;
+ DependencyList? result = null;
// First do the dataflow for the constructor parameters if necessary.
- if (flowAnnotations.RequiresDataflowAnalysis(method))
+ if (annotations.RequiresDataflowAnalysis(method))
{
for (int i = 0; i < method.Signature.Length; i++)
{
- DynamicallyAccessedMemberTypes annotation = flowAnnotations.GetParameterAnnotation(method, i + 1);
- if (annotation != DynamicallyAccessedMemberTypes.None)
+ var parameterValue = annotations.GetMethodParameterValue(method, i);
+ if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None)
{
- ValueNode valueNode = GetValueNodeForCustomAttributeArgument(arguments.FixedArguments[i].Value);
- if (valueNode != null)
- {
- var targetContext = new ParameterOrigin(method, i);
- var reflectionContext = new ReflectionPatternContext(logger, true, method, targetContext);
- try
- {
- reflectionContext.AnalyzingPattern();
- var scanner = new ReflectionMethodBodyScanner(factory, flowAnnotations, logger);
- scanner.RequireDynamicallyAccessedMembers(ref reflectionContext, annotation, valueNode, targetContext);
- result = scanner._dependencies;
- }
- finally
- {
- reflectionContext.Dispose();
- }
- }
+ MultiValue value = GetValueForCustomAttributeArgument(arguments.FixedArguments[i].Value);
+ var diagnosticContext = new DiagnosticContext(new MessageOrigin(method), diagnosticsEnabled: true, logger);
+ var scanner = new ReflectionMethodBodyScanner(factory, annotations, logger);
+ scanner.RequireDynamicallyAccessedMembers(diagnosticContext, value, parameterValue, parameterValue.ParameterOrigin);
+ AddResults(scanner._reflectionMarker.Dependencies);
}
}
}
@@ -211,16 +194,14 @@ namespace ILCompiler.Dataflow
TypeDesc attributeType = method.OwningType;
foreach (var namedArgument in arguments.NamedArguments)
{
- TypeSystemEntity entity = null;
- DynamicallyAccessedMemberTypes annotation = DynamicallyAccessedMemberTypes.None;
- Origin targetContext = null;
+ MultiValue targetValues = new();
+ Origin? targetContext = null;
if (namedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
FieldDesc field = attributeType.GetField(namedArgument.Name);
if (field != null)
{
- annotation = flowAnnotations.GetFieldAnnotation(field);
- entity = field;
+ targetValues = GetFieldValue(field, annotations);
targetContext = new FieldOrigin(field);
}
}
@@ -231,59 +212,52 @@ namespace ILCompiler.Dataflow
MethodDesc setter = property.SetMethod;
if (setter != null && setter.Signature.Length > 0 && !setter.Signature.IsStatic)
{
- annotation = flowAnnotations.GetParameterAnnotation(setter, 1);
- entity = property;
+ targetValues = annotations.GetMethodParameterValue(setter, 0);
targetContext = new ParameterOrigin(setter, 1);
}
}
- if (annotation != DynamicallyAccessedMemberTypes.None)
+ foreach (var targetValueCandidate in targetValues)
{
- ValueNode valueNode = GetValueNodeForCustomAttributeArgument(namedArgument.Value);
- if (valueNode != null)
- {
- var reflectionContext = new ReflectionPatternContext(logger, true, method, targetContext);
- try
- {
- reflectionContext.AnalyzingPattern();
- var scanner = new ReflectionMethodBodyScanner(factory, flowAnnotations, logger);
- scanner.RequireDynamicallyAccessedMembers(ref reflectionContext, annotation, valueNode, targetContext);
- if (result == null)
- {
- result = scanner._dependencies;
- }
- else
- {
- result.AddRange(scanner._dependencies);
- }
- }
- finally
- {
- reflectionContext.Dispose();
- }
- }
+ if (targetValueCandidate is not ValueWithDynamicallyAccessedMembers targetValue ||
+ targetValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None)
+ continue;
+
+ MultiValue valueNode = GetValueForCustomAttributeArgument(namedArgument.Value);
+ var diagnosticContext = new DiagnosticContext(new MessageOrigin(method), diagnosticsEnabled: true, logger);
+ var scanner = new ReflectionMethodBodyScanner(factory, annotations, logger);
+ scanner.RequireDynamicallyAccessedMembers(diagnosticContext, valueNode, targetValue, targetContext!);
+ AddResults(scanner._reflectionMarker.Dependencies);
}
}
return result;
+
+ void AddResults(DependencyList dependencies)
+ {
+ if (result == null)
+ {
+ result = dependencies;
+ }
+ else
+ {
+ result.AddRange(dependencies);
+ }
+ }
}
public static DependencyList ProcessTypeGetTypeDataflow(NodeFactory factory, FlowAnnotations flowAnnotations, Logger logger, MetadataType type)
{
DynamicallyAccessedMemberTypes annotation = flowAnnotations.GetTypeAnnotation(type);
Debug.Assert(annotation != DynamicallyAccessedMemberTypes.None);
- var scanner = new ReflectionMethodBodyScanner(factory, flowAnnotations, logger, ScanningPurpose.GetTypeDataflow);
- ReflectionPatternContext reflectionPatternContext = new ReflectionPatternContext(logger, reportingEnabled: true, type, new TypeOrigin(type));
- reflectionPatternContext.AnalyzingPattern();
- scanner.MarkTypeForDynamicallyAccessedMembers(ref reflectionPatternContext, type, annotation);
- reflectionPatternContext.RecordHandledPattern();
- reflectionPatternContext.Dispose();
- return scanner._dependencies;
+ var reflectionMarker = new ReflectionMarker(logger, factory, flowAnnotations, true);
+ reflectionMarker.MarkTypeForDynamicallyAccessedMembers(new MessageOrigin(type), type, annotation, new TypeOrigin(type));
+ return reflectionMarker.Dependencies;
}
- static ValueNode GetValueNodeForCustomAttributeArgument(object argument)
+ static MultiValue GetValueForCustomAttributeArgument(object? argument)
{
- ValueNode result = null;
+ SingleValue? result = null;
if (argument is TypeDesc td)
{
result = new SystemTypeValue(td);
@@ -298,6 +272,7 @@ namespace ILCompiler.Dataflow
result = NullValue.Instance;
}
+ Debug.Assert(result != null);
return result;
}
@@ -305,18 +280,47 @@ namespace ILCompiler.Dataflow
{
var scanner = new ReflectionMethodBodyScanner(factory, flowAnnotations, logger);
- var annotation = flowAnnotations.GetGenericParameterAnnotation(genericParameter);
- Debug.Assert(annotation != DynamicallyAccessedMemberTypes.None);
+ var genericParameterValue = flowAnnotations.GetGenericParameterValue(genericParameter);
+ Debug.Assert(genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None);
- ValueNode valueNode = new SystemTypeValue(genericArgument);
+ MultiValue genericArgumentValue = scanner.GetTypeValueNodeFromGenericArgument(genericArgument);
+ bool enableDiagnostics = ShouldSuppressAnalysisWarningsForRequires(source, RequiresUnreferencedCodeAttribute);
+ var diagnosticContext = new DiagnosticContext(new MessageOrigin(source), diagnosticsEnabled: enableDiagnostics, logger);
var origin = new GenericParameterOrigin(genericParameter);
- var reflectionContext = new ReflectionPatternContext(logger, reportingEnabled: true, source, origin);
- reflectionContext.AnalyzingPattern();
- scanner.RequireDynamicallyAccessedMembers(ref reflectionContext, annotation, valueNode, origin);
- reflectionContext.Dispose();
+ scanner.RequireDynamicallyAccessedMembers(diagnosticContext, genericArgumentValue, genericParameterValue, origin);
+
+ return scanner._reflectionMarker.Dependencies;
+ }
- return scanner._dependencies;
+ MultiValue GetTypeValueNodeFromGenericArgument(TypeDesc genericArgument)
+ {
+ if (genericArgument is GenericParameterDesc inputGenericParameter)
+ {
+ return _annotations.GetGenericParameterValue(inputGenericParameter);
+ }
+ else if (genericArgument is MetadataType genericArgumentType)
+ {
+ if (genericArgumentType.IsTypeOf(WellKnownType.System_Nullable_T))
+ {
+ var innerGenericArgument = genericArgumentType.Instantiation.Length == 1 ? genericArgumentType.Instantiation[0] : null;
+ switch (innerGenericArgument)
+ {
+ case GenericParameterDesc gp:
+ return new NullableValueWithDynamicallyAccessedMembers(genericArgumentType,
+ new GenericParameterValue(gp, _annotations.GetGenericParameterAnnotation(gp)));
+
+ case TypeDesc underlyingType:
+ return new NullableSystemTypeValue(genericArgumentType, new SystemTypeValue(underlyingType));
+ }
+ }
+ // All values except for Nullable<T>, including Nullable<> (with no type arguments)
+ return new SystemTypeValue(genericArgumentType);
+ }
+ else
+ {
+ return UnknownValue.Instance;
+ }
}
protected override void WarnAboutInvalidILInMethod(MethodIL method, int ilOffset)
@@ -330,1972 +334,389 @@ namespace ILCompiler.Dataflow
Debug.Fail("Invalid IL or a bug in the scanner");
}
- protected override ValueNode GetMethodParameterValue(MethodDesc method, int parameterIndex)
+ protected override ValueWithDynamicallyAccessedMembers GetMethodParameterValue(MethodDesc method, int parameterIndex)
+ => GetMethodParameterValue(method, parameterIndex, _annotations.GetParameterAnnotation(method, parameterIndex));
+
+ ValueWithDynamicallyAccessedMembers GetMethodParameterValue(MethodDesc method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
{
- DynamicallyAccessedMemberTypes memberTypes = _flowAnnotations.GetParameterAnnotation(method, parameterIndex);
- return new MethodParameterValue(method, parameterIndex, memberTypes);
+ if (!method.Signature.IsStatic)
+ {
+ if (parameterIndex == 0)
+ return _annotations.GetMethodThisParameterValue(method, dynamicallyAccessedMemberTypes);
+
+ parameterIndex--;
+ }
+
+ return _annotations.GetMethodParameterValue(method, parameterIndex, dynamicallyAccessedMemberTypes);
}
- protected override ValueNode GetFieldValue(MethodIL method, FieldDesc field)
+ static MultiValue GetFieldValue(FieldDesc field, FlowAnnotations annotations)
{
switch (field.Name)
{
- case "EmptyTypes" when field.OwningType.IsTypeOf("System", "Type"):
+ case "EmptyTypes" when field.OwningType.IsTypeOf(ILLink.Shared.TypeSystemProxy.WellKnownType.System_Type):
{
- return new ArrayValue(new ConstIntValue(0), field.OwningType);
+ return ArrayValue.Create(0, field.OwningType);
}
- case "Empty" when field.OwningType.IsTypeOf("System", "String"):
+ case "Empty" when field.OwningType.IsTypeOf(ILLink.Shared.TypeSystemProxy.WellKnownType.System_String):
{
return new KnownStringValue(string.Empty);
}
default:
{
- DynamicallyAccessedMemberTypes memberTypes = _flowAnnotations.GetFieldAnnotation(field);
- return new LoadFieldValue(field, memberTypes);
+ DynamicallyAccessedMemberTypes memberTypes = annotations.GetFieldAnnotation(field);
+ return new FieldValue(field, memberTypes);
}
}
}
- protected override void HandleStoreField(MethodIL methodBody, int offset, FieldDesc field, ValueNode valueToStore)
+ protected override MultiValue GetFieldValue(FieldDesc field)
{
- var requiredMemberTypes = _flowAnnotations.GetFieldAnnotation(field);
- if (requiredMemberTypes != 0)
- {
- var origin = new FieldOrigin(field);
- bool shouldEnableReflectionWarnings = !ShouldSuppressAnalysisWarningsForRequires(methodBody.OwningMethod, RequiresUnreferencedCodeAttribute);
- var reflectionContext = new ReflectionPatternContext(_logger, shouldEnableReflectionWarnings, methodBody, offset, origin);
- reflectionContext.AnalyzingPattern();
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, valueToStore, origin);
- reflectionContext.Dispose();
- }
- CheckAndReportRequires(field, new MessageOrigin(methodBody.OwningMethod), RequiresUnreferencedCodeAttribute);
- CheckAndReportRequires(field, new MessageOrigin(methodBody.OwningMethod), RequiresDynamicCodeAttribute);
+ return GetFieldValue(field, _annotations);
}
- protected override void HandleStoreParameter(MethodIL method, int offset, int index, ValueNode valueToStore)
+ protected override void HandleStoreField(MethodIL methodBody, int offset, FieldValue field, MultiValue valueToStore)
{
- var requiredMemberTypes = _flowAnnotations.GetParameterAnnotation(method.OwningMethod, index);
- if (requiredMemberTypes != 0)
+ if (field.DynamicallyAccessedMemberTypes != 0)
{
- Origin parameter = DiagnosticUtilities.GetMethodParameterFromIndex(method.OwningMethod, index);
- bool shouldEnableReflectionWarnings = !ShouldSuppressAnalysisWarningsForRequires(method.OwningMethod, RequiresUnreferencedCodeAttribute);
- var reflectionContext = new ReflectionPatternContext(_logger, shouldEnableReflectionWarnings, method, offset, parameter);
- reflectionContext.AnalyzingPattern();
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, valueToStore, parameter);
- reflectionContext.Dispose();
+ var diagnosticContext = new DiagnosticContext(new MessageOrigin(methodBody, offset), !ShouldSuppressAnalysisWarningsForRequires(methodBody.OwningMethod, RequiresUnreferencedCodeAttribute), _logger);
+ RequireDynamicallyAccessedMembers(diagnosticContext, valueToStore, field, new FieldOrigin(field.Field));
}
- }
- enum IntrinsicId
- {
- None = 0,
- IntrospectionExtensions_GetTypeInfo,
- Type_GetTypeFromHandle,
- Type_get_TypeHandle,
- Object_GetType,
- TypeDelegator_Ctor,
- Array_Empty,
- TypeInfo_AsType,
- MethodBase_GetMethodFromHandle,
-
- // Anything above this marker will require the method to be run through
- // the reflection body scanner.
- RequiresReflectionBodyScanner_Sentinel = 1000,
- Type_MakeGenericType,
- Type_GetType,
- Type_GetConstructor,
- Type_GetConstructors,
- Type_GetMethod,
- Type_GetMethods,
- Type_GetField,
- Type_GetFields,
- Type_GetProperty,
- Type_GetProperties,
- Type_GetEvent,
- Type_GetEvents,
- Type_GetNestedType,
- Type_GetNestedTypes,
- Type_GetMember,
- Type_GetMembers,
- Type_GetInterface,
- Type_get_AssemblyQualifiedName,
- Type_get_UnderlyingSystemType,
- Type_get_BaseType,
- Expression_Call,
- Expression_Field,
- Expression_Property,
- Expression_New,
- Enum_GetValues,
- Marshal_SizeOf,
- Marshal_OffsetOf,
- Marshal_PtrToStructure,
- Marshal_DestroyStructure,
- Marshal_GetDelegateForFunctionPointer,
- Activator_CreateInstance_Type,
- Activator_CreateInstance_AssemblyName_TypeName,
- Activator_CreateInstanceFrom,
- Activator_CreateInstanceOfT,
- AppDomain_CreateInstance,
- AppDomain_CreateInstanceAndUnwrap,
- AppDomain_CreateInstanceFrom,
- AppDomain_CreateInstanceFromAndUnwrap,
- Assembly_CreateInstance,
- RuntimeReflectionExtensions_GetRuntimeEvent,
- RuntimeReflectionExtensions_GetRuntimeField,
- RuntimeReflectionExtensions_GetRuntimeMethod,
- RuntimeReflectionExtensions_GetRuntimeProperty,
- RuntimeHelpers_RunClassConstructor,
- MethodInfo_MakeGenericMethod,
+ CheckAndReportRequires(field.Field, new MessageOrigin(methodBody.OwningMethod), RequiresUnreferencedCodeAttribute);
+ CheckAndReportRequires(field.Field, new MessageOrigin(methodBody.OwningMethod), RequiresDynamicCodeAttribute);
}
- static IntrinsicId GetIntrinsicIdForMethod(MethodDesc calledMethod)
+ protected override void HandleStoreParameter(MethodIL method, int offset, MethodParameterValue parameter, MultiValue valueToStore)
{
- return calledMethod.Name switch
+ if (parameter.DynamicallyAccessedMemberTypes != 0)
{
- // static System.Reflection.IntrospectionExtensions.GetTypeInfo (Type type)
- "GetTypeInfo" when calledMethod.IsDeclaredOnType("System.Reflection", "IntrospectionExtensions") => IntrinsicId.IntrospectionExtensions_GetTypeInfo,
-
- // System.Reflection.TypeInfo.AsType ()
- "AsType" when calledMethod.IsDeclaredOnType("System.Reflection", "TypeInfo") => IntrinsicId.TypeInfo_AsType,
-
- // System.Type.GetTypeInfo (Type type)
- "GetTypeFromHandle" when calledMethod.IsDeclaredOnType("System", "Type") => IntrinsicId.Type_GetTypeFromHandle,
-
- // System.Type.GetTypeHandle (Type type)
- "get_TypeHandle" when calledMethod.IsDeclaredOnType("System", "Type") => IntrinsicId.Type_get_TypeHandle,
-
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
- "GetMethodFromHandle" when calledMethod.IsDeclaredOnType("System.Reflection", "MethodBase")
- && calledMethod.HasParameterOfType(0, "System", "RuntimeMethodHandle")
- && (calledMethod.Signature.Length == 1 || calledMethod.Signature.Length == 2)
- => IntrinsicId.MethodBase_GetMethodFromHandle,
-
- // static System.Type.MakeGenericType (Type [] typeArguments)
- "MakeGenericType" when calledMethod.IsDeclaredOnType("System", "Type") => IntrinsicId.Type_MakeGenericType,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeEvent (this Type type, string name)
- "GetRuntimeEvent" when calledMethod.IsDeclaredOnType("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeField (this Type type, string name)
- "GetRuntimeField" when calledMethod.IsDeclaredOnType("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeMethod (this Type type, string name, Type[] parameters)
- "GetRuntimeMethod" when calledMethod.IsDeclaredOnType("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod,
-
- // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeProperty (this Type type, string name)
- "GetRuntimeProperty" when calledMethod.IsDeclaredOnType("System.Reflection", "RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty,
-
- // static System.Linq.Expressions.Expression.Call (Type, String, Type[], Expression[])
- "Call" when calledMethod.IsDeclaredOnType("System.Linq.Expressions", "Expression")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.Signature.Length == 4
- => IntrinsicId.Expression_Call,
-
- // static System.Linq.Expressions.Expression.Field (Expression, Type, String)
- "Field" when calledMethod.IsDeclaredOnType("System.Linq.Expressions", "Expression")
- && calledMethod.HasParameterOfType(1, "System", "Type")
- && calledMethod.Signature.Length == 3
- => IntrinsicId.Expression_Field,
-
- // static System.Linq.Expressions.Expression.Property (Expression, Type, String)
- // static System.Linq.Expressions.Expression.Property (Expression, MethodInfo)
- "Property" when calledMethod.IsDeclaredOnType("System.Linq.Expressions", "Expression")
- && ((calledMethod.HasParameterOfType(1, "System", "Type") && calledMethod.Signature.Length == 3)
- || (calledMethod.HasParameterOfType(1, "System.Reflection", "MethodInfo") && calledMethod.Signature.Length == 2))
- => IntrinsicId.Expression_Property,
-
- // static System.Linq.Expressions.Expression.New (Type)
- "New" when calledMethod.IsDeclaredOnType("System.Linq.Expressions", "Expression")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.Signature.Length == 1
- => IntrinsicId.Expression_New,
-
- // static Array System.Enum.GetValues (Type)
- "GetValues" when calledMethod.IsDeclaredOnType("System", "Enum")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.Signature.Length == 1
- => IntrinsicId.Enum_GetValues,
-
- // static int System.Runtime.InteropServices.Marshal.SizeOf (Type)
- "SizeOf" when calledMethod.IsDeclaredOnType("System.Runtime.InteropServices", "Marshal")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.Signature.Length == 1
- => IntrinsicId.Marshal_SizeOf,
-
- // static int System.Runtime.InteropServices.Marshal.OffsetOf (Type, string)
- "OffsetOf" when calledMethod.IsDeclaredOnType("System.Runtime.InteropServices", "Marshal")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- && calledMethod.Signature.Length == 2
- => IntrinsicId.Marshal_OffsetOf,
-
- // static object System.Runtime.InteropServices.Marshal.PtrToStructure (IntPtr, Type)
- "PtrToStructure" when calledMethod.IsDeclaredOnType("System.Runtime.InteropServices", "Marshal")
- && calledMethod.HasParameterOfType(1, "System", "Type")
- && calledMethod.Signature.Length == 2
- => IntrinsicId.Marshal_PtrToStructure,
-
- // static void System.Runtime.InteropServices.Marshal.DestroyStructure (IntPtr, Type)
- "DestroyStructure" when calledMethod.IsDeclaredOnType("System.Runtime.InteropServices", "Marshal")
- && calledMethod.HasParameterOfType(1, "System", "Type")
- && calledMethod.Signature.Length == 2
- => IntrinsicId.Marshal_DestroyStructure,
-
- // static Delegate System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer (IntPtr, Type)
- "GetDelegateForFunctionPointer" when calledMethod.IsDeclaredOnType("System.Runtime.InteropServices", "Marshal")
- && calledMethod.HasParameterOfType(1, "System", "Type")
- && calledMethod.Signature.Length == 2
- => IntrinsicId.Marshal_GetDelegateForFunctionPointer,
-
- // static System.Type.GetType (string)
- // static System.Type.GetType (string, Boolean)
- // static System.Type.GetType (string, Boolean, Boolean)
- // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>)
- // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
- // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
- "GetType" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- => IntrinsicId.Type_GetType,
-
- // System.Type.GetConstructor (Type[])
- // System.Type.GetConstructor (BindingFlags, Type[])
- // System.Type.GetConstructor (BindingFlags, Binder, Type[], ParameterModifier [])
- // System.Type.GetConstructor (BindingFlags, Binder, CallingConventions, Type[], ParameterModifier [])
- "GetConstructor" when calledMethod.IsDeclaredOnType("System", "Type")
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetConstructor,
-
- // System.Type.GetConstructors (BindingFlags)
- "GetConstructors" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System.Reflection", "BindingFlags")
- && calledMethod.Signature.Length == 1
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetConstructors,
-
- // System.Type.GetMethod (string)
- // System.Type.GetMethod (string, BindingFlags)
- // System.Type.GetMethod (string, Type[])
- // System.Type.GetMethod (string, Type[], ParameterModifier[])
- // System.Type.GetMethod (string, BindingFlags, Type[])
- // System.Type.GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
- // System.Type.GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
- // System.Type.GetMethod (string, int, Type[])
- // System.Type.GetMethod (string, int, Type[], ParameterModifier[]?)
- // System.Type.GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
- // System.Type.GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
- "GetMethod" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetMethod,
-
- // System.Type.GetMethods (BindingFlags)
- "GetMethods" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System.Reflection", "BindingFlags")
- && calledMethod.Signature.Length == 1
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetMethods,
-
- // System.Type.GetField (string)
- // System.Type.GetField (string, BindingFlags)
- "GetField" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetField,
-
- // System.Type.GetFields (BindingFlags)
- "GetFields" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System.Reflection", "BindingFlags")
- && calledMethod.Signature.Length == 1
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetFields,
-
- // System.Type.GetEvent (string)
- // System.Type.GetEvent (string, BindingFlags)
- "GetEvent" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetEvent,
-
- // System.Type.GetEvents (BindingFlags)
- "GetEvents" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System.Reflection", "BindingFlags")
- && calledMethod.Signature.Length == 1
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetEvents,
-
- // System.Type.GetNestedType (string)
- // System.Type.GetNestedType (string, BindingFlags)
- "GetNestedType" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetNestedType,
-
- // System.Type.GetNestedTypes (BindingFlags)
- "GetNestedTypes" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System.Reflection", "BindingFlags")
- && calledMethod.Signature.Length == 1
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetNestedTypes,
-
- // System.Type.GetMember (String)
- // System.Type.GetMember (String, BindingFlags)
- // System.Type.GetMember (String, MemberTypes, BindingFlags)
- "GetMember" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && !calledMethod.Signature.IsStatic
- && (calledMethod.Signature.Length == 1 ||
- (calledMethod.Signature.Length == 2 && calledMethod.HasParameterOfType(1, "System.Reflection", "BindingFlags")) ||
- (calledMethod.Signature.Length == 3 && calledMethod.HasParameterOfType(2, "System.Reflection", "BindingFlags")))
- => IntrinsicId.Type_GetMember,
-
- // System.Type.GetMembers (BindingFlags)
- "GetMembers" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System.Reflection", "BindingFlags")
- && calledMethod.Signature.Length == 1
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetMembers,
-
- // System.Type.GetInterface (string)
- // System.Type.GetInterface (string, bool)
- "GetInterface" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && !calledMethod.Signature.IsStatic
- && (calledMethod.Signature.Length == 1 ||
- (calledMethod.Signature.Length == 2 && calledMethod.Signature[1].IsWellKnownType(WellKnownType.Boolean)))
- => IntrinsicId.Type_GetInterface,
-
- // System.Type.AssemblyQualifiedName
- "get_AssemblyQualifiedName" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.Signature.Length == 0
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_get_AssemblyQualifiedName,
-
- // System.Type.UnderlyingSystemType
- "get_UnderlyingSystemType" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.Signature.Length == 0
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_get_UnderlyingSystemType,
-
- // System.Type.BaseType
- "get_BaseType" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.Signature.Length == 0
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_get_BaseType,
-
- // System.Type.GetProperty (string)
- // System.Type.GetProperty (string, BindingFlags)
- // System.Type.GetProperty (string, Type)
- // System.Type.GetProperty (string, Type[])
- // System.Type.GetProperty (string, Type, Type[])
- // System.Type.GetProperty (string, Type, Type[], ParameterModifier[])
- // System.Type.GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
- "GetProperty" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetProperty,
-
- // System.Type.GetProperties (BindingFlags)
- "GetProperties" when calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.HasParameterOfType(0, "System.Reflection", "BindingFlags")
- && calledMethod.Signature.Length == 1
- && !calledMethod.Signature.IsStatic
- => IntrinsicId.Type_GetProperties,
-
- // static System.Object.GetType ()
- "GetType" when calledMethod.IsDeclaredOnType("System", "Object")
- => IntrinsicId.Object_GetType,
-
- ".ctor" when calledMethod.IsDeclaredOnType("System.Reflection", "TypeDelegator")
- && calledMethod.HasParameterOfType(0, "System", "Type")
- => IntrinsicId.TypeDelegator_Ctor,
-
- "Empty" when calledMethod.IsDeclaredOnType("System", "Array")
- => IntrinsicId.Array_Empty,
-
- // static System.Activator.CreateInstance (System.Type type)
- // static System.Activator.CreateInstance (System.Type type, bool nonPublic)
- // static System.Activator.CreateInstance (System.Type type, params object?[]? args)
- // static System.Activator.CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
- // static System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
- // static System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
- "CreateInstance" when calledMethod.IsDeclaredOnType("System", "Activator")
- && !calledMethod.HasInstantiation
- && calledMethod.HasParameterOfType(0, "System", "Type")
- => IntrinsicId.Activator_CreateInstance_Type,
-
- // static System.Activator.CreateInstance (string assemblyName, string typeName)
- // static System.Activator.CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
- // static System.Activator.CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
- "CreateInstance" when calledMethod.IsDeclaredOnType("System", "Activator")
- && !calledMethod.HasInstantiation
- && calledMethod.HasParameterOfType(0, "System", "String")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName,
-
- // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName)
- // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- "CreateInstanceFrom" when calledMethod.IsDeclaredOnType("System", "Activator")
- && !calledMethod.HasInstantiation
- && calledMethod.HasParameterOfType(0, "System", "String")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.Activator_CreateInstanceFrom,
-
- // static T System.Activator.CreateInstance<T> ()
- "CreateInstance" when calledMethod.IsDeclaredOnType("System", "Activator")
- && calledMethod.HasInstantiation
- && calledMethod.Instantiation.Length == 1
- && calledMethod.Signature.Length == 0
- => IntrinsicId.Activator_CreateInstanceOfT,
-
- // System.AppDomain.CreateInstance (string assemblyName, string typeName)
- // System.AppDomain.CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
- "CreateInstance" when calledMethod.IsDeclaredOnType("System", "AppDomain")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstance,
-
- // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName)
- // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
- "CreateInstanceAndUnwrap" when calledMethod.IsDeclaredOnType("System", "AppDomain")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstanceAndUnwrap,
-
- // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName)
- // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- "CreateInstanceFrom" when calledMethod.IsDeclaredOnType("System", "AppDomain")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstanceFrom,
-
- // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
- // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
- "CreateInstanceFromAndUnwrap" when calledMethod.IsDeclaredOnType("System", "AppDomain")
- && calledMethod.HasParameterOfType(0, "System", "String")
- && calledMethod.HasParameterOfType(1, "System", "String")
- => IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap,
-
- // System.Reflection.Assembly.CreateInstance (string typeName)
- // System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase)
- // System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
- "CreateInstance" when calledMethod.IsDeclaredOnType("System.Reflection", "Assembly")
- && calledMethod.HasParameterOfType(0, "System", "String")
- => IntrinsicId.Assembly_CreateInstance,
-
- // System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (RuntimeTypeHandle type)
- "RunClassConstructor" when calledMethod.IsDeclaredOnType("System.Runtime.CompilerServices", "RuntimeHelpers")
- && calledMethod.HasParameterOfType(0, "System", "RuntimeTypeHandle")
- => IntrinsicId.RuntimeHelpers_RunClassConstructor,
-
- // System.Reflection.MethodInfo.MakeGenericMethod (Type[] typeArguments)
- "MakeGenericMethod" when calledMethod.IsDeclaredOnType("System.Reflection", "MethodInfo")
- && !calledMethod.Signature.IsStatic
- && calledMethod.Signature.Length == 1
- => IntrinsicId.MethodInfo_MakeGenericMethod,
-
- _ => IntrinsicId.None,
- };
+ var diagnosticContext = new DiagnosticContext(new MessageOrigin(method, offset), !ShouldSuppressAnalysisWarningsForRequires(method.OwningMethod, RequiresUnreferencedCodeAttribute), _logger);
+ RequireDynamicallyAccessedMembers(diagnosticContext, valueToStore, parameter, parameter.ParameterOrigin);
+ }
}
- public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMethod, ILOpcode operation, int offset, ValueNodeList methodParams, out ValueNode methodReturnValue)
+ public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMethod, ILOpcode operation, int offset, ValueNodeList methodParams, out MultiValue methodReturnValue)
{
methodReturnValue = null;
+ MultiValue? maybeMethodReturnValue = null;
var callingMethodDefinition = callingMethodBody.OwningMethod;
bool shouldEnableReflectionWarnings = !ShouldSuppressAnalysisWarningsForRequires(callingMethodDefinition, RequiresUnreferencedCodeAttribute);
- var reflectionContext = new ReflectionPatternContext(_logger, shouldEnableReflectionWarnings, callingMethodBody, offset, new MethodOrigin(calledMethod));
+ bool shouldEnableAotWarnings = !ShouldSuppressAnalysisWarningsForRequires(callingMethodDefinition, RequiresDynamicCodeAttribute);
DynamicallyAccessedMemberTypes returnValueDynamicallyAccessedMemberTypes = 0;
- try
- {
-
- bool requiresDataFlowAnalysis = _flowAnnotations.RequiresDataflowAnalysis(calledMethod);
- returnValueDynamicallyAccessedMemberTypes = requiresDataFlowAnalysis ?
- _flowAnnotations.GetReturnParameterAnnotation(calledMethod) : 0;
-
- var intrinsicId = GetIntrinsicIdForMethod(calledMethod);
- switch (intrinsicId)
- {
- case IntrinsicId.IntrospectionExtensions_GetTypeInfo:
- {
- // typeof(Foo).GetTypeInfo()... will be commonly present in code targeting
- // the dead-end reflection refactoring. The call doesn't do anything and we
- // don't want to lose the annotation.
- methodReturnValue = methodParams[0];
- }
- break;
-
- case IntrinsicId.TypeInfo_AsType:
+ bool requiresDataFlowAnalysis = _annotations.RequiresDataflowAnalysis(calledMethod);
+ returnValueDynamicallyAccessedMemberTypes = requiresDataFlowAnalysis ?
+ _annotations.GetReturnParameterAnnotation(calledMethod) : 0;
+
+ var diagnosticContext = new DiagnosticContext(new MessageOrigin(callingMethodBody, offset), shouldEnableReflectionWarnings, _logger);
+ var handleCallAction = new HandleCallAction(_annotations, _reflectionMarker, diagnosticContext, callingMethodDefinition, new MethodOrigin(calledMethod));
+
+ var intrinsicId = Intrinsics.GetIntrinsicIdForMethod(calledMethod);
+ switch (intrinsicId)
+ {
+ case IntrinsicId.IntrospectionExtensions_GetTypeInfo:
+ case IntrinsicId.TypeInfo_AsType:
+ case IntrinsicId.Type_get_UnderlyingSystemType:
+ case IntrinsicId.Type_GetTypeFromHandle:
+ case IntrinsicId.Type_get_TypeHandle:
+ case IntrinsicId.Type_GetInterface:
+ case IntrinsicId.Type_get_AssemblyQualifiedName:
+ case IntrinsicId.RuntimeHelpers_RunClassConstructor:
+ case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
+ callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
+ && calledMethod.OwningType.IsTypeOf(WellKnownType.System_Type)
+ && calledMethod.Signature[0].IsTypeOf("System.Reflection.BindingFlags")
+ && !calledMethod.Signature.IsStatic:
+ case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
+ && calledMethod.OwningType.IsTypeOf(WellKnownType.System_Type)
+ && calledMethod.Signature[0].IsTypeOf(WellKnownType.System_String)
+ && !calledMethod.Signature.IsStatic:
+ case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
+ case IntrinsicId.Type_GetMember:
+ case IntrinsicId.Type_GetMethod:
+ case IntrinsicId.Type_GetNestedType:
+ case IntrinsicId.Nullable_GetUnderlyingType:
+ case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType(1, "System.Reflection.MethodInfo"):
+ case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property:
+ case IntrinsicId.Type_get_BaseType:
+ case IntrinsicId.Type_GetConstructor:
+ case IntrinsicId.MethodBase_GetMethodFromHandle:
+ case IntrinsicId.MethodBase_get_MethodHandle:
+ case IntrinsicId.Type_MakeGenericType:
+ case IntrinsicId.MethodInfo_MakeGenericMethod:
+ case IntrinsicId.Expression_Call:
+ case IntrinsicId.Expression_New:
+ case IntrinsicId.Type_GetType:
+ case IntrinsicId.Activator_CreateInstance_Type:
+ case IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName:
+ case IntrinsicId.Activator_CreateInstanceFrom:
+ case var appDomainCreateInstance when appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstance
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceAndUnwrap
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFrom
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap:
+ case IntrinsicId.Assembly_CreateInstance:
+ {
+ var instanceValue = MultiValueLattice.Top;
+ IReadOnlyList<MultiValue> parameterValues = methodParams;
+ if (!calledMethod.Signature.IsStatic)
{
- // someType.AsType()... will be commonly present in code targeting
- // the dead-end reflection refactoring. The call doesn't do anything and we
- // don't want to lose the annotation.
- methodReturnValue = methodParams[0];
+ instanceValue = methodParams[0];
+ parameterValues = parameterValues.Skip(1).ToImmutableList();
}
- break;
+ bool result = handleCallAction.Invoke(calledMethod, instanceValue, parameterValues, out methodReturnValue, out _);
- case IntrinsicId.TypeDelegator_Ctor:
+ // Special case some intrinsics for AOT handling (on top of the trimming handling done in the HandleCallAction)
+ switch (intrinsicId)
{
- // This is an identity function for analysis purposes
- if (operation == ILOpcode.newobj)
- methodReturnValue = methodParams[1];
+ case IntrinsicId.Type_MakeGenericType:
+ case IntrinsicId.MethodInfo_MakeGenericMethod:
+ CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
+ break;
}
- break;
- case IntrinsicId.Array_Empty:
- {
- methodReturnValue = new ArrayValue(new ConstIntValue(0), calledMethod.Instantiation[0]);
- }
- break;
+ return result;
+ }
- case IntrinsicId.Type_GetTypeFromHandle:
+ case IntrinsicId.None:
+ {
+ if (calledMethod.IsPInvoke)
{
- // Infrastructure piece to support "typeof(Foo)"
- if (methodParams[0] is RuntimeTypeHandleValue typeHandle)
- methodReturnValue = new SystemTypeValue(typeHandle.TypeRepresented);
- else if (methodParams[0] is RuntimeTypeHandleForGenericParameterValue typeHandleForGenericParameter)
- {
- methodReturnValue = new SystemTypeForGenericParameterValue(
- typeHandleForGenericParameter.GenericParameter,
- _flowAnnotations.GetGenericParameterAnnotation(typeHandleForGenericParameter.GenericParameter));
- }
- }
- break;
+ // Is the PInvoke dangerous?
+ ParameterMetadata[] paramMetadata = calledMethod.GetParameterMetadata();
- case IntrinsicId.Type_get_TypeHandle:
- {
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue typeValue)
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new RuntimeTypeHandleValue(typeValue.TypeRepresented));
- else if (value == NullValue.Instance)
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, value);
- else
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, UnknownValue.Instance);
- }
- }
- break;
+ ParameterMetadata returnParamMetadata = Array.Find(paramMetadata, m => m.Index == 0);
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
- case IntrinsicId.MethodBase_GetMethodFromHandle:
- {
- // Infrastructure piece to support "ldtoken method -> GetMethodFromHandle"
- if (methodParams[0] is RuntimeMethodHandleValue methodHandle)
- methodReturnValue = new SystemReflectionMethodBaseValue(methodHandle.MethodRepresented);
- }
- break;
-
- //
- // System.Type
- //
- // Type MakeGenericType (params Type[] typeArguments)
- //
- case IntrinsicId.Type_MakeGenericType:
- {
- reflectionContext.AnalyzingPattern();
- foreach (var value in methodParams[0].UniqueValues())
+ bool comDangerousMethod = IsComInterop(returnParamMetadata.MarshalAsDescriptor, calledMethod.Signature.ReturnType);
+ for (int paramIndex = 0; paramIndex < calledMethod.Signature.Length; paramIndex++)
{
- if (value is SystemTypeValue typeValue)
- {
- if (AnalyzeGenericInstantiationTypeArray(methodParams[1], ref reflectionContext, calledMethod, typeValue.TypeRepresented.GetTypeDefinition().Instantiation))
- {
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- bool hasUncheckedAnnotation = false;
- foreach (GenericParameterDesc genericParameter in typeValue.TypeRepresented.GetTypeDefinition().Instantiation)
- {
- if (_flowAnnotations.GetGenericParameterAnnotation(genericParameter) != DynamicallyAccessedMemberTypes.None ||
- (genericParameter.HasDefaultConstructorConstraint && !typeValue.TypeRepresented.IsNullable))
- {
- // If we failed to analyze the array, we go through the analyses again
- // and intentionally ignore one particular annotation:
- // Special case: Nullable<T> where T : struct
- // The struct constraint in C# implies new() constraints, but Nullable doesn't make a use of that part.
- // There are several places even in the framework where typeof(Nullable<>).MakeGenericType would warn
- // without any good reason to do so.
- hasUncheckedAnnotation = true;
- break;
- }
- }
- if (hasUncheckedAnnotation)
- {
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.MakeGenericType,
- new DiagnosticString(DiagnosticId.MakeGenericType).GetMessage(calledMethod.GetDisplayName()));
- }
- }
-
- // We haven't found any generic parameters with annotations, so there's nothing to validate.
- reflectionContext.RecordHandledPattern();
- }
- else if (value == NullValue.Instance)
- reflectionContext.RecordHandledPattern();
- else
+ MarshalAsDescriptor? marshalAsDescriptor = null;
+ for (int metadataIndex = 0; metadataIndex < paramMetadata.Length; metadataIndex++)
{
- // We have no way to "include more" to fix this if we don't know, so we have to warn
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.MakeGenericType,
- new DiagnosticString(DiagnosticId.MakeGenericType).GetMessage(calledMethod.GetDisplayName()));
+ if (paramMetadata[metadataIndex].Index == paramIndex + 1)
+ marshalAsDescriptor = paramMetadata[metadataIndex].MarshalAsDescriptor;
}
- }
-
- CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
- // We don't want to lose track of the type
- // in case this is e.g. Activator.CreateInstance(typeof(Foo<>).MakeGenericType(...));
- methodReturnValue = methodParams[0];
- }
- break;
-
- //
- // System.Reflection.RuntimeReflectionExtensions
- //
- // static GetRuntimeEvent (this Type type, string name)
- // static GetRuntimeField (this Type type, string name)
- // static GetRuntimeMethod (this Type type, string name, Type[] parameters)
- // static GetRuntimeProperty (this Type type, string name)
- //
- case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
- {
-
- reflectionContext.AnalyzingPattern();
- BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
- DynamicallyAccessedMemberTypes requiredMemberTypes = getRuntimeMember switch
- {
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent => DynamicallyAccessedMemberTypes.PublicEvents,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField => DynamicallyAccessedMemberTypes.PublicFields,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod => DynamicallyAccessedMemberTypes.PublicMethods,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty => DynamicallyAccessedMemberTypes.PublicProperties,
- _ => throw new Exception($"Reflection call '{calledMethod.GetDisplayName()}' inside '{callingMethodDefinition.GetDisplayName()}' is of unexpected member type."),
- };
-
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- foreach (var stringParam in methodParams[1].UniqueValues())
- {
- if (stringParam is KnownStringValue stringValue)
- {
- switch (getRuntimeMember)
- {
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent:
- MarkEventsOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, e => e.Name == stringValue.Contents, bindingFlags);
- reflectionContext.RecordHandledPattern();
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField:
- MarkFieldsOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, f => f.Name == stringValue.Contents, bindingFlags);
- reflectionContext.RecordHandledPattern();
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod:
- ProcessGetMethodByName(ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, bindingFlags, ref methodReturnValue);
- reflectionContext.RecordHandledPattern();
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
- MarkPropertiesOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, p => p.Name == stringValue.Contents, bindingFlags);
- reflectionContext.RecordHandledPattern();
- break;
- default:
- throw new Exception($"Error processing reflection call '{calledMethod.GetDisplayName()}' inside {callingMethodDefinition.GetDisplayName()}. Unexpected member kind.");
- }
- }
- else
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new ParameterOrigin(calledMethod, 0));
- }
- }
- }
- else
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new ParameterOrigin(calledMethod, 0));
- }
+ comDangerousMethod |= IsComInterop(marshalAsDescriptor, calledMethod.Signature[paramIndex]);
}
- }
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static Call (Type, String, Type[], Expression[])
- //
- case IntrinsicId.Expression_Call:
- {
- reflectionContext.AnalyzingPattern();
- BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
- bool hasTypeArguments = (methodParams[2] as ArrayValue)?.Size.AsConstInt() != 0;
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- foreach (var stringParam in methodParams[1].UniqueValues())
- {
- if (stringParam is KnownStringValue stringValue)
- {
- foreach (var method in systemTypeValue.TypeRepresented.GetMethodsOnTypeHierarchy(m => m.Name == stringValue.Contents, bindingFlags))
- {
- ValidateGenericMethodInstantiation(ref reflectionContext, method, methodParams[2], calledMethod);
- MarkMethod(ref reflectionContext, method);
- }
-
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- if (hasTypeArguments)
- {
- // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
- // that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.MakeGenericMethod,
- new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod)));
- }
-
- RequireDynamicallyAccessedMembers(
- ref reflectionContext,
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods(bindingFlags),
- value,
- new ParameterOrigin(calledMethod, 0));
- }
- }
- }
- else
- {
- if (hasTypeArguments)
- {
- // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
- // that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.MakeGenericMethod,
- new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod)));
- }
-
- RequireDynamicallyAccessedMembers(
- ref reflectionContext,
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods(bindingFlags),
- value,
- new ParameterOrigin(calledMethod, 0));
- }
- }
- }
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static Property (Expression, MethodInfo)
- //
- case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType(1, "System.Reflection", "MethodInfo"):
- {
- reflectionContext.AnalyzingPattern();
- foreach (var value in methodParams[1].UniqueValues())
+ if (comDangerousMethod)
{
- if (value is SystemReflectionMethodBaseValue methodBaseValue)
- {
- // We have one of the accessors for the property. The Expression.Property will in this case search
- // for the matching PropertyInfo and store that. So to be perfectly correct we need to mark the
- // respective PropertyInfo as "accessed via reflection".
- var propertyDefinition = methodBaseValue.MethodRepresented.GetPropertyForAccessor();
- if (propertyDefinition is not null)
- {
- MarkProperty(ref reflectionContext, propertyDefinition);
- continue;
- }
- }
- else if (value == NullValue.Instance)
- {
- reflectionContext.RecordHandledPattern();
- continue;
- }
- // In all other cases we may not even know which type this is about, so there's nothing we can do
- // report it as a warning.
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined,
- new DiagnosticString(DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined).GetMessage(
- DiagnosticUtilities.GetParameterNameForErrorMessage(new ParameterOrigin(calledMethod, 1)),
- DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod)));
+ diagnosticContext.AddDiagnostic(DiagnosticId.CorrectnessOfCOMCannotBeGuaranteed, calledMethod.GetDisplayName());
}
}
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static Field (Expression, Type, String)
- // static Property (Expression, Type, String)
- //
- case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property:
- {
- reflectionContext.AnalyzingPattern();
- DynamicallyAccessedMemberTypes memberTypes = fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property
- ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties
- : DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields;
- foreach (var value in methodParams[1].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- foreach (var stringParam in methodParams[2].UniqueValues())
- {
- if (stringParam is KnownStringValue stringValue)
- {
- BindingFlags bindingFlags = methodParams[0]?.Kind == ValueNodeKind.Null ? BindingFlags.Static : BindingFlags.Default;
- if (fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property)
- {
- MarkPropertiesOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, filter: p => p.Name == stringValue.Contents, bindingFlags);
- }
- else
- {
- MarkFieldsOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, filter: f => f.Name == stringValue.Contents, bindingFlags);
- }
-
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, memberTypes, value, new ParameterOrigin(calledMethod, 2));
- }
- }
- }
- else
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, memberTypes, value, new ParameterOrigin(calledMethod, 1));
- }
- }
- }
- break;
-
- //
- // System.Linq.Expressions.Expression
- //
- // static New (Type)
- //
- case IntrinsicId.Expression_New:
- {
- reflectionContext.AnalyzingPattern();
+ var origin = new MessageOrigin(callingMethodBody, offset);
+ CheckAndReportRequires(calledMethod, origin, RequiresUnreferencedCodeAttribute);
+ CheckAndReportRequires(calledMethod, origin, RequiresDynamicCodeAttribute);
+ CheckAndReportRequires(calledMethod, origin, RequiresAssemblyFilesAttribute);
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- MarkConstructorsOnType(ref reflectionContext, systemTypeValue.TypeRepresented, null, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, value, new ParameterOrigin(calledMethod, 0));
- }
- }
- }
- break;
-
- //
- // System.Enum
- //
- // static GetValues (Type)
- //
- case IntrinsicId.Enum_GetValues:
+ var instanceValue = MultiValueLattice.Top;
+ IReadOnlyList<MultiValue> parameterValues = methodParams;
+ if (!calledMethod.Signature.IsStatic)
{
- // Enum.GetValues returns System.Array, but it's the array of the enum type under the hood
- // and people depend on this undocumented detail (could have returned enum of the underlying
- // type instead).
- //
- // At least until we have shared enum code, this needs extra handling to get it right.
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue
- && !systemTypeValue.TypeRepresented.IsGenericDefinition
- && !systemTypeValue.TypeRepresented.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true))
- {
- if (systemTypeValue.TypeRepresented.IsEnum)
- {
- _dependencies.Add(_factory.ConstructedTypeSymbol(systemTypeValue.TypeRepresented.MakeArrayType()), "Enum.GetValues");
- }
- }
- else
- CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset),RequiresDynamicCodeAttribute);
- }
+ instanceValue = methodParams[0];
+ parameterValues = parameterValues.Skip(1).ToImmutableList();
}
- break;
-
- //
- // System.Runtime.InteropServices.Marshal
- //
- // static SizeOf (Type)
- // static PtrToStructure (IntPtr, Type)
- // static DestroyStructure (IntPtr, Type)
- // static OffsetOf (Type, string)
- //
- case IntrinsicId.Marshal_SizeOf:
- case IntrinsicId.Marshal_PtrToStructure:
- case IntrinsicId.Marshal_DestroyStructure:
- case IntrinsicId.Marshal_OffsetOf:
- {
- int paramIndex = intrinsicId == IntrinsicId.Marshal_SizeOf
- || intrinsicId == IntrinsicId.Marshal_OffsetOf
- ? 0 : 1;
-
- // We need the data to do struct marshalling.
- foreach (var value in methodParams[paramIndex].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue
- && !systemTypeValue.TypeRepresented.IsGenericDefinition
- && !systemTypeValue.TypeRepresented.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true))
- {
- if (systemTypeValue.TypeRepresented.IsDefType)
- {
- _dependencies.Add(_factory.StructMarshallingData((DefType)systemTypeValue.TypeRepresented), "Marshal API");
- }
- }
- else
- CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
- }
- }
- break;
-
- //
- // System.Runtime.InteropServices.Marshal
- //
- // static GetDelegateForFunctionPointer (IntPtr, Type)
- //
- case IntrinsicId.Marshal_GetDelegateForFunctionPointer:
- {
- // We need the data to do delegate marshalling.
- foreach (var value in methodParams[1].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue
- && !systemTypeValue.TypeRepresented.IsGenericDefinition
- && !systemTypeValue.TypeRepresented.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true))
- {
- if (systemTypeValue.TypeRepresented.IsDefType)
- {
- _dependencies.Add(_factory.DelegateMarshallingData((DefType)systemTypeValue.TypeRepresented), "Marshal API");
- }
- }
- else
- CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
- }
- }
- break;
-
- //
- // System.Object
- //
- // GetType()
- //
- case IntrinsicId.Object_GetType:
- {
- foreach (var valueNode in methodParams[0].UniqueValues())
- {
- // Note that valueNode can be statically typed in IL as some generic argument type.
- // For example:
- // void Method<T>(T instance) { instance.GetType().... }
- // Currently this case will end up with null StaticType - since there's no typedef for the generic argument type.
- // But it could be that T is annotated with for example PublicMethods:
- // void Method<[DAM(PublicMethods)] T>(T instance) { instance.GetType().GetMethod("Test"); }
- // In this case it's in theory possible to handle it, by treating the T basically as a base class
- // for the actual type of "instance". But the analysis for this would be pretty complicated (as the marking
- // has to happen on the callsite, which doesn't know that GetType() will be used...).
- // For now we're intentionally ignoring this case - it will produce a warning.
- // The counter example is:
- // Method<Base>(new Derived);
- // In this case to get correct results, trimmer would have to mark all public methods on Derived. Which
- // currently it won't do.
-
- TypeDesc staticType = valueNode.StaticType;
- 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"
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new MethodReturnValue(calledMethod, DynamicallyAccessedMemberTypes.None));
- }
- else if (staticType.IsSealed() || staticType.IsTypeOf("System", "Delegate"))
- {
- // We can treat this one the same as if it was a typeof() expression
-
- // We can allow Object.GetType to be modeled as System.Delegate because we keep all methods
- // on delegates anyway so reflection on something this approximation would miss is actually safe.
-
- // We ignore the fact that the type can be annotated (see below for handling of annotated types)
- // This means the annotations (if any) won't be applied - instead we rely on the exact knowledge
- // of the type. So for example even if the type is annotated with PublicMethods
- // but the code calls GetProperties on it - it will work - mark properties, don't mark methods
- // since we ignored the fact that it's annotated.
- // This can be seen a little bit as a violation of the annotation, but we already have similar cases
- // where a parameter is annotated and if something in the method sets a specific known type to it
- // we will also make it just work, even if the annotation doesn't match the usage.
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new SystemTypeValue(staticType));
- }
- else
- {
- reflectionContext.AnalyzingPattern();
-
- Debug.Assert(staticType is MetadataType || staticType.IsArray);
- MetadataType closestMetadataType = staticType is MetadataType mdType ?
- mdType : (MetadataType)_factory.TypeSystemContext.GetWellKnownType(WellKnownType.Array);
-
- var annotation = _flowAnnotations.GetTypeAnnotation(staticType);
-
- if (annotation != default)
- {
- _dependencies.Add(_factory.ObjectGetTypeFlowDependencies(closestMetadataType), "GetType called on this type");
- }
-
- reflectionContext.RecordHandledPattern();
-
- // 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.
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new MethodReturnValue(calledMethod, annotation));
- }
- }
- }
- break;
-
- //
- // System.Type
- //
- // GetType (string)
- // GetType (string, Boolean)
- // GetType (string, Boolean, Boolean)
- // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>)
- // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
- // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
- //
- case IntrinsicId.Type_GetType:
- {
- reflectionContext.AnalyzingPattern();
-
- var parameters = calledMethod.Signature;
- if ((parameters.Length == 3 && parameters[2].IsWellKnownType(WellKnownType.Boolean) && methodParams[2].AsConstInt() != 0) ||
- (parameters.Length == 5 && methodParams[4].AsConstInt() != 0))
- {
- reflectionContext.RecordUnrecognizedPattern(2096, $"Call to '{calledMethod.GetDisplayName()}' can perform case insensitive lookup of the type, currently ILLink can not guarantee presence of all the matching types");
- break;
- }
- foreach (var typeNameValue in methodParams[0].UniqueValues())
- {
- if (typeNameValue is KnownStringValue knownStringValue)
- {
- bool found = ILCompiler.DependencyAnalysis.ReflectionMethodBodyScanner.ResolveType(knownStringValue.Contents, ((MetadataType)callingMethodDefinition.OwningType).Module,
- callingMethodDefinition.Context,
- out TypeDesc foundType, out ModuleDesc referenceModule);
- if (!found)
- {
- // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- // Also add module metadata in case this reference was through a type forward
- if (_factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
- _dependencies.Add(_factory.ModuleMetadata(referenceModule), reflectionContext.MemberWithRequirements.ToString());
-
- reflectionContext.RecordRecognizedPattern(() => _dependencies.Add(_factory.MaximallyConstructableType(foundType), "Type.GetType reference"));
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new SystemTypeValue(foundType));
- }
- }
- else if (typeNameValue == NullValue.Instance)
- {
- reflectionContext.RecordHandledPattern();
- }
- else if (typeNameValue is LeafValueWithDynamicallyAccessedMemberNode valueWithDynamicallyAccessedMember && valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes != 0)
- {
- // Propagate the annotation from the type name to the return value. Annotation on a string value will be fullfilled 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.
- reflectionContext.RecordHandledPattern();
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new MethodReturnValue(calledMethod, valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes));
- }
- else
- {
- reflectionContext.RecordUnrecognizedPattern(2057, $"Unrecognized value passed to the parameter 'typeName' of method '{calledMethod.GetDisplayName()}'. It's not possible to guarantee the availability of the target type.");
- }
- }
+ return handleCallAction.Invoke(calledMethod, instanceValue, parameterValues, out methodReturnValue, out _);
+ }
- }
- break;
-
- //
- // GetConstructor (Type[])
- // GetConstructor (BindingFlags, Type[])
- // GetConstructor (BindingFlags, Binder, Type[], ParameterModifier [])
- // GetConstructor (BindingFlags, Binder, CallingConventions, Type[], ParameterModifier [])
- //
- case IntrinsicId.Type_GetConstructor:
- {
- reflectionContext.AnalyzingPattern();
+ case IntrinsicId.TypeDelegator_Ctor:
+ {
+ // This is an identity function for analysis purposes
+ if (operation == ILOpcode.newobj)
+ AddReturnValue(methodParams[1]);
+ }
+ break;
- var parameters = calledMethod.Signature;
- BindingFlags? bindingFlags;
- if (parameters.Length > 1 && calledMethod.Signature[0].IsTypeOf("System.Reflection", "BindingFlags"))
- bindingFlags = GetBindingFlagsFromValue(methodParams[1]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Public | BindingFlags.Instance;
+ case IntrinsicId.Array_Empty:
+ {
+ AddReturnValue(ArrayValue.Create(0, calledMethod.Instantiation[0]));
+ }
+ break;
- int? ctorParameterCount = parameters.Length switch
- {
- 1 => (methodParams[1] as ArrayValue)?.Size.AsConstInt(),
- 2 => (methodParams[2] as ArrayValue)?.Size.AsConstInt(),
- 4 => (methodParams[3] as ArrayValue)?.Size.AsConstInt(),
- 5 => (methodParams[4] as ArrayValue)?.Size.AsConstInt(),
- _ => null,
- };
-
- // Go over all types we've seen
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- if (BindingFlagsAreUnsupported(bindingFlags))
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors, value, new MethodOrigin(calledMethod));
- }
- else
- {
- if (HasBindingFlag(bindingFlags, BindingFlags.Public) && !HasBindingFlag(bindingFlags, BindingFlags.NonPublic)
- && ctorParameterCount == 0)
- {
- MarkConstructorsOnType(ref reflectionContext, systemTypeValue.TypeRepresented, m => m.IsPublic() && m.Signature.Length == 0, bindingFlags);
- }
- else
- {
- MarkConstructorsOnType(ref reflectionContext, systemTypeValue.TypeRepresented, null, bindingFlags);
- }
- }
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- // Otherwise fall back to the bitfield requirements
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors(bindingFlags);
- // We can scope down the public constructors requirement if we know the number of parameters is 0
- if (requiredMemberTypes == DynamicallyAccessedMemberTypes.PublicConstructors && ctorParameterCount == 0)
- requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new MethodOrigin(calledMethod));
- }
- }
- }
- break;
-
- //
- // GetMethod (string)
- // GetMethod (string, BindingFlags)
- // GetMethod (string, Type[])
- // GetMethod (string, Type[], ParameterModifier[])
- // GetMethod (string, BindingFlags, Type[])
- // GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
- // GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
- // GetMethod (string, int, Type[])
- // GetMethod (string, int, Type[], ParameterModifier[]?)
- // GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
- // GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
- //
- case IntrinsicId.Type_GetMethod:
+ //
+ // System.Enum
+ //
+ // static GetValues (Type)
+ //
+ case IntrinsicId.Enum_GetValues:
+ {
+ // Enum.GetValues returns System.Array, but it's the array of the enum type under the hood
+ // and people depend on this undocumented detail (could have returned enum of the underlying
+ // type instead).
+ //
+ // At least until we have shared enum code, this needs extra handling to get it right.
+ foreach (var value in methodParams[0])
{
- reflectionContext.AnalyzingPattern();
-
- BindingFlags? bindingFlags;
- if (calledMethod.Signature.Length > 1 && calledMethod.Signature[1].IsTypeOf("System.Reflection", "BindingFlags"))
- bindingFlags = GetBindingFlagsFromValue(methodParams[2]);
- else if (calledMethod.Signature.Length > 2 && calledMethod.Signature[2].IsTypeOf("System.Reflection", "BindingFlags"))
- bindingFlags = GetBindingFlagsFromValue(methodParams[3]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods(bindingFlags);
- foreach (var value in methodParams[0].UniqueValues())
+ if (value is SystemTypeValue systemTypeValue
+ && !systemTypeValue.RepresentedType.Type.IsGenericDefinition
+ && !systemTypeValue.RepresentedType.Type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true))
{
- if (value is SystemTypeValue systemTypeValue)
- {
- foreach (var stringParam in methodParams[1].UniqueValues())
- {
- if (stringParam is KnownStringValue stringValue)
- {
- if (BindingFlagsAreUnsupported(bindingFlags))
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods, value, new MethodOrigin(calledMethod));
- }
- else
- {
- ProcessGetMethodByName(ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, bindingFlags, ref methodReturnValue);
- }
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new MethodOrigin(calledMethod));
- }
- }
- }
- else
+ if (systemTypeValue.RepresentedType.Type.IsEnum)
{
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new MethodOrigin(calledMethod));
+ _reflectionMarker.Dependencies.Add(_factory.ConstructedTypeSymbol(systemTypeValue.RepresentedType.Type.MakeArrayType()), "Enum.GetValues");
}
}
- }
- break;
-
- //
- // GetNestedType (string)
- // GetNestedType (string, BindingFlags)
- //
- case IntrinsicId.Type_GetNestedType:
- {
- reflectionContext.AnalyzingPattern();
-
- BindingFlags? bindingFlags;
- if (calledMethod.Signature.Length > 1 && calledMethod.Signature[1].IsTypeOf("System.Reflection", "BindingFlags"))
- bindingFlags = GetBindingFlagsFromValue(methodParams[2]);
else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes(bindingFlags);
- bool everyParentTypeHasAll = true;
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- foreach (var stringParam in methodParams[1].UniqueValues())
- {
- if (stringParam is KnownStringValue stringValue)
- {
- if (BindingFlagsAreUnsupported(bindingFlags))
- // We have chosen not to populate the methodReturnValue for now
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes, value, new MethodOrigin(calledMethod));
- else
- {
- MetadataType[] matchingNestedTypes = MarkNestedTypesOnType(ref reflectionContext, systemTypeValue.TypeRepresented, m => m.Name == stringValue.Contents, bindingFlags);
-
- if (matchingNestedTypes != null)
- {
- for (int i = 0; i < matchingNestedTypes.Length; i++)
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new SystemTypeValue(matchingNestedTypes[i]));
- }
- }
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new MethodOrigin(calledMethod));
- }
- }
- }
- else
- {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new MethodOrigin(calledMethod));
- }
-
- if (value is LeafValueWithDynamicallyAccessedMemberNode leafValueWithDynamicallyAccessedMember)
- {
- if (leafValueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.All)
- everyParentTypeHasAll = false;
- }
- else if (!(value is NullValue || value is SystemTypeValue))
- {
- // Known Type values are always OK - either they're fully resolved above and thus the return value
- // is set to the known resolved type, or if they're not resolved, they won't exist at runtime
- // and will cause exceptions - and thus don't introduce new requirements on marking.
- // nulls are intentionally ignored as they will lead to exceptions at runtime
- // and thus don't introduce new requirements on marking.
- everyParentTypeHasAll = false;
- }
- }
-
- // If the parent type (all the possible values) has DynamicallyAccessedMemberTypes.All it means its nested types are also fully marked
- // (see MarkStep.MarkEntireType - it will recursively mark entire type on nested types). In that case we can annotate
- // the returned type (the nested type) with DynamicallyAccessedMemberTypes.All as well.
- // Note it's OK to blindly overwrite any potential annotation on the return value from the method definition
- // since DynamicallyAccessedMemberTypes.All is a superset of any other annotation.
- if (everyParentTypeHasAll && methodReturnValue == null)
- methodReturnValue = new MethodReturnValue(calledMethod, DynamicallyAccessedMemberTypes.All);
- }
- break;
-
- //
- // AssemblyQualifiedName
- //
- case IntrinsicId.Type_get_AssemblyQualifiedName:
- {
-
- ValueNode transformedResult = null;
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is LeafValueWithDynamicallyAccessedMemberNode dynamicallyAccessedThing)
- {
- var annotatedString = new AnnotatedStringValue(dynamicallyAccessedThing.SourceContext, dynamicallyAccessedThing.DynamicallyAccessedMemberTypes);
- transformedResult = MergePointValue.MergeValues(transformedResult, annotatedString);
- }
- else
- {
- transformedResult = null;
- break;
- }
- }
-
- if (transformedResult != null)
- {
- methodReturnValue = transformedResult;
- }
+ CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
}
- break;
+ }
+ break;
- //
- // UnderlyingSystemType
- //
- case IntrinsicId.Type_get_UnderlyingSystemType:
- {
- // This is identity for the purposes of the analysis.
- methodReturnValue = methodParams[0];
- }
- break;
+ //
+ // System.Runtime.InteropServices.Marshal
+ //
+ // static SizeOf (Type)
+ // static PtrToStructure (IntPtr, Type)
+ // static DestroyStructure (IntPtr, Type)
+ // static OffsetOf (Type, string)
+ //
+ case IntrinsicId.Marshal_SizeOf:
+ case IntrinsicId.Marshal_PtrToStructure:
+ case IntrinsicId.Marshal_DestroyStructure:
+ case IntrinsicId.Marshal_OffsetOf:
+ {
+ int paramIndex = intrinsicId == IntrinsicId.Marshal_SizeOf
+ || intrinsicId == IntrinsicId.Marshal_OffsetOf
+ ? 0 : 1;
- //
- // Type.BaseType
- //
- case IntrinsicId.Type_get_BaseType:
+ // We need the data to do struct marshalling.
+ foreach (var value in methodParams[paramIndex])
{
- foreach (var value in methodParams[0].UniqueValues())
+ if (value is SystemTypeValue systemTypeValue
+ && !systemTypeValue.RepresentedType.Type.IsGenericDefinition
+ && !systemTypeValue.RepresentedType.Type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true))
{
- if (value is LeafValueWithDynamicallyAccessedMemberNode dynamicallyAccessedMemberNode)
- {
- DynamicallyAccessedMemberTypes propagatedMemberTypes = DynamicallyAccessedMemberTypes.None;
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
- propagatedMemberTypes = DynamicallyAccessedMemberTypes.All;
- else
- {
- // PublicConstructors are not propagated to base type
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicEvents))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicEvents;
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicFields))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicFields;
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicMethods))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicMethods;
-
- // PublicNestedTypes are not propagated to base type
-
- // PublicParameterlessConstructor is not propagated to base type
-
- if (dynamicallyAccessedMemberNode.DynamicallyAccessedMemberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicProperties))
- propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicProperties;
- }
-
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new MethodReturnValue(calledMethod, propagatedMemberTypes));
- }
- else if (value is SystemTypeValue systemTypeValue)
- {
- DefType baseTypeDefinition = systemTypeValue.TypeRepresented.BaseType;
- if (baseTypeDefinition != null)
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new SystemTypeValue(baseTypeDefinition));
- else
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new MethodReturnValue(calledMethod, DynamicallyAccessedMemberTypes.None));
- }
- else if (value == NullValue.Instance)
+ if (systemTypeValue.RepresentedType.Type.IsDefType)
{
- // Ignore nulls - null.BaseType will fail at runtime, but it has no effect on static analysis
- continue;
- }
- else
- {
- // Unknown input - propagate a return value without any annotation - we know it's a Type but we know nothing about it
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new MethodReturnValue(calledMethod, DynamicallyAccessedMemberTypes.None));
+ _reflectionMarker.Dependencies.Add(_factory.StructMarshallingData((DefType)systemTypeValue.RepresentedType.Type), "Marshal API");
}
}
- }
- break;
-
- //
- // GetField (string)
- // GetField (string, BindingFlags)
- // GetEvent (string)
- // GetEvent (string, BindingFlags)
- // GetProperty (string)
- // GetProperty (string, BindingFlags)
- // GetProperty (string, Type)
- // GetProperty (string, Type[])
- // GetProperty (string, Type, Type[])
- // GetProperty (string, Type, Type[], ParameterModifier[])
- // GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
- //
- case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
- && calledMethod.IsDeclaredOnType("System", "Type")
- && !calledMethod.Signature.IsStatic
- && calledMethod.Signature[0].IsString:
- {
-
- reflectionContext.AnalyzingPattern();
- BindingFlags? bindingFlags;
- if (calledMethod.Signature.Length > 1 && calledMethod.Signature[1].IsTypeOf("System.Reflection", "BindingFlags"))
- bindingFlags = GetBindingFlagsFromValue(methodParams[2]);
else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- DynamicallyAccessedMemberTypes memberTypes = fieldPropertyOrEvent switch
- {
- IntrinsicId.Type_GetEvent => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents(bindingFlags),
- IntrinsicId.Type_GetField => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields(bindingFlags),
- IntrinsicId.Type_GetProperty => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties(bindingFlags),
- _ => throw new ArgumentException($"Reflection call '{calledMethod.GetDisplayName()}' inside '{callingMethodDefinition.GetDisplayName()}' is of unexpected member type."),
- };
-
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- foreach (var stringParam in methodParams[1].UniqueValues())
- {
- if (stringParam is KnownStringValue stringValue)
- {
- switch (fieldPropertyOrEvent)
- {
- case IntrinsicId.Type_GetEvent:
- if (BindingFlagsAreUnsupported(bindingFlags))
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents, value, new MethodOrigin(calledMethod));
- else
- MarkEventsOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, filter: e => e.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.Type_GetField:
- if (BindingFlagsAreUnsupported(bindingFlags))
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields, value, new MethodOrigin(calledMethod));
- else
- MarkFieldsOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, filter: f => f.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.Type_GetProperty:
- if (BindingFlagsAreUnsupported(bindingFlags))
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties, value, new MethodOrigin(calledMethod));
- else
- MarkPropertiesOnTypeHierarchy(ref reflectionContext, systemTypeValue.TypeRepresented, filter: p => p.Name == stringValue.Contents, bindingFlags);
- break;
- default:
- Debug.Fail("Unreachable.");
- break;
- }
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, memberTypes, value, new MethodOrigin(calledMethod));
- }
- }
- }
- else
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, memberTypes, value, new MethodOrigin(calledMethod));
- }
- }
- }
- break;
-
- //
- // GetConstructors (BindingFlags)
- // GetMethods (BindingFlags)
- // GetFields (BindingFlags)
- // GetEvents (BindingFlags)
- // GetProperties (BindingFlags)
- // GetNestedTypes (BindingFlags)
- // GetMembers (BindingFlags)
- //
- case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
- callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
- && calledMethod.IsDeclaredOnType("System", "Type")
- && calledMethod.Signature[0].IsTypeOf("System.Reflection", "BindingFlags")
- && !calledMethod.Signature.IsStatic:
- {
- reflectionContext.AnalyzingPattern();
- BindingFlags? bindingFlags;
- bindingFlags = GetBindingFlagsFromValue(methodParams[1]);
- DynamicallyAccessedMemberTypes memberTypes = DynamicallyAccessedMemberTypes.None;
- if (BindingFlagsAreUnsupported(bindingFlags))
- {
- memberTypes = callType switch
- {
- IntrinsicId.Type_GetConstructors => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors,
- IntrinsicId.Type_GetMethods => DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods,
- IntrinsicId.Type_GetEvents => DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents,
- IntrinsicId.Type_GetFields => DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields,
- IntrinsicId.Type_GetProperties => DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties,
- IntrinsicId.Type_GetNestedTypes => DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
- IntrinsicId.Type_GetMembers => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
- DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
- DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
- DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
- DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
- DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
- _ => throw new ArgumentException($"Reflection call '{calledMethod.GetDisplayName()}' inside '{callingMethodDefinition.GetDisplayName()}' is of unexpected member type."),
- };
- }
- else
- {
- memberTypes = callType switch
- {
- IntrinsicId.Type_GetConstructors => GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors(bindingFlags),
- IntrinsicId.Type_GetMethods => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods(bindingFlags),
- IntrinsicId.Type_GetEvents => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents(bindingFlags),
- IntrinsicId.Type_GetFields => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields(bindingFlags),
- IntrinsicId.Type_GetProperties => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties(bindingFlags),
- IntrinsicId.Type_GetNestedTypes => GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes(bindingFlags),
- IntrinsicId.Type_GetMembers => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers(bindingFlags),
- _ => throw new ArgumentException($"Reflection call '{calledMethod.GetDisplayName()}' inside '{callingMethodDefinition.GetDisplayName()}' is of unexpected member type."),
- };
- }
-
- foreach (var value in methodParams[0].UniqueValues())
- {
- RequireDynamicallyAccessedMembers(ref reflectionContext, memberTypes, value, new MethodOrigin(calledMethod));
- }
+ CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
}
- break;
-
-
- //
- // GetMember (String)
- // GetMember (String, BindingFlags)
- // GetMember (String, MemberTypes, BindingFlags)
- //
- case IntrinsicId.Type_GetMember:
- {
- reflectionContext.AnalyzingPattern();
- var signature = calledMethod.Signature;
- BindingFlags? bindingFlags;
- if (signature.Length == 1)
- {
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Public | BindingFlags.Instance;
- }
- else if (signature.Length == 2 && calledMethod.HasParameterOfType(1, "System.Reflection", "BindingFlags"))
- bindingFlags = GetBindingFlagsFromValue(methodParams[2]);
- else if (signature.Length == 3 && calledMethod.HasParameterOfType(2, "System.Reflection", "BindingFlags"))
- {
- bindingFlags = GetBindingFlagsFromValue(methodParams[3]);
- }
- else // Non recognized intrinsic
- throw new ArgumentException($"Reflection call '{calledMethod.GetDisplayName()}' inside '{callingMethodDefinition.GetDisplayName()}' is an unexpected intrinsic.");
-
- DynamicallyAccessedMemberTypes requiredMemberTypes = DynamicallyAccessedMemberTypes.None;
- if (BindingFlagsAreUnsupported(bindingFlags))
- {
- requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
- DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
- DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
- DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
- DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
- DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
- }
- else
- {
- requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers(bindingFlags);
- }
- // Go over all types we've seen
- foreach (var value in methodParams[0].UniqueValues())
- {
- // Mark based on bitfield requirements
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new MethodOrigin(calledMethod));
- }
- }
- break;
+ }
+ break;
- //
- // GetInterface (String)
- // GetInterface (String, bool)
- //
- case IntrinsicId.Type_GetInterface:
- {
- reflectionContext.AnalyzingPattern();
- foreach (var value in methodParams[0].UniqueValues())
- {
- // For now no support for marking a single interface by name. We would have to correctly support
- // mangled names for generics to do that correctly. Simply mark all interfaces on the type for now.
- // Require Interfaces annotation
- RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberTypes.Interfaces, value, new MethodOrigin(calledMethod));
- // Interfaces is transitive, so the return values will always have at least Interfaces annotation
- DynamicallyAccessedMemberTypes returnMemberTypes = DynamicallyAccessedMemberTypes.Interfaces;
- // Propagate All annotation across the call - All is a superset of Interfaces
- if (value is LeafValueWithDynamicallyAccessedMemberNode annotatedNode
- && annotatedNode.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
- returnMemberTypes = DynamicallyAccessedMemberTypes.All;
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new MethodReturnValue(calledMethod, returnMemberTypes));
- }
- }
- break;
-
- //
- // System.Activator
- //
- // static CreateInstance (System.Type type)
- // static CreateInstance (System.Type type, bool nonPublic)
- // static CreateInstance (System.Type type, params object?[]? args)
- // static CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
- // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
- // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
- //
- case IntrinsicId.Activator_CreateInstance_Type:
+ //
+ // System.Runtime.InteropServices.Marshal
+ //
+ // static GetDelegateForFunctionPointer (IntPtr, Type)
+ //
+ case IntrinsicId.Marshal_GetDelegateForFunctionPointer:
+ {
+ // We need the data to do delegate marshalling.
+ foreach (var value in methodParams[1])
{
- var parameters = calledMethod.Signature;
-
- reflectionContext.AnalyzingPattern();
-
- int? ctorParameterCount = null;
- BindingFlags bindingFlags = BindingFlags.Instance;
- if (parameters.Length > 1)
+ if (value is SystemTypeValue systemTypeValue
+ && !systemTypeValue.RepresentedType.Type.IsGenericDefinition
+ && !systemTypeValue.RepresentedType.Type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true))
{
- if (parameters[1].IsWellKnownType(WellKnownType.Boolean))
+ if (systemTypeValue.RepresentedType.Type.IsDefType)
{
- // The overload that takes a "nonPublic" bool
- bool nonPublic = true;
- if (methodParams[1] is ConstIntValue constInt)
- {
- nonPublic = constInt.Value != 0;
- }
-
- if (nonPublic)
- bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
- else
- bindingFlags |= BindingFlags.Public;
- ctorParameterCount = 0;
- }
- else
- {
- // Overload that has the parameters as the second or fourth argument
- int argsParam = parameters.Length == 2 || parameters.Length == 3 ? 1 : 3;
-
- if (methodParams.Count > argsParam)
- {
- if (methodParams[argsParam] is ArrayValue arrayValue &&
- arrayValue.Size.AsConstInt() != null)
- ctorParameterCount = arrayValue.Size.AsConstInt();
- else if (methodParams[argsParam] is NullValue)
- ctorParameterCount = 0;
- }
-
- if (parameters.Length > 3)
- {
- if (methodParams[1].AsConstInt() is int constInt)
- bindingFlags |= (BindingFlags)constInt;
- else
- bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
- }
- else
- {
- bindingFlags |= BindingFlags.Public;
- }
+ _reflectionMarker.Dependencies.Add(_factory.DelegateMarshallingData((DefType)systemTypeValue.RepresentedType.Type), "Marshal API");
}
}
else
- {
- // The overload with a single System.Type argument
- ctorParameterCount = 0;
- bindingFlags |= BindingFlags.Public;
- }
-
- // Go over all types we've seen
- foreach (var value in methodParams[0].UniqueValues())
- {
- if (value is SystemTypeValue systemTypeValue)
- {
- // Special case known type values as we can do better by applying exact binding flags and parameter count.
- MarkConstructorsOnType(ref reflectionContext, systemTypeValue.TypeRepresented,
- ctorParameterCount == null ? null : m => m.Signature.Length == ctorParameterCount, bindingFlags);
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- // Otherwise fall back to the bitfield requirements
- var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors(bindingFlags);
-
- // Special case the public parameterless constructor if we know that there are 0 args passed in
- if (ctorParameterCount == 0 && requiredMemberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicConstructors))
- {
- requiredMemberTypes &= ~DynamicallyAccessedMemberTypes.PublicConstructors;
- requiredMemberTypes |= DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
- }
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, value, new ParameterOrigin(calledMethod, 0));
- }
- }
- }
- break;
-
-#if false
- // TODO: niche APIs that we probably shouldn't even have added
- //
- // System.Activator
- //
- // static CreateInstance (string assemblyName, string typeName)
- // static CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
- // static CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
- //
- case IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName:
- ProcessCreateInstanceByName(ref reflectionContext, calledMethod, methodParams);
- break;
-
- //
- // System.Activator
- //
- // static CreateInstanceFrom (string assemblyFile, string typeName)
- // static CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // static CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- //
- case IntrinsicId.Activator_CreateInstanceFrom:
- ProcessCreateInstanceByName(ref reflectionContext, calledMethod, methodParams);
- break;
-#endif
-
-#if false
- // We probably don't need this because there's other places within the compiler that ensure this works.
- //
- // System.Activator
- //
- // static T CreateInstance<T> ()
- //
- // Note: If the when condition returns false it would be an overload which we don't recognize, so just fall through to the default case
- case IntrinsicId.Activator_CreateInstanceOfT when
- calledMethod.Instantiation.Length == 1:
- {
- reflectionContext.AnalyzingPattern();
-
- if (genericCalledMethod.GenericArguments[0] is GenericParameter genericParameter &&
- genericParameter.HasDefaultConstructorConstraint)
- {
- // This is safe, the linker would have marked the default .ctor already
- reflectionContext.RecordHandledPattern();
- break;
- }
-
- RequireDynamicallyAccessedMembers(
- ref reflectionContext,
- DynamicallyAccessedMemberTypes.PublicParameterlessConstructor,
- GetTypeValueNodeFromGenericArgument(genericCalledMethod.GenericArguments[0]),
- calledMethodDefinition.GenericParameters[0]);
+ CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
}
- break;
-#endif
-
-#if false
- // TODO: niche APIs that we probably shouldn't even have added
- //
- // System.AppDomain
- //
- // CreateInstance (string assemblyName, string typeName)
- // CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
- //
- // CreateInstanceAndUnwrap (string assemblyName, string typeName)
- // CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
- //
- // CreateInstanceFrom (string assemblyFile, string typeName)
- // CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
- //
- // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
- // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
- // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
- //
- case var appDomainCreateInstance when appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstance
- || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceAndUnwrap
- || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFrom
- || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap:
- ProcessCreateInstanceByName(ref reflectionContext, calledMethod, methodParams);
- break;
-#endif
-
- //
- // System.Reflection.Assembly
- //
- // CreateInstance (string typeName)
- // CreateInstance (string typeName, bool ignoreCase)
- // CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
- //
- case IntrinsicId.Assembly_CreateInstance:
- // For now always fail since we don't track assemblies (dotnet/linker/issues/1947)
- reflectionContext.AnalyzingPattern();
- reflectionContext.RecordUnrecognizedPattern(2058, $"Parameters passed to method '{calledMethod.GetDisplayName()}' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead.");
- break;
-
- //
- // System.Runtime.CompilerServices.RuntimeHelpers
- //
- // RunClassConstructor (RuntimeTypeHandle type)
- //
- case IntrinsicId.RuntimeHelpers_RunClassConstructor:
- {
- reflectionContext.AnalyzingPattern();
- foreach (var typeHandleValue in methodParams[0].UniqueValues())
- {
- if (typeHandleValue is RuntimeTypeHandleValue runtimeTypeHandleValue)
- {
- TypeDesc typeRepresented = runtimeTypeHandleValue.TypeRepresented;
- if (!typeRepresented.IsGenericDefinition && !typeRepresented.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && typeRepresented.HasStaticConstructor)
- {
- _dependencies.Add(_factory.CanonicalEntrypoint(typeRepresented.GetStaticConstructor()), "RunClassConstructor reference");
- }
+ }
+ break;
- reflectionContext.RecordHandledPattern();
- }
- else if (typeHandleValue == NullValue.Instance)
- reflectionContext.RecordHandledPattern();
- else
- {
- reflectionContext.RecordUnrecognizedPattern(2059, $"Unrecognized value passed to the parameter 'type' of method '{calledMethod.GetDisplayName()}'. It's not possible to guarantee the availability of the target static constructor.");
- }
+ //
+ // System.Object
+ //
+ // GetType()
+ //
+ case IntrinsicId.Object_GetType:
+ {
+ foreach (var valueNode in methodParams[0])
+ {
+ // Note that valueNode can be statically typed in IL as some generic argument type.
+ // For example:
+ // void Method<T>(T instance) { instance.GetType().... }
+ // Currently this case will end up with null StaticType - since there's no typedef for the generic argument type.
+ // But it could be that T is annotated with for example PublicMethods:
+ // void Method<[DAM(PublicMethods)] T>(T instance) { instance.GetType().GetMethod("Test"); }
+ // In this case it's in theory possible to handle it, by treating the T basically as a base class
+ // for the actual type of "instance". But the analysis for this would be pretty complicated (as the marking
+ // has to happen on the callsite, which doesn't know that GetType() will be used...).
+ // For now we're intentionally ignoring this case - it will produce a warning.
+ // The counter example is:
+ // Method<Base>(new Derived);
+ // In this case to get correct results, trimmer would have to mark all public methods on Derived. Which
+ // currently it won't do.
+
+ TypeDesc? staticType = (valueNode as IValueWithStaticType)?.StaticType;
+ 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(_annotations.GetMethodReturnValue(calledMethod));
+ }
+ else if (staticType.IsSealed() || staticType.IsTypeOf("System", "Delegate"))
+ {
+ // We can treat this one the same as if it was a typeof() expression
+
+ // We can allow Object.GetType to be modeled as System.Delegate because we keep all methods
+ // on delegates anyway so reflection on something this approximation would miss is actually safe.
+
+ // We ignore the fact that the type can be annotated (see below for handling of annotated types)
+ // This means the annotations (if any) won't be applied - instead we rely on the exact knowledge
+ // of the type. So for example even if the type is annotated with PublicMethods
+ // but the code calls GetProperties on it - it will work - mark properties, don't mark methods
+ // since we ignored the fact that it's annotated.
+ // This can be seen a little bit as a violation of the annotation, but we already have similar cases
+ // where a parameter is annotated and if something in the method sets a specific known type to it
+ // we will also make it just work, even if the annotation doesn't match the usage.
+ AddReturnValue(new SystemTypeValue(staticType));
}
- }
- break;
-
- //
- // System.Reflection.MethodInfo
- //
- // MakeGenericMethod (Type[] typeArguments)
- //
- case IntrinsicId.MethodInfo_MakeGenericMethod:
- {
- reflectionContext.AnalyzingPattern();
-
- foreach (var methodValue in methodParams[0].UniqueValues())
+ else
{
- if (methodValue is SystemReflectionMethodBaseValue methodBaseValue)
- {
- ValidateGenericMethodInstantiation(ref reflectionContext, methodBaseValue.MethodRepresented, methodParams[1], calledMethod);
- }
- else if (methodValue == NullValue.Instance)
- {
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
- // that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.MakeGenericMethod,
- new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage(
- DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod)));
- }
- }
- // MakeGenericMethod doesn't change the identity of the MethodBase we're tracking so propagate to the return value
- methodReturnValue = methodParams[0];
-
- CheckAndReportRequires(calledMethod, new MessageOrigin(callingMethodBody, offset), RequiresDynamicCodeAttribute);
- }
- break;
-
- default:
- if (calledMethod.IsPInvoke)
- {
- // Is the PInvoke dangerous?
- ParameterMetadata[] paramMetadata = calledMethod.GetParameterMetadata();
+ Debug.Assert(staticType is MetadataType || staticType.IsArray);
+ MetadataType closestMetadataType = staticType is MetadataType mdType ?
+ mdType : (MetadataType)_factory.TypeSystemContext.GetWellKnownType(Internal.TypeSystem.WellKnownType.Array);
- ParameterMetadata returnParamMetadata = Array.Find(paramMetadata, m => m.Index == 0);
+ var annotation = _annotations.GetTypeAnnotation(staticType);
- bool comDangerousMethod = IsComInterop(returnParamMetadata.MarshalAsDescriptor, calledMethod.Signature.ReturnType);
- for (int paramIndex = 0; paramIndex < calledMethod.Signature.Length; paramIndex++)
- {
- MarshalAsDescriptor marshalAsDescriptor = null;
- for (int metadataIndex = 0; metadataIndex < paramMetadata.Length; metadataIndex++)
+ if (annotation != default)
{
- if (paramMetadata[metadataIndex].Index == paramIndex + 1)
- marshalAsDescriptor = paramMetadata[metadataIndex].MarshalAsDescriptor;
+ _reflectionMarker.Dependencies.Add(_factory.ObjectGetTypeFlowDependencies(closestMetadataType), "GetType called on this type");
}
- comDangerousMethod |= IsComInterop(marshalAsDescriptor, calledMethod.Signature[paramIndex]);
- }
-
- if (comDangerousMethod)
- {
- reflectionContext.AnalyzingPattern();
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.CorrectnessOfCOMCannotBeGuaranteed,
- new DiagnosticString(DiagnosticId.CorrectnessOfCOMCannotBeGuaranteed).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod)));
- }
- }
-
- if (requiresDataFlowAnalysis)
- {
- reflectionContext.AnalyzingPattern();
- for (int parameterIndex = 0; parameterIndex < methodParams.Count; parameterIndex++)
- {
- var requiredMemberTypes = _flowAnnotations.GetParameterAnnotation(calledMethod, parameterIndex);
- if (requiredMemberTypes != 0)
- {
- Origin targetContext = DiagnosticUtilities.GetMethodParameterFromIndex(calledMethod, parameterIndex);
- RequireDynamicallyAccessedMembers(ref reflectionContext, requiredMemberTypes, methodParams[parameterIndex], targetContext);
- }
+ // 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(_annotations.GetMethodReturnValue(calledMethod, annotation));
}
-
- reflectionContext.RecordHandledPattern();
- }
-
- var origin = new MessageOrigin(callingMethodBody, offset);
- CheckAndReportRequires(calledMethod, origin, RequiresUnreferencedCodeAttribute);
- CheckAndReportRequires(calledMethod, origin, RequiresDynamicCodeAttribute);
- CheckAndReportRequires(calledMethod, origin, RequiresAssemblyFilesAttribute);
-
- // To get good reporting of errors we need to track the origin of the value for all method calls
- // but except Newobj as those are special.
- if (!calledMethod.Signature.ReturnType.IsVoid)
- {
- methodReturnValue = new MethodReturnValue(calledMethod, returnValueDynamicallyAccessedMemberTypes);
-
- return true;
}
+ }
+ break;
- return false;
- }
- }
- finally
- {
- reflectionContext.Dispose();
+ default:
+ throw new NotImplementedException("Unhandled instrinsic");
}
// If we get here, we handled this as an intrinsic. 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.
- if (methodReturnValue == null)
- {
- if (!calledMethod.Signature.ReturnType.IsVoid)
- {
- methodReturnValue = new MethodReturnValue(calledMethod, returnValueDynamicallyAccessedMemberTypes);
- }
- }
+ bool returnsVoid = calledMethod.Signature.ReturnType.IsVoid;
+ methodReturnValue = maybeMethodReturnValue ?? (returnsVoid ?
+ MultiValueLattice.Top :
+ _annotations.GetMethodReturnValue(calledMethod, returnValueDynamicallyAccessedMemberTypes)!);
// Validate that the return value has the correct annotations as per the method return value annotations
if (returnValueDynamicallyAccessedMemberTypes != 0)
{
- foreach (var uniqueValue in methodReturnValue.UniqueValues())
+ foreach (var uniqueValue in methodReturnValue)
{
- if (uniqueValue is LeafValueWithDynamicallyAccessedMemberNode methodReturnValueWithMemberTypes)
+ if (uniqueValue is ValueWithDynamicallyAccessedMembers methodReturnValueWithMemberTypes)
{
if (!methodReturnValueWithMemberTypes.DynamicallyAccessedMemberTypes.HasFlag(returnValueDynamicallyAccessedMemberTypes))
throw new InvalidOperationException($"Internal linker error: processing of call from {callingMethodDefinition.GetDisplayName()} to {calledMethod.GetDisplayName()} returned value which is not correctly annotated with the expected dynamic member access kinds.");
@@ -2313,9 +734,14 @@ namespace ILCompiler.Dataflow
}
return true;
+
+ void AddReturnValue(MultiValue value)
+ {
+ maybeMethodReturnValue = (maybeMethodReturnValue is null) ? value : MultiValueLattice.Meet((MultiValue)maybeMethodReturnValue, value);
+ }
}
- bool IsComInterop(MarshalAsDescriptor marshalInfoProvider, TypeDesc parameterType)
+ bool IsComInterop(MarshalAsDescriptor? marshalInfoProvider, TypeDesc parameterType)
{
// This is best effort. One can likely find ways how to get COM without triggering these alarms.
// AsAny marshalling of a struct with an object-typed field would be one, for example.
@@ -2346,12 +772,12 @@ namespace ILCompiler.Dataflow
while (parameterType.IsParameterizedType)
parameterType = ((ParameterizedType)parameterType).ParameterType;
- if (parameterType.IsWellKnownType(WellKnownType.Array))
+ if (parameterType.IsWellKnownType(Internal.TypeSystem.WellKnownType.Array))
{
// System.Array marshals as IUnknown by default
return true;
}
- else if (parameterType.IsWellKnownType(WellKnownType.String) ||
+ else if (parameterType.IsWellKnownType(Internal.TypeSystem.WellKnownType.String) ||
InteropTypes.IsStringBuilder(context, parameterType))
{
// String and StringBuilder are special cased by interop
@@ -2368,8 +794,8 @@ namespace ILCompiler.Dataflow
// Interface types marshal as COM by default
return true;
}
- else if (parameterType.IsDelegate || parameterType.IsWellKnownType(WellKnownType.MulticastDelegate)
- || parameterType == context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType)
+ else if (parameterType.IsDelegate || parameterType.IsWellKnownType(Internal.TypeSystem.WellKnownType.MulticastDelegate)
+ || parameterType == context.GetWellKnownType(Internal.TypeSystem.WellKnownType.MulticastDelegate).BaseType)
{
// Delegates are special cased by interop
return false;
@@ -2394,724 +820,10 @@ namespace ILCompiler.Dataflow
return false;
}
- private bool AnalyzeGenericInstantiationTypeArray(ValueNode arrayParam, ref ReflectionPatternContext reflectionContext, MethodDesc calledMethod, Instantiation genericParameters)
+ void RequireDynamicallyAccessedMembers(in DiagnosticContext diagnosticContext, in MultiValue value, ValueWithDynamicallyAccessedMembers targetValue, Origin memberWithRequirements)
{
- bool hasRequirements = false;
- foreach (GenericParameterDesc genericParameter in genericParameters)
- {
- if (_flowAnnotations.GetGenericParameterAnnotation(genericParameter) != DynamicallyAccessedMemberTypes.None)
- {
- hasRequirements = true;
- break;
- }
- }
-
- // If there are no requirements, then there's no point in warning
- if (!hasRequirements)
- return true;
-
- foreach (var typesValue in arrayParam.UniqueValues())
- {
- if (typesValue.Kind != ValueNodeKind.Array)
- {
- return false;
- }
- ArrayValue array = (ArrayValue)typesValue;
- int? size = array.Size.AsConstInt();
- if (size == null || size != genericParameters.Length)
- {
- return false;
- }
- bool allIndicesKnown = true;
- for (int i = 0; i < size.Value; i++)
- {
- if (!array.IndexValues.TryGetValue(i, out ValueBasicBlockPair value) || value.Value is null or { Kind: ValueNodeKind.Unknown })
- {
- allIndicesKnown = false;
- break;
- }
- }
-
- if (!allIndicesKnown)
- {
- return false;
- }
-
- for (int i = 0; i < size.Value; i++)
- {
- if (array.IndexValues.TryGetValue(i, out ValueBasicBlockPair value))
- {
- RequireDynamicallyAccessedMembers(
- ref reflectionContext,
- _flowAnnotations.GetGenericParameterAnnotation((GenericParameterDesc)genericParameters[i]),
- value.Value,
- new MethodOrigin(calledMethod));
- }
- }
- }
- return true;
+ var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(_reflectionMarker, diagnosticContext, memberWithRequirements);
+ requireDynamicallyAccessedMembersAction.Invoke(value, targetValue);
}
-
-#if false
- void ProcessCreateInstanceByName(ref ReflectionPatternContext reflectionContext, MethodDesc calledMethod, ValueNodeList methodParams)
- {
- reflectionContext.AnalyzingPattern();
-
- BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
- bool parameterlessConstructor = true;
- if (calledMethod.Parameters.Count == 8 && calledMethod.Parameters[2].ParameterType.MetadataType == MetadataType.Boolean)
- {
- parameterlessConstructor = false;
- bindingFlags = BindingFlags.Instance;
- if (methodParams[3].AsConstInt() is int bindingFlagsInt)
- bindingFlags |= (BindingFlags)bindingFlagsInt;
- else
- bindingFlags |= BindingFlags.Public | BindingFlags.NonPublic;
- }
-
- int methodParamsOffset = !calledMethod.Signature.IsStatic ? 1 : 0;
-
- foreach (var assemblyNameValue in methodParams[methodParamsOffset].UniqueValues())
- {
- if (assemblyNameValue is KnownStringValue assemblyNameStringValue)
- {
- foreach (var typeNameValue in methodParams[methodParamsOffset + 1].UniqueValues())
- {
- if (typeNameValue is KnownStringValue typeNameStringValue)
- {
- var resolvedAssembly = _context.GetLoadedAssembly(assemblyNameStringValue.Contents);
- if (resolvedAssembly == null)
- {
- reflectionContext.RecordUnrecognizedPattern(2061, $"The assembly name '{assemblyNameStringValue.Contents}' passed to method '{calledMethod.GetDisplayName()}' references assembly which is not available.");
- continue;
- }
-
- var resolvedType = _context.TypeNameResolver.ResolveTypeName(resolvedAssembly, typeNameStringValue.Contents)?.Resolve();
- if (resolvedType == null)
- {
- // It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case
- // Note that we did find the assembly, so it's not a linker config problem, it's either intentional, or wrong versions of assemblies
- // but linker can't know that.
- reflectionContext.RecordHandledPattern();
- continue;
- }
-
- MarkConstructorsOnType(ref reflectionContext, resolvedType, parameterlessConstructor ? m => m.Parameters.Count == 0 : null, bindingFlags);
- }
- else
- {
- reflectionContext.RecordUnrecognizedPattern(2032, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[1].Name}' of method '{calledMethod.GetDisplayName()}'. It's not possible to guarantee the availability of the target type.");
- }
- }
- }
- else
- {
- reflectionContext.RecordUnrecognizedPattern(2032, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[0].Name}' of method '{calledMethod.GetDisplayName()}'. It's not possible to guarantee the availability of the target type.");
- }
- }
- }
-#endif
-
- void ProcessGetMethodByName(
- ref ReflectionPatternContext reflectionContext,
- TypeDesc typeDefinition,
- string methodName,
- BindingFlags? bindingFlags,
- ref ValueNode methodReturnValue)
- {
- bool foundAny = false;
- foreach (var method in typeDefinition.GetMethodsOnTypeHierarchy(m => m.Name == methodName, bindingFlags))
- {
- MarkMethod(ref reflectionContext, method);
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, new SystemReflectionMethodBaseValue(method));
- foundAny = true;
- }
- // If there were no methods found the API will return null at runtime, so we should
- // track the null as a return value as well.
- // This also prevents warnings in such case, since if we don't set the return value it will be
- // "unknown" and consumers may warn.
- if (!foundAny)
- methodReturnValue = MergePointValue.MergeValues(methodReturnValue, NullValue.Instance);
- }
-
- public static DynamicallyAccessedMemberTypes GetMissingMemberTypes(DynamicallyAccessedMemberTypes requiredMemberTypes, DynamicallyAccessedMemberTypes availableMemberTypes)
- {
- if (availableMemberTypes.HasFlag(requiredMemberTypes))
- return DynamicallyAccessedMemberTypes.None;
-
- if (requiredMemberTypes == DynamicallyAccessedMemberTypes.All)
- return DynamicallyAccessedMemberTypes.All;
-
- var missingMemberTypes = requiredMemberTypes & ~availableMemberTypes;
-
- // PublicConstructors is a special case since its value is 3 - so PublicParameterlessConstructor (1) | _PublicConstructor_WithMoreThanOneParameter_ (2)
- // The above bit logic only works for value with single bit set.
- if (requiredMemberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicConstructors) &&
- !availableMemberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicConstructors))
- missingMemberTypes |= DynamicallyAccessedMemberTypes.PublicConstructors;
-
- return missingMemberTypes;
- }
-
- private string GetMemberTypesString(DynamicallyAccessedMemberTypes memberTypes)
- {
- Debug.Assert(memberTypes != DynamicallyAccessedMemberTypes.None);
-
- if (memberTypes == DynamicallyAccessedMemberTypes.All)
- return $"'{nameof(DynamicallyAccessedMemberTypes)}.{nameof(DynamicallyAccessedMemberTypes.All)}'";
-
- var memberTypesList = Enum.GetValues<DynamicallyAccessedMemberTypes>()
- .Where(damt => (memberTypes & damt) == damt && damt != DynamicallyAccessedMemberTypes.None)
- .ToList();
-
- if (memberTypes.HasFlag(DynamicallyAccessedMemberTypes.PublicConstructors))
- memberTypesList.Remove(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
-
- return string.Join(", ", memberTypesList.Select(mt => $"'{nameof(DynamicallyAccessedMemberTypes)}.{mt}'"));
- }
-
- void RequireDynamicallyAccessedMembers(ref ReflectionPatternContext reflectionContext, DynamicallyAccessedMemberTypes requiredMemberTypes, ValueNode value, Origin targetContext)
- {
- foreach (var uniqueValue in value.UniqueValues())
- {
- if (requiredMemberTypes == DynamicallyAccessedMemberTypes.PublicParameterlessConstructor
- && uniqueValue is SystemTypeForGenericParameterValue genericParam
- && genericParam.GenericParameter.HasDefaultConstructorConstraint)
- {
- // We allow a new() constraint on a generic parameter to satisfy DynamicallyAccessedMemberTypes.PublicParameterlessConstructor
- reflectionContext.RecordHandledPattern();
- }
- else if (uniqueValue is LeafValueWithDynamicallyAccessedMemberNode valueWithDynamicallyAccessedMember)
- {
- var availableMemberTypes = valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes;
- var missingMemberTypesValue = GetMissingMemberTypes(requiredMemberTypes, availableMemberTypes);
- if (missingMemberTypesValue != DynamicallyAccessedMemberTypes.None)
- {
- var missingMemberTypes = GetMemberTypesString(missingMemberTypesValue);
- switch ((valueWithDynamicallyAccessedMember.SourceContext, targetContext))
- {
- case (ParameterOrigin sourceParameter, ParameterOrigin targetParameter):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter).GetMessage(
- DiagnosticUtilities.GetParameterNameForErrorMessage(targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetParameter.Method),
- DiagnosticUtilities.GetParameterNameForErrorMessage(sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterOrigin sourceParameter, MethodReturnOrigin targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType).GetMessage(
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetMethodReturnType.Method),
- DiagnosticUtilities.GetParameterNameForErrorMessage(sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterOrigin sourceParameter, FieldOrigin targetField):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField).GetMessage(
- targetField.GetDisplayName(),
- DiagnosticUtilities.GetParameterNameForErrorMessage(sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterOrigin sourceParameter, MethodOrigin targetMethod):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter).GetMessage(
- targetMethod.GetDisplayName(),
- DiagnosticUtilities.GetParameterNameForErrorMessage(sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceParameter.Method),
- missingMemberTypes));
- break;
- case (ParameterOrigin sourceParameter, GenericParameterOrigin targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsGenericParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsGenericParameter).GetMessage(
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(targetGenericParameter),
- DiagnosticUtilities.GetParameterNameForErrorMessage(sourceParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceParameter.Method),
- missingMemberTypes));
- break;
-
- case (MethodReturnOrigin sourceMethodReturnType, ParameterOrigin targetParameter):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter).GetMessage(
- DiagnosticUtilities.GetParameterNameForErrorMessage(targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetParameter.Method),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnOrigin sourceMethodReturnType, MethodReturnOrigin targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType).GetMessage(
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetMethodReturnType.Method),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnOrigin sourceMethodReturnType, FieldOrigin targetField):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField).GetMessage(
- targetField.GetDisplayName(),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnOrigin sourceMethodReturnType, MethodOrigin targetMethod):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter).GetMessage(
- targetMethod.GetDisplayName(),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
- case (MethodReturnOrigin sourceMethodReturnType, GenericParameterOrigin targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsGenericParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsGenericParameter).GetMessage(
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(targetGenericParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(sourceMethodReturnType.Method),
- missingMemberTypes));
- break;
-
- case (FieldOrigin sourceField, ParameterOrigin targetParameter):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsParameter).GetMessage(
- DiagnosticUtilities.GetParameterNameForErrorMessage(targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetParameter.Method),
- sourceField.GetDisplayName(),
- missingMemberTypes));
- break;
- case (FieldOrigin sourceField, MethodReturnOrigin targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType).GetMessage(
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetMethodReturnType.Method),
- sourceField.GetDisplayName(),
- missingMemberTypes));
- break;
- case (FieldOrigin sourceField, FieldOrigin targetField):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsField,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsField).GetMessage(
- targetField.GetDisplayName(),
- sourceField.GetDisplayName(),
- missingMemberTypes));
- break;
- case (FieldOrigin sourceField, MethodOrigin targetMethod):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter).GetMessage(
- targetMethod.GetDisplayName(),
- sourceField.GetDisplayName(),
- missingMemberTypes));
- break;
- case (FieldOrigin sourceField, GenericParameterOrigin targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsGenericParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsGenericParameter).GetMessage(
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(targetGenericParameter),
- sourceField.GetDisplayName(),
- missingMemberTypes));
- break;
-
- case (MethodOrigin sourceMethod, ParameterOrigin targetParameter):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsParameter).GetMessage(
- DiagnosticUtilities.GetParameterNameForErrorMessage(targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetParameter.Method),
- sourceMethod.GetDisplayName(),
- missingMemberTypes));
- break;
- case (MethodOrigin sourceMethod, MethodReturnOrigin targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType).GetMessage(
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetMethodReturnType.Method),
- sourceMethod.GetDisplayName(),
- missingMemberTypes));
- break;
- case (MethodOrigin sourceMethod, FieldOrigin targetField):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsField,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsField).GetMessage(
- targetField.GetDisplayName(),
- sourceMethod.GetDisplayName(),
- missingMemberTypes));
- break;
- case (MethodOrigin sourceMethod, MethodOrigin targetMethod):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter).GetMessage(
- targetMethod.GetDisplayName(),
- sourceMethod.GetDisplayName(),
- missingMemberTypes));
- break;
- case (MethodOrigin sourceMethod, GenericParameterOrigin targetGenericParameter):
- // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsGenericParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsGenericParameter).GetMessage(
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(targetGenericParameter),
- sourceMethod.GetDisplayName(),
- missingMemberTypes));
- break;
-
- case (GenericParameterOrigin sourceGenericParameter, ParameterOrigin targetParameter):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter).GetMessage(
- DiagnosticUtilities.GetParameterNameForErrorMessage(targetParameter),
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetParameter.Method),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameterOrigin sourceGenericParameter, MethodReturnOrigin targetMethodReturnType):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType).GetMessage(
- DiagnosticUtilities.GetMethodSignatureDisplayName(targetMethodReturnType.Method),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameterOrigin sourceGenericParameter, FieldOrigin targetField):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField).GetMessage(
- targetField.GetDisplayName(),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameterOrigin sourceGenericParameter, MethodOrigin targetMethod):
- // Currently this is never generated, it might be possible one day if we try to validate annotations on results of reflection
- // For example code like this should ideally one day generate the warning
- // void TestMethod<T>()
- // {
- // // This passes the T as the "this" parameter to Type.GetMethods()
- // typeof(Type).GetMethod("GetMethods").Invoke(typeof(T), new object[] {});
- // }
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter).GetMessage(
- targetMethod.GetDisplayName(),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(sourceGenericParameter),
- missingMemberTypes));
- break;
- case (GenericParameterOrigin sourceGenericParameter, GenericParameterOrigin targetGenericParameter):
- reflectionContext.RecordUnrecognizedPattern((int)DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter,
- new DiagnosticString(DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter).GetMessage(
- targetGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(targetGenericParameter),
- sourceGenericParameter.Name,
- DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(sourceGenericParameter),
- missingMemberTypes));
- break;
-
- default:
- throw new NotImplementedException($"unsupported source context {valueWithDynamicallyAccessedMember.SourceContext} or target context {targetContext}");
- };
- }
- else
- {
- reflectionContext.RecordHandledPattern();
- }
- }
- else if (uniqueValue is SystemTypeValue systemTypeValue)
- {
- MarkTypeForDynamicallyAccessedMembers(ref reflectionContext, systemTypeValue.TypeRepresented, requiredMemberTypes);
- }
- else if (uniqueValue is KnownStringValue knownStringValue)
- {
- ModuleDesc callingModule = ((reflectionContext.Source as MethodDesc)?.OwningType as MetadataType)?.Module;
-
- if (!ILCompiler.DependencyAnalysis.ReflectionMethodBodyScanner.ResolveType(knownStringValue.Contents, callingModule, reflectionContext.Source.Context, out TypeDesc foundType, out ModuleDesc referenceModule))
- {
- // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
- reflectionContext.RecordHandledPattern();
- }
- else
- {
- // Also add module metadata in case this reference was through a type forward
- if (_factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
- _dependencies.Add(_factory.ModuleMetadata(referenceModule), reflectionContext.MemberWithRequirements.ToString());
-
- MarkType(ref reflectionContext, foundType);
- MarkTypeForDynamicallyAccessedMembers(ref reflectionContext, foundType, requiredMemberTypes);
- }
- }
- else if (uniqueValue == NullValue.Instance)
- {
- // Ignore - probably unreachable path as it would fail at runtime anyway.
- }
- else
- {
- switch (targetContext)
- {
- case ParameterOrigin parameterDefinition:
- reflectionContext.RecordUnrecognizedPattern(
- 2062,
- $"Value passed to parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage(parameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName(parameterDefinition.Method)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case MethodReturnOrigin methodReturnType:
- reflectionContext.RecordUnrecognizedPattern(
- 2063,
- $"Value returned from method '{DiagnosticUtilities.GetMethodSignatureDisplayName(methodReturnType.Method)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case FieldOrigin fieldDefinition:
- reflectionContext.RecordUnrecognizedPattern(
- 2064,
- $"Value assigned to {fieldDefinition.GetDisplayName()} can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case MethodOrigin methodDefinition:
- reflectionContext.RecordUnrecognizedPattern(
- 2065,
- $"Value passed to implicit 'this' parameter of method '{methodDefinition.GetDisplayName()}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- case GenericParameterOrigin genericParameter:
- // Unknown value to generic parameter - this is possible if the generic argumnet fails to resolve
- reflectionContext.RecordUnrecognizedPattern(
- 2066,
- $"Type passed to generic parameter '{genericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(genericParameter)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.");
- break;
- default: throw new NotImplementedException($"unsupported target context {targetContext.GetType()}");
- };
- }
- }
-
- reflectionContext.RecordHandledPattern();
- }
-
- static BindingFlags? GetBindingFlagsFromValue(ValueNode parameter) => (BindingFlags?)parameter.AsConstInt();
-
- static bool BindingFlagsAreUnsupported(BindingFlags? bindingFlags)
- {
- if (bindingFlags == null)
- return true;
-
- // Binding flags we understand
- const BindingFlags UnderstoodBindingFlags =
- BindingFlags.DeclaredOnly |
- BindingFlags.Instance |
- BindingFlags.Static |
- BindingFlags.Public |
- BindingFlags.NonPublic |
- BindingFlags.FlattenHierarchy |
- BindingFlags.ExactBinding;
-
- // Binding flags that don't affect binding outside InvokeMember (that we don't analyze).
- const BindingFlags IgnorableBindingFlags =
- BindingFlags.InvokeMethod |
- BindingFlags.CreateInstance |
- BindingFlags.GetField |
- BindingFlags.SetField |
- BindingFlags.GetProperty |
- BindingFlags.SetProperty;
-
- BindingFlags flags = bindingFlags.Value;
- return (flags & ~(UnderstoodBindingFlags | IgnorableBindingFlags)) != 0;
- }
-
- static bool HasBindingFlag(BindingFlags? bindingFlags, BindingFlags? search) => bindingFlags != null && (bindingFlags & search) == search;
-
- void MarkTypeForDynamicallyAccessedMembers(ref ReflectionPatternContext reflectionContext, TypeDesc typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, bool declaredOnly = false)
- {
- foreach (var member in typeDefinition.GetDynamicallyAccessedMembers(requiredMemberTypes, declaredOnly))
- {
- switch (member)
- {
- case MethodDesc method:
- MarkMethod(ref reflectionContext, method);
- break;
- case FieldDesc field:
- MarkField(ref reflectionContext, field);
- break;
- case MetadataType type:
- MarkType(ref reflectionContext, type);
- break;
- case PropertyPseudoDesc property:
- MarkProperty(ref reflectionContext, property);
- break;
- case EventPseudoDesc @event:
- MarkEvent(ref reflectionContext, @event);
- break;
- default:
- Debug.Fail(member.GetType().ToString());
- break;
- }
- }
- }
-
- void MarkType(ref ReflectionPatternContext reflectionContext, TypeDesc type)
- {
- RootingHelpers.TryGetDependenciesForReflectedType(ref _dependencies, _factory, type, reflectionContext.MemberWithRequirements.ToString());
- reflectionContext.RecordHandledPattern();
- }
-
- void WarnOnReflectionAccess(ref ReflectionPatternContext context, TypeSystemEntity entity)
- {
- if (_purpose == ScanningPurpose.GetTypeDataflow)
- {
- // Don't check whether the current scope is a RUC type or RUC method because these warnings
- // are not suppressed in RUC scopes. Here the scope represents the DynamicallyAccessedMembers
- // annotation on a type, not a callsite which uses the annotation. We always want to warn about
- // possible reflection access indicated by these annotations.
- _logger.LogWarning(context.Source, DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers,
- ((TypeOrigin)context.MemberWithRequirements).GetDisplayName(), entity.GetDisplayName());
- }
- else
- {
- if (entity is FieldDesc && context.ReportingEnabled)
- {
- _logger.LogWarning(context.Source, DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection, entity.GetDisplayName());
- }
- else
- {
- Debug.Assert(entity is MethodDesc);
-
- _logger.LogWarning(context.Source, DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection, entity.GetDisplayName());
- }
- }
- }
-
- void MarkMethod(ref ReflectionPatternContext reflectionContext, MethodDesc method)
- {
- if(method.DoesMethodRequire(RequiresUnreferencedCodeAttribute, out _))
- {
- if (_purpose == ScanningPurpose.GetTypeDataflow)
- {
- _logger.LogWarning(reflectionContext.Source, DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode,
- ((TypeOrigin)reflectionContext.MemberWithRequirements).GetDisplayName(), method.GetDisplayName());
- }
- }
-
- if (_flowAnnotations.ShouldWarnWhenAccessedForReflection(method) && !ShouldSuppressAnalysisWarningsForRequires(method, RequiresUnreferencedCodeAttribute))
- {
- WarnOnReflectionAccess(ref reflectionContext, method);
- }
-
- RootingHelpers.TryGetDependenciesForReflectedMethod(ref _dependencies, _factory, method, reflectionContext.MemberWithRequirements.ToString());
- reflectionContext.RecordHandledPattern();
- }
-
- void MarkField(ref ReflectionPatternContext reflectionContext, FieldDesc field)
- {
- if (_flowAnnotations.ShouldWarnWhenAccessedForReflection(field) && !ShouldSuppressAnalysisWarningsForRequires(reflectionContext.Source, RequiresUnreferencedCodeAttribute))
- {
- WarnOnReflectionAccess(ref reflectionContext, field);
- }
-
- RootingHelpers.TryGetDependenciesForReflectedField(ref _dependencies, _factory, field, reflectionContext.MemberWithRequirements.ToString());
- reflectionContext.RecordHandledPattern();
- }
-
- void MarkProperty(ref ReflectionPatternContext reflectionContext, PropertyPseudoDesc property)
- {
- if (property.GetMethod != null)
- MarkMethod(ref reflectionContext, property.GetMethod);
- if (property.SetMethod != null)
- MarkMethod(ref reflectionContext, property.SetMethod);
- reflectionContext.RecordHandledPattern();
- }
-
- void MarkEvent(ref ReflectionPatternContext reflectionContext, EventPseudoDesc @event)
- {
- if (@event.AddMethod != null)
- MarkMethod(ref reflectionContext, @event.AddMethod);
- if (@event.RemoveMethod != null)
- MarkMethod(ref reflectionContext, @event.RemoveMethod);
- reflectionContext.RecordHandledPattern();
- }
-
- void MarkConstructorsOnType(ref ReflectionPatternContext reflectionContext, TypeDesc type, Func<MethodDesc, bool> filter, BindingFlags? bindingFlags = null)
- {
- foreach (var ctor in type.GetConstructorsOnType(filter, bindingFlags))
- MarkMethod(ref reflectionContext, ctor);
- }
-
- void MarkFieldsOnTypeHierarchy(ref ReflectionPatternContext reflectionContext, TypeDesc type, Func<FieldDesc, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- foreach (var field in type.GetFieldsOnTypeHierarchy(filter, bindingFlags))
- MarkField(ref reflectionContext, field);
- }
-
- MetadataType[] MarkNestedTypesOnType(ref ReflectionPatternContext reflectionContext, TypeDesc type, Func<MetadataType, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- var result = new ArrayBuilder<MetadataType>();
-
- foreach (var nestedType in type.GetNestedTypesOnType(filter, bindingFlags))
- {
- result.Add(nestedType);
- MarkTypeForDynamicallyAccessedMembers(ref reflectionContext, nestedType, DynamicallyAccessedMemberTypes.All);
- }
-
- return result.ToArray();
- }
-
- void MarkPropertiesOnTypeHierarchy(ref ReflectionPatternContext reflectionContext, TypeDesc type, Func<PropertyPseudoDesc, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- foreach (var property in type.GetPropertiesOnTypeHierarchy(filter, bindingFlags))
- MarkProperty(ref reflectionContext, property);
- }
-
- void MarkEventsOnTypeHierarchy(ref ReflectionPatternContext reflectionContext, TypeDesc type, Func<EventPseudoDesc, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- foreach (var @event in type.GetEventsOnTypeHierarchy(filter, bindingFlags))
- MarkEvent(ref reflectionContext, @event);
- }
-
- void ValidateGenericMethodInstantiation(
- ref ReflectionPatternContext reflectionContext,
- MethodDesc genericMethod,
- ValueNode genericParametersArray,
- MethodDesc reflectionMethod)
- {
- if (!genericMethod.HasInstantiation)
- {
- reflectionContext.RecordHandledPattern();
- return;
- }
- if (!AnalyzeGenericInstantiationTypeArray(genericParametersArray, ref reflectionContext, reflectionMethod, genericMethod.GetMethodDefinition().Instantiation))
- {
- reflectionContext.RecordUnrecognizedPattern(
- (int)DiagnosticId.MakeGenericMethod,
- new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(reflectionMethod)));
- }
- else
- {
- reflectionContext.RecordHandledPattern();
- }
- }
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes(BindingFlags? bindingFlags) =>
- (HasBindingFlag(bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag(bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported(bindingFlags) ? DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors(BindingFlags? bindingFlags) =>
- (HasBindingFlag(bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicConstructors : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag(bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported(bindingFlags) ? DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods(BindingFlags? bindingFlags) =>
- (HasBindingFlag(bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicMethods : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag(bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported(bindingFlags) ? DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields(BindingFlags? bindingFlags) =>
- (HasBindingFlag(bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicFields : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag(bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported(bindingFlags) ? DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties(BindingFlags? bindingFlags) =>
- (HasBindingFlag(bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicProperties : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag(bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported(bindingFlags) ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents(BindingFlags? bindingFlags) =>
- (HasBindingFlag(bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicEvents : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag(bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported(bindingFlags) ? DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers(BindingFlags? bindingFlags) =>
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors(bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents(bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields(bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods(bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties(bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes(bindingFlags);
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs
deleted file mode 100644
index 61a48fe965a..00000000000
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics;
-using Internal.IL;
-using Internal.TypeSystem;
-
-using ILLink.Shared;
-
-namespace ILCompiler.Dataflow
-{
- /// <summary>
- /// Helper struct to pass around context information about reflection pattern
- /// as a single parameter (and have a way to extend this in the future if we need to easily).
- /// Also implements a simple validation mechanism to check that the code does report patter recognition
- /// results for all methods it works on.
- /// The promise of the pattern recorder is that for a given reflection method, it will either not talk
- /// about it ever, or it will always report recognized/unrecognized.
- /// </summary>
- struct ReflectionPatternContext : IDisposable
- {
- readonly Logger _logger;
- readonly int _ilOffset;
- readonly MethodIL _sourceIL;
-
-#if DEBUG
- bool _patternAnalysisAttempted;
- bool _patternReported;
-#endif
-
- public TypeSystemEntity Source { get; private set; }
- public Origin MemberWithRequirements { get; private set; }
- public bool ReportingEnabled { get; private set; }
-
- public ReflectionPatternContext(
- Logger logger,
- bool reportingEnabled,
- TypeSystemEntity source,
- Origin memberWithRequirements)
- {
- _logger = logger;
- ReportingEnabled = reportingEnabled;
- Source = source;
- MemberWithRequirements = memberWithRequirements;
- _ilOffset = 0;
- _sourceIL = null;
-
-#if DEBUG
- _patternAnalysisAttempted = false;
- _patternReported = false;
-#endif
- }
-
- public ReflectionPatternContext(
- Logger logger,
- bool reportingEnabled,
- MethodIL source,
- int offset,
- Origin memberWithRequirements)
- : this(logger, reportingEnabled, source.OwningMethod, memberWithRequirements)
- {
- _sourceIL = source;
- _ilOffset = offset;
- }
-
-#pragma warning disable CA1822
- [Conditional("DEBUG")]
- public void AnalyzingPattern()
- {
-#if DEBUG
- _patternAnalysisAttempted = true;
-#endif
- }
-
- [Conditional("DEBUG")]
- public void RecordHandledPattern()
- {
-#if DEBUG
- _patternReported = true;
-#endif
- }
-#pragma warning restore CA1822
-
- public void RecordRecognizedPattern(Action mark)
- {
-#if DEBUG
- if (!_patternAnalysisAttempted)
- throw new InvalidOperationException($"Internal error: To correctly report all patterns, when starting to analyze a pattern the AnalyzingPattern must be called first. {Source} -> {MemberWithRequirements}");
-
- _patternReported = true;
-#endif
-
- mark();
- }
-
- public void RecordUnrecognizedPattern(int messageCode, string message)
- {
-#if DEBUG
- if (!_patternAnalysisAttempted)
- throw new InvalidOperationException($"Internal error: To correctly report all patterns, when starting to analyze a pattern the AnalyzingPattern must be called first. {Source} -> {MemberWithRequirements}");
-
- _patternReported = true;
-#endif
-
- if (ReportingEnabled)
- {
- if (_sourceIL != null)
- _logger.LogWarning(message, messageCode, _sourceIL, _ilOffset, MessageSubCategory.TrimAnalysis);
- else
- _logger.LogWarning(message, messageCode, Source, MessageSubCategory.TrimAnalysis);
- }
- }
-
- public void Dispose()
- {
-#if DEBUG
- if (_patternAnalysisAttempted && !_patternReported)
- throw new InvalidOperationException($"Internal error: A reflection pattern was analyzed, but no result was reported. {Source} -> {MemberWithRequirements}");
-#endif
- }
- }
-}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs
new file mode 100644
index 00000000000..69e03cf2d39
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs
@@ -0,0 +1,47 @@
+// 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.CodeAnalysis;
+using ILCompiler.Dataflow;
+using ILLink.Shared.TypeSystemProxy;
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ partial struct RequireDynamicallyAccessedMembersAction
+ {
+ readonly ReflectionMarker _reflectionMarker;
+ readonly Origin _memberWithRequirements;
+
+ public RequireDynamicallyAccessedMembersAction(
+ ReflectionMarker reflectionMarker,
+ in DiagnosticContext diagnosticContext,
+ Origin memberWithRequirements)
+ {
+ _reflectionMarker = reflectionMarker;
+ _diagnosticContext = diagnosticContext;
+ _memberWithRequirements = memberWithRequirements;
+ }
+
+ public partial bool TryResolveTypeNameAndMark(string typeName, bool needsAssemblyName, out TypeProxy type)
+ {
+ if (_reflectionMarker.TryResolveTypeNameAndMark(typeName, _diagnosticContext.Origin, needsAssemblyName, _memberWithRequirements, out TypeDesc? foundType))
+ {
+ type = new(foundType);
+ return true;
+ }
+ else
+ {
+ type = default;
+ return false;
+ }
+ }
+
+ private partial void MarkTypeForDynamicallyAccessedMembers(in TypeProxy type, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ _reflectionMarker.MarkTypeForDynamicallyAccessedMembers(_diagnosticContext.Origin, type.Type, dynamicallyAccessedMemberTypes, _memberWithRequirements);
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeExtensions.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeExtensions.cs
index 89b9cd764a2..d8a0311b5a6 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeExtensions.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeExtensions.cs
@@ -1,9 +1,17 @@
// 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;
+using ILLink.Shared.TypeSystemProxy;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
+using TypeSystemWellKnownType = Internal.TypeSystem.WellKnownType;
+using ILLinkSharedWellKnownType = ILLink.Shared.TypeSystemProxy.WellKnownType;
+
+#nullable enable
+
namespace ILCompiler.Dataflow
{
static class TypeExtensions
@@ -13,14 +21,41 @@ namespace ILCompiler.Dataflow
return type is MetadataType mdType && mdType.Name == name && mdType.Namespace == ns;
}
- public static bool IsDeclaredOnType(this MethodDesc method, string ns, string name)
+ public static bool IsTypeOf(this TypeDesc type, string fullTypeName)
+ {
+ if (type is not MetadataType metadataType)
+ return false;
+
+ var name = fullTypeName.AsSpan();
+ if (metadataType.Name.Length + 1 > name.Length)
+ return false;
+
+ if (!name.Slice(name.Length - metadataType.Name.Length).Equals(metadataType.Name.AsSpan(), StringComparison.Ordinal))
+ return false;
+
+ if (name[name.Length - metadataType.Name.Length - 1] != '.')
+ return false;
+
+ return name.Slice(0, name.Length - metadataType.Name.Length - 1).Equals(metadataType.Namespace, StringComparison.Ordinal);
+ }
+
+ public static bool IsTypeOf(this TypeDesc type, ILLinkSharedWellKnownType wellKnownType) =>
+ wellKnownType switch
+ {
+ ILLinkSharedWellKnownType.System_String => type.IsWellKnownType(TypeSystemWellKnownType.String),
+ ILLinkSharedWellKnownType.System_Object => type.IsWellKnownType(TypeSystemWellKnownType.Object),
+ ILLinkSharedWellKnownType.System_Void => type.IsWellKnownType(TypeSystemWellKnownType.Void),
+ _ => wellKnownType == WellKnownTypeExtensions.GetWellKnownType((type as MetadataType)?.Namespace ?? string.Empty, ((type as MetadataType)?.Name) ?? string.Empty)
+ };
+
+ public static bool IsDeclaredOnType(this MethodDesc method, string fullTypeName)
{
- return method.OwningType.IsTypeOf(ns, name);
+ return method.OwningType.IsTypeOf(fullTypeName);
}
- public static bool HasParameterOfType(this MethodDesc method, int index, string ns, string name)
+ public static bool HasParameterOfType(this MethodDesc method, int index, string fullTypeName)
{
- return index < method.Signature.Length && method.Signature[index].IsTypeOf(ns, name);
+ return index < method.Signature.Length && method.Signature[index].IsTypeOf(fullTypeName);
}
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeProxy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeProxy.cs
new file mode 100644
index 00000000000..35943c4c58c
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeProxy.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.Collections.Immutable;
+using ILCompiler;
+using ILCompiler.Dataflow;
+using Internal.TypeSystem;
+
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal readonly partial struct TypeProxy
+ {
+ public TypeProxy(TypeDesc type) => Type = type;
+
+ public static implicit operator TypeProxy(TypeDesc type) => new(type);
+
+ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters()
+ {
+ var typeDef = Type.GetTypeDefinition();
+
+ if (!typeDef.HasInstantiation)
+ return ImmutableArray<GenericParameterProxy>.Empty;
+
+ var builder = ImmutableArray.CreateBuilder<GenericParameterProxy>(typeDef.Instantiation.Length);
+ foreach (var genericParameter in typeDef.Instantiation)
+ {
+ builder.Add(new GenericParameterProxy((GenericParameterDesc)genericParameter));
+ }
+
+ return builder.ToImmutableArray();
+ }
+
+ public TypeDesc Type { get; }
+
+ public string Name { get => Type is MetadataType metadataType ? metadataType.Name : string.Empty; }
+
+ public string? Namespace { get => Type is MetadataType metadataType ? metadataType.Namespace : null; }
+
+ public bool IsTypeOf(string @namespace, string name) => Type.IsTypeOf(@namespace, name);
+
+ public bool IsTypeOf(WellKnownType wellKnownType) => Type.IsTypeOf(wellKnownType);
+
+ public string GetDisplayName() => Type.GetDisplayName();
+
+ public override string ToString() => Type.ToString();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ValueNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ValueNode.cs
index e348eec7c2f..9a8254de64c 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ValueNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ValueNode.cs
@@ -3,1325 +3,14 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Text;
-using Internal.IL;
-using Internal.TypeSystem;
-using Internal.TypeSystem.Ecma;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
-using Debug = System.Diagnostics.Debug;
+#nullable enable
namespace ILCompiler.Dataflow
{
- public enum ValueNodeKind
- {
- Invalid, // in case the Kind field is not initialized properly
-
- Unknown, // unknown value, has StaticType from context
-
- Null, // known value
- SystemType, // known value - TypeRepresented
- RuntimeTypeHandle, // known value - TypeRepresented
- KnownString, // known value - Contents
- ConstInt, // known value - Int32
- AnnotatedString, // string with known annotation
-
- MethodParameter, // symbolic placeholder
- MethodReturn, // symbolic placeholder
-
- RuntimeMethodHandle, // known value - MethodRepresented
- SystemReflectionMethodBase, // known value - MethodRepresented
-
- RuntimeTypeHandleForGenericParameter, // symbolic placeholder for generic parameter
- SystemTypeForGenericParameter, // symbolic placeholder for generic parameter
-
- MergePoint, // structural, multiplexer - Values
- GetTypeFromString, // structural, could be known value - KnownString
- Array, // structural, could be known value - Array
-
- LoadField, // structural, could be known value - InstanceValue
- }
-
- /// <summary>
- /// A ValueNode represents a value in the IL dataflow analysis. It may not contain complete information as it is a
- /// best-effort representation. Additionally, as the analysis is linear and does not account for control flow, any
- /// given ValueNode may represent multiple values simultaneously. (This occurs, for example, at control flow join
- /// points when both paths yield values on the IL stack or in a local.)
- /// </summary>
- public abstract class ValueNode : IEquatable<ValueNode>
- {
- public ValueNode()
- {
-#if false // Helpful for debugging a cycle that has inadvertently crept into the graph
- if (this.DetectCycle(new HashSet<ValueNode>()))
- {
- throw new Exception("Found a cycle");
- }
-#endif
- }
-
- /// <summary>
- /// The 'kind' of value node -- this represents the most-derived type and allows us to switch over and do
- /// equality checks without the cost of casting. Intermediate non-leaf types in the ValueNode hierarchy should
- /// be abstract.
- /// </summary>
- public ValueNodeKind Kind { get; protected set; }
-
- /// <summary>
- /// The IL type of the value, represented as closely as possible, but not always exact. It can be null, for
- /// example, when the analysis is imprecise or operating on malformed IL.
- /// </summary>
- public TypeDesc StaticType { get; protected set; }
-
- /// <summary>
- /// Allows the enumeration of the direct children of this node. The ChildCollection struct returned here
- /// supports 'foreach' without allocation.
- /// </summary>
- public ChildCollection Children { get { return new ChildCollection(this); } }
-
- /// <summary>
- /// This property allows you to enumerate all 'unique values' represented by a given ValueNode. The basic idea
- /// is that there will be no MergePointValues in the returned ValueNodes and all structural operations will be
- /// applied so that each 'unique value' can be considered on its own without regard to the structure that led to
- /// it.
- /// </summary>
- public UniqueValueCollection UniqueValuesInternal
- {
- get
- {
- return new UniqueValueCollection(this);
- }
- }
-
- /// <summary>
- /// This protected method is how nodes implement the UniqueValues property. It is protected because it returns
- /// an IEnumerable and we want to avoid allocating an enumerator for the exceedingly common case of there being
- /// only one value in the enumeration. The UniqueValueCollection returned by the UniqueValues property handles
- /// this detail.
- /// </summary>
- protected abstract IEnumerable<ValueNode> EvaluateUniqueValues();
-
- /// <summary>
- /// RepresentsExactlyOneValue is used by the UniqueValues property to allow us to bypass allocating an
- /// enumerator to return just one value. If a node returns 'true' from RepresentsExactlyOneValue, it must also
- /// return that one value from GetSingleUniqueValue. If it always returns 'false', it doesn't need to implement
- /// GetSingleUniqueValue.
- /// </summary>
- protected virtual bool RepresentsExactlyOneValue { get { return false; } }
-
- /// <summary>
- /// GetSingleUniqueValue is called if, and only if, RepresentsExactlyOneValue returns true. It allows us to
- /// bypass the allocation of an enumerator for the common case of returning exactly one value.
- /// </summary>
- protected virtual ValueNode GetSingleUniqueValue()
- {
- // Not implemented because RepresentsExactlyOneValue returns false and, therefore, this method should be
- // unreachable.
- throw new NotImplementedException();
- }
-
- protected abstract int NumChildren { get; }
- protected abstract ValueNode ChildAt(int index);
-
- public virtual bool Equals(ValueNode other)
- {
- return other != null && this.Kind == other.Kind && this.StaticType == other.StaticType;
- }
-
- public abstract override int GetHashCode();
-
- /// <summary>
- /// Each node type must implement this to stringize itself. The expectation is that it is implemented using
- /// ValueNodeDump.ValueNodeToString(), passing any non-ValueNode properties of interest (e.g.
- /// SystemTypeValue.TypeRepresented). Properties that are invariant on a particular node type
- /// should be omitted for clarity.
- /// </summary>
- protected abstract string NodeToString();
-
- public override string ToString()
- {
- return NodeToString();
- }
-
- public override bool Equals(object other)
- {
- if (!(other is ValueNode))
- return false;
-
- return this.Equals((ValueNode)other);
- }
-
- #region Specialized Collection Nested Types
- /// <summary>
- /// ChildCollection struct is used to wrap the operations on a node involving its children. In particular, the
- /// struct implements a GetEnumerator method that is used to allow "foreach (ValueNode node in myNode.Children)"
- /// without heap allocations.
- /// </summary>
- public struct ChildCollection : IEnumerable<ValueNode>
- {
- /// <summary>
- /// Enumerator for children of a ValueNode. Allows foreach(var child in node.Children) to work without
- /// allocating a heap-based enumerator.
- /// </summary>
- public struct Enumerator : IEnumerator<ValueNode>
- {
- int _index;
- readonly ValueNode _parent;
-
- public Enumerator(ValueNode parent)
- {
- _parent = parent;
- _index = -1;
- }
-
- public ValueNode Current { get { return _parent?.ChildAt(_index); } }
-
- object System.Collections.IEnumerator.Current { get { return Current; } }
-
- public bool MoveNext()
- {
- _index++;
- return (_parent != null) ? (_index < _parent.NumChildren) : false;
- }
-
- public void Reset()
- {
- _index = -1;
- }
-
- public void Dispose()
- {
- }
- }
-
- readonly ValueNode _parentNode;
-
- public ChildCollection(ValueNode parentNode) { _parentNode = parentNode; }
-
- // Used by C# 'foreach', when strongly typed, to avoid allocation.
- public Enumerator GetEnumerator()
- {
- return new Enumerator(_parentNode);
- }
-
- IEnumerator<ValueNode> IEnumerable<ValueNode>.GetEnumerator()
- {
- // note the boxing!
- return new Enumerator(_parentNode);
- }
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- // note the boxing!
- return new Enumerator(_parentNode);
- }
-
- public int Count { get { return (_parentNode != null) ? _parentNode.NumChildren : 0; } }
- }
-
- /// <summary>
- /// UniqueValueCollection is used to wrap calls to ValueNode.EvaluateUniqueValues. If a ValueNode represents
- /// only one value, then foreach(ValueNode value in node.UniqueValues) will not allocate a heap-based enumerator.
- ///
- /// This is implented by having each ValueNode tell us whether or not it represents exactly one value or not.
- /// If it does, we fetch it with ValueNode.GetSingleUniqueValue(), otherwise, we fall back to the usual heap-
- /// based IEnumerable returned by ValueNode.EvaluateUniqueValues.
- /// </summary>
- public struct UniqueValueCollection : IEnumerable<ValueNode>
- {
- readonly IEnumerable<ValueNode> _multiValueEnumerable;
- readonly ValueNode _treeNode;
-
- public UniqueValueCollection(ValueNode node)
- {
- if (node.RepresentsExactlyOneValue)
- {
- _multiValueEnumerable = null;
- _treeNode = node;
- }
- else
- {
- _multiValueEnumerable = node.EvaluateUniqueValues();
- _treeNode = null;
- }
- }
-
- public Enumerator GetEnumerator()
- {
- return new Enumerator(_treeNode, _multiValueEnumerable);
- }
-
- IEnumerator<ValueNode> IEnumerable<ValueNode>.GetEnumerator()
- {
- if (_multiValueEnumerable != null)
- {
- return _multiValueEnumerable.GetEnumerator();
- }
-
- // note the boxing!
- return GetEnumerator();
- }
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- if (_multiValueEnumerable != null)
- {
- return _multiValueEnumerable.GetEnumerator();
- }
-
- // note the boxing!
- return GetEnumerator();
- }
-
-
- public struct Enumerator : IEnumerator<ValueNode>
- {
- readonly IEnumerator<ValueNode> _multiValueEnumerator;
- readonly ValueNode _singleValueNode;
- int _index;
-
- public Enumerator(ValueNode treeNode, IEnumerable<ValueNode> mulitValueEnumerable)
- {
- _singleValueNode = treeNode?.GetSingleUniqueValue();
- _multiValueEnumerator = mulitValueEnumerable?.GetEnumerator();
- _index = -1;
- }
-
- public void Reset()
- {
- if (_multiValueEnumerator != null)
- {
- _multiValueEnumerator.Reset();
- return;
- }
-
- _index = -1;
- }
-
- public bool MoveNext()
- {
- if (_multiValueEnumerator != null)
- return _multiValueEnumerator.MoveNext();
-
- _index++;
- return _index == 0;
- }
-
- public ValueNode Current
- {
- get
- {
- if (_multiValueEnumerator != null)
- return _multiValueEnumerator.Current;
-
- if (_index == 0)
- return _singleValueNode;
-
- throw new InvalidOperationException();
- }
- }
-
- object System.Collections.IEnumerator.Current { get { return Current; } }
-
- public void Dispose()
- {
- }
- }
- }
- #endregion
- }
-
- /// <summary>
- /// LeafValueNode represents a 'leaf' in the expression tree. In other words, the node has no ValueNode children.
- /// It *may* still have non-ValueNode 'properties' that are interesting. This class serves, primarily, as a way to
- /// collect up the very common implmentation of NumChildren/ChildAt for leaf nodes and the "represents exactly one
- /// value" optimization. These things aren't on the ValueNode base class because, otherwise, new node types
- /// deriving from ValueNode may 'forget' to implement these things. So this class allows them to remain abstract in
- /// ValueNode while still having a common implementation for all the leaf nodes.
- /// </summary>
- public abstract class LeafValueNode : ValueNode
- {
- protected override int NumChildren { get { return 0; } }
- protected override ValueNode ChildAt(int index) { throw new InvalidOperationException(); }
-
- protected override bool RepresentsExactlyOneValue { get { return true; } }
-
- protected override ValueNode GetSingleUniqueValue() { return this; }
-
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues()
- {
- // Leaf values should not represent more than one value. This method should be unreachable as long as
- // RepresentsExactlyOneValue returns true.
- throw new NotImplementedException();
- }
- }
-
- // These are extension methods because we want to allow the use of them on null 'this' pointers.
- internal static class ValueNodeExtensions
- {
- /// <summary>
- /// Returns true if a ValueNode graph contains a cycle
- /// </summary>
- /// <param name="node">Node to evaluate</param>
- /// <param name="seenNodes">Set of nodes previously seen on the current arc. Callers may pass a non-empty set
- /// to test whether adding that set to this node would create a cycle. Contents will be modified by the walk
- /// and should not be used by the caller after returning</param>
- /// <param name="allNodesSeen">Optional. The set of all nodes encountered during a walk after DetectCycle returns</param>
- /// <returns></returns>
- public static bool DetectCycle(this ValueNode node, HashSet<ValueNode> seenNodes, HashSet<ValueNode> allNodesSeen)
- {
- if (node == null)
- return false;
-
- if (seenNodes.Contains(node))
- return true;
-
- seenNodes.Add(node);
-
- if (allNodesSeen != null)
- {
- allNodesSeen.Add(node);
- }
-
- bool foundCycle = false;
- switch (node.Kind)
- {
- //
- // Leaf nodes
- //
- case ValueNodeKind.Unknown:
- case ValueNodeKind.Null:
- case ValueNodeKind.SystemType:
- case ValueNodeKind.RuntimeTypeHandle:
- case ValueNodeKind.KnownString:
- case ValueNodeKind.AnnotatedString:
- case ValueNodeKind.ConstInt:
- case ValueNodeKind.MethodParameter:
- case ValueNodeKind.MethodReturn:
- case ValueNodeKind.SystemTypeForGenericParameter:
- case ValueNodeKind.RuntimeTypeHandleForGenericParameter:
- case ValueNodeKind.SystemReflectionMethodBase:
- case ValueNodeKind.RuntimeMethodHandle:
- case ValueNodeKind.LoadField:
- break;
-
- //
- // Nodes with children
- //
- case ValueNodeKind.MergePoint:
- foreach (ValueNode val in ((MergePointValue)node).Values)
- {
- if (val.DetectCycle(seenNodes, allNodesSeen))
- {
- foundCycle = true;
- }
- }
- break;
-
- case ValueNodeKind.GetTypeFromString:
- GetTypeFromStringValue gtfsv = (GetTypeFromStringValue)node;
- foundCycle = gtfsv.AssemblyIdentity.DetectCycle(seenNodes, allNodesSeen);
- foundCycle |= gtfsv.NameString.DetectCycle(seenNodes, allNodesSeen);
- break;
-
- case ValueNodeKind.Array:
- ArrayValue av = (ArrayValue)node;
- foundCycle = av.Size.DetectCycle(seenNodes, allNodesSeen);
- foreach (ValueBasicBlockPair pair in av.IndexValues.Values)
- {
- foundCycle |= pair.Value.DetectCycle(seenNodes, allNodesSeen);
- }
- break;
-
- default:
- throw new Exception(String.Format("Unknown node kind: {0}", node.Kind));
- }
- seenNodes.Remove(node);
-
- return foundCycle;
- }
-
- public static ValueNode.UniqueValueCollection UniqueValues(this ValueNode node)
- {
- if (node == null)
- return new ValueNode.UniqueValueCollection(UnknownValue.Instance);
-
- return node.UniqueValuesInternal;
- }
-
- public static int? AsConstInt(this ValueNode node)
- {
- if (node is ConstIntValue constInt)
- return constInt.Value;
- return null;
- }
- }
-
- internal static class ValueNodeDump
- {
- internal static string ValueNodeToString(ValueNode node, params object[] args)
- {
- if (node == null)
- return "<null>";
-
- StringBuilder sb = new StringBuilder();
- sb.Append(node.Kind.ToString());
- sb.Append("(");
- if (args != null)
- {
- for (int i = 0; i < args.Length; i++)
- {
- if (i > 0)
- sb.Append(",");
- sb.Append(args[i] == null ? "<null>" : args[i].ToString());
- }
- }
- sb.Append(")");
- return sb.ToString();
- }
-
- static string GetIndent(int level)
- {
- StringBuilder sb = new StringBuilder(level * 2);
- for (int i = 0; i < level; i++)
- sb.Append(" ");
- return sb.ToString();
- }
-
- public static void DumpTree(this ValueNode node, System.IO.TextWriter writer = null, int indentLevel = 0)
- {
- if (writer == null)
- writer = Console.Out;
-
- writer.Write(GetIndent(indentLevel));
- if (node == null)
- {
- writer.WriteLine("<null>");
- return;
- }
-
- writer.WriteLine(node);
- foreach (ValueNode child in node.Children)
- {
- child.DumpTree(writer, indentLevel + 1);
- }
- }
- }
-
- /// <summary>
- /// Represents an unknown value.
- /// </summary>
- class UnknownValue : LeafValueNode
- {
- private UnknownValue()
- {
- Kind = ValueNodeKind.Unknown;
- StaticType = null;
- }
-
- public static UnknownValue Instance { get; } = new UnknownValue();
-
- public override bool Equals(ValueNode other)
- {
- return base.Equals(other);
- }
-
- public override int GetHashCode()
- {
- // All instances of UnknownValue are equivalent, so they all hash to the same hashcode. This one was
- // chosen for no particular reason at all.
- return 0x98052;
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this);
- }
- }
-
- class NullValue : LeafValueNode
- {
- private NullValue()
- {
- Kind = ValueNodeKind.Null;
- StaticType = null;
- }
-
- public override bool Equals(ValueNode other)
- {
- return base.Equals(other);
- }
-
- public static NullValue Instance { get; } = new NullValue();
-
- public override int GetHashCode()
- {
- // All instances of NullValue are equivalent, so they all hash to the same hashcode. This one was
- // chosen for no particular reason at all.
- return 0x90210;
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this);
- }
- }
-
- /// <summary>
- /// This is a known System.Type value. TypeRepresented is the 'value' of the System.Type.
- /// </summary>
- class SystemTypeValue : LeafValueNode
- {
- public SystemTypeValue(TypeDesc typeRepresented)
- {
- Kind = ValueNodeKind.SystemType;
-
- // Should be System.Type - but we don't have any use case where tracking it like that would matter
- StaticType = null;
-
- TypeRepresented = typeRepresented;
- }
-
- public TypeDesc TypeRepresented { get; private set; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- return Equals(this.TypeRepresented, ((SystemTypeValue)other).TypeRepresented);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, TypeRepresented);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, TypeRepresented);
- }
- }
-
- /// <summary>
- /// This is the System.RuntimeTypeHandle equivalent to a <see cref="SystemTypeValue"/> node.
- /// </summary>
- class RuntimeTypeHandleValue : LeafValueNode
- {
- public RuntimeTypeHandleValue(TypeDesc typeRepresented)
- {
- Kind = ValueNodeKind.RuntimeTypeHandle;
-
- // Should be System.RuntimeTypeHandle, but we don't have a use case for it like that
- StaticType = null;
-
- TypeRepresented = typeRepresented;
- }
-
- public TypeDesc TypeRepresented { get; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- return Equals(this.TypeRepresented, ((RuntimeTypeHandleValue)other).TypeRepresented);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, TypeRepresented);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, TypeRepresented);
- }
- }
-
- /// <summary>
- /// This is a System.Type value which represents generic parameter (basically result of typeof(T))
- /// Its actual type is unknown, but it can have annotations.
- /// </summary>
- class SystemTypeForGenericParameterValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public SystemTypeForGenericParameterValue(GenericParameterDesc genericParameter, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- Kind = ValueNodeKind.SystemTypeForGenericParameter;
-
- // Should be System.Type, but we don't have a use case for it
- StaticType = null;
-
- GenericParameter = genericParameter;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- SourceContext = new GenericParameterOrigin(genericParameter);
- }
-
- public GenericParameterDesc GenericParameter { get; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- var otherValue = (SystemTypeForGenericParameterValue)other;
- return this.GenericParameter == otherValue.GenericParameter && this.DynamicallyAccessedMemberTypes == otherValue.DynamicallyAccessedMemberTypes;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, GenericParameter, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, GenericParameter, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// This is the System.RuntimeTypeHandle equivalent to a <see cref="SystemTypeForGenericParameterValue"/> node.
- /// </summary>
- class RuntimeTypeHandleForGenericParameterValue : LeafValueNode
- {
- public RuntimeTypeHandleForGenericParameterValue(GenericParameterDesc genericParameter)
- {
- Kind = ValueNodeKind.RuntimeTypeHandleForGenericParameter;
-
- // Should be System.RuntimeTypeHandle, but we don't have a use case for it
- StaticType = null;
-
- GenericParameter = genericParameter;
- }
-
- public GenericParameterDesc GenericParameter { get; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- return Equals(this.GenericParameter, ((RuntimeTypeHandleForGenericParameterValue)other).GenericParameter);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, GenericParameter);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, GenericParameter);
- }
- }
-
- /// <summary>
- /// This is the System.RuntimeMethodHandle equivalent to a <see cref="SystemReflectionMethodBaseValue"/> node.
- /// </summary>
- class RuntimeMethodHandleValue : LeafValueNode
- {
- public RuntimeMethodHandleValue(MethodDesc methodRepresented)
- {
- Kind = ValueNodeKind.RuntimeMethodHandle;
-
- // Should be System.RuntimeMethodHandle, but we don't have a use case for it
- StaticType = null;
-
- MethodRepresented = methodRepresented;
- }
-
- public MethodDesc MethodRepresented { get; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- return Equals(this.MethodRepresented, ((RuntimeMethodHandleValue)other).MethodRepresented);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, MethodRepresented);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, MethodRepresented);
- }
- }
-
- /// <summary>
- /// This is a known System.Reflection.MethodBase value. MethodRepresented is the 'value' of the MethodBase.
- /// </summary>
- class SystemReflectionMethodBaseValue : LeafValueNode
- {
- public SystemReflectionMethodBaseValue(MethodDesc methodRepresented)
- {
- Kind = ValueNodeKind.SystemReflectionMethodBase;
-
- // Should be System.Reflection.MethodBase, but we don't have a use case for it
- StaticType = null;
-
- MethodRepresented = methodRepresented;
- }
-
- public MethodDesc MethodRepresented { get; private set; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- return Equals(this.MethodRepresented, ((SystemReflectionMethodBaseValue)other).MethodRepresented);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, MethodRepresented);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, MethodRepresented);
- }
- }
-
- /// <summary>
- /// A known string - such as the result of a ldstr.
- /// </summary>
- class KnownStringValue : LeafValueNode
- {
- public KnownStringValue(string contents)
- {
- Kind = ValueNodeKind.KnownString;
-
- // Should be System.String, but we don't have a use case for it
- StaticType = null;
-
- Contents = contents;
- }
-
- public string Contents { get; private set; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- return this.Contents == ((KnownStringValue)other).Contents;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, Contents);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, "\"" + Contents + "\"");
- }
- }
-
- /// <summary>
- /// Base class for all nodes which can have dynamically accessed member annotation.
- /// </summary>
- abstract class LeafValueWithDynamicallyAccessedMemberNode : LeafValueNode
- {
- public Origin SourceContext { get; protected set; }
-
- /// <summary>
- /// The bitfield of dynamically accessed member types the node guarantees
- /// </summary>
- public DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; protected set; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
- var otherValue = (LeafValueWithDynamicallyAccessedMemberNode)other;
- return SourceContext == otherValue.SourceContext
- && DynamicallyAccessedMemberTypes == otherValue.DynamicallyAccessedMemberTypes;
- }
- }
-
- /// <summary>
- /// A value that came from a method parameter - such as the result of a ldarg.
- /// </summary>
- class MethodParameterValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public MethodParameterValue(MethodDesc method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- Kind = ValueNodeKind.MethodParameter;
- StaticType = !method.Signature.IsStatic
- ? (parameterIndex == 0
- ? method.OwningType
- : method.Signature[parameterIndex - 1])
- : method.Signature[parameterIndex];
- ParameterIndex = parameterIndex;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- SourceContext = !method.Signature.IsStatic && parameterIndex == 0 ?
- new MethodOrigin(method) :
- new ParameterOrigin(method, parameterIndex);
- }
-
- public int ParameterIndex { get; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- var otherValue = (MethodParameterValue)other;
- return this.ParameterIndex == otherValue.ParameterIndex;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, ParameterIndex, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, ParameterIndex, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// String with a known annotation.
- /// </summary>
- class AnnotatedStringValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public AnnotatedStringValue(Origin sourceContext, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- Kind = ValueNodeKind.AnnotatedString;
-
- // Should be System.String, but we don't have a use case for it
- StaticType = null;
-
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- SourceContext = sourceContext;
- }
-
- public override bool Equals(ValueNode other)
- {
- return base.Equals(other);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// Return value from a method
- /// </summary>
- class MethodReturnValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public MethodReturnValue(MethodDesc method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- Kind = ValueNodeKind.MethodReturn;
- StaticType = method.Signature.ReturnType;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- SourceContext = new MethodReturnOrigin(method);
- }
-
- public override bool Equals(ValueNode other)
- {
- return base.Equals(other);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// A merge point commonly occurs due to control flow in a method body. It represents a set of values
- /// from different paths through the method. It is the reason for EvaluateUniqueValues, which essentially
- /// provides an enumeration over all the concrete values represented by a given ValueNode after 'erasing'
- /// the merge point nodes.
- /// </summary>
- class MergePointValue : ValueNode
- {
- private MergePointValue(ValueNode one, ValueNode two)
- {
- Kind = ValueNodeKind.MergePoint;
- StaticType = null;
- m_values = new ValueNodeHashSet();
-
- if (one.Kind == ValueNodeKind.MergePoint)
- {
- MergePointValue mpvOne = (MergePointValue)one;
- foreach (ValueNode value in mpvOne.Values)
- m_values.Add(value);
- }
- else
- m_values.Add(one);
-
- if (two.Kind == ValueNodeKind.MergePoint)
- {
- MergePointValue mpvTwo = (MergePointValue)two;
- foreach (ValueNode value in mpvTwo.Values)
- m_values.Add(value);
- }
- else
- m_values.Add(two);
- }
-
- public MergePointValue()
- {
- Kind = ValueNodeKind.MergePoint;
- m_values = new ValueNodeHashSet();
- }
-
- public void AddValue(ValueNode node)
- {
- // we are mutating our state, so we must invalidate any cached knowledge
- //InvalidateIsOpen ();
-
- if (node.Kind == ValueNodeKind.MergePoint)
- {
- foreach (ValueNode value in ((MergePointValue)node).Values)
- m_values.Add(value);
- }
- else
- m_values.Add(node);
-
-#if false
- if (this.DetectCycle(new HashSet<ValueNode>()))
- {
- throw new Exception("Found a cycle");
- }
-#endif
- }
-
- readonly ValueNodeHashSet m_values;
-
- public ValueNodeHashSet Values { get { return m_values; } }
-
- protected override int NumChildren { get { return Values.Count; } }
- protected override ValueNode ChildAt(int index)
- {
- if (index < NumChildren)
- return Values.ElementAt(index);
- throw new InvalidOperationException();
- }
-
- public static ValueNode MergeValues(ValueNode one, ValueNode two)
- {
- if (one == null)
- return two;
- else if (two == null)
- return one;
- else if (one.Equals(two))
- return one;
- else
- return new MergePointValue(one, two);
- }
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues()
- {
- foreach (ValueNode value in Values)
- {
- foreach (ValueNode uniqueValue in value.UniqueValuesInternal)
- {
- yield return uniqueValue;
- }
- }
- }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- MergePointValue otherMpv = (MergePointValue)other;
- if (this.Values.Count != otherMpv.Values.Count)
- return false;
-
- foreach (ValueNode value in this.Values)
- {
- if (!otherMpv.Values.Contains(value))
- return false;
- }
- return true;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, Values);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this);
- }
- }
-
- delegate TypeDesc TypeResolver(string assemblyString, string typeString);
-
- /// <summary>
- /// The result of a Type.GetType.
- /// AssemblyIdentity is the scope in which to resolve if the type name string is not assembly-qualified.
- /// </summary>
-
-#pragma warning disable CA1812 // GetTypeFromStringValue is never instantiated
- class GetTypeFromStringValue : ValueNode
- {
- private readonly TypeResolver _resolver;
-
- public GetTypeFromStringValue(TypeResolver resolver, ValueNode assemblyIdentity, ValueNode nameString)
- {
- _resolver = resolver;
- Kind = ValueNodeKind.GetTypeFromString;
-
- // Should be System.Type, but we don't have a use case for it
- StaticType = null;
-
- AssemblyIdentity = assemblyIdentity;
- NameString = nameString;
- }
-
- public ValueNode AssemblyIdentity { get; private set; }
-
- public ValueNode NameString { get; private set; }
-
- protected override int NumChildren { get { return 2; } }
- protected override ValueNode ChildAt(int index)
- {
- if (index == 0) return AssemblyIdentity;
- if (index == 1) return NameString;
- throw new InvalidOperationException();
- }
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues()
- {
- HashSet<string> names = null;
-
- foreach (ValueNode nameStringValue in NameString.UniqueValuesInternal)
- {
- if (nameStringValue.Kind == ValueNodeKind.KnownString)
- {
- if (names == null)
- {
- names = new HashSet<string>();
- }
-
- string typeName = ((KnownStringValue)nameStringValue).Contents;
- names.Add(typeName);
- }
- }
-
- bool foundAtLeastOne = false;
-
- if (names != null)
- {
- foreach (ValueNode assemblyValue in AssemblyIdentity.UniqueValuesInternal)
- {
- if (assemblyValue.Kind == ValueNodeKind.KnownString)
- {
- string assemblyName = ((KnownStringValue)assemblyValue).Contents;
-
- foreach (string name in names)
- {
- TypeDesc typeDefinition = _resolver(assemblyName, name);
- if (typeDefinition != null)
- {
- foundAtLeastOne = true;
- yield return new SystemTypeValue(typeDefinition);
- }
- }
- }
- }
- }
-
- if (!foundAtLeastOne)
- yield return UnknownValue.Instance;
- }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- GetTypeFromStringValue otherGtfs = (GetTypeFromStringValue)other;
-
- return this.AssemblyIdentity.Equals(otherGtfs.AssemblyIdentity) &&
- this.NameString.Equals(otherGtfs.NameString);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, AssemblyIdentity, NameString);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, NameString);
- }
- }
-
- /// <summary>
- /// A representation of a ldfld. Note that we don't have a representation of objects containing fields
- /// so there isn't much that can be done with this node type yet.
- /// </summary>
- class LoadFieldValue : LeafValueWithDynamicallyAccessedMemberNode
- {
- public LoadFieldValue(FieldDesc fieldToLoad, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- Kind = ValueNodeKind.LoadField;
- StaticType = fieldToLoad.FieldType;
- Field = fieldToLoad;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- SourceContext = new FieldOrigin(fieldToLoad);
- }
-
- public FieldDesc Field { get; private set; }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- LoadFieldValue otherLfv = (LoadFieldValue)other;
- return Equals(this.Field, otherLfv.Field);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, Field, DynamicallyAccessedMemberTypes);
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, Field, DynamicallyAccessedMemberTypes);
- }
- }
-
- /// <summary>
- /// Represents a ldc on an int32.
- /// </summary>
- class ConstIntValue : LeafValueNode
- {
- public ConstIntValue(int value)
- {
- Kind = ValueNodeKind.ConstInt;
-
- // Should be System.Int32, but we don't have a usecase for it right now
- StaticType = null;
-
- Value = value;
- }
-
- public int Value { get; private set; }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, Value);
- }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- ConstIntValue otherCiv = (ConstIntValue)other;
- return Value == otherCiv.Value;
- }
-
- protected override string NodeToString()
- {
- return ValueNodeDump.ValueNodeToString(this, Value);
- }
- }
-
- class ArrayValue : ValueNode
- {
- protected override int NumChildren => 1 + IndexValues.Count;
-
- /// <summary>
- /// Constructs an array value of the given size
- /// </summary>
- public ArrayValue(ValueNode size, TypeDesc elementType)
- {
- Kind = ValueNodeKind.Array;
- // Should be System.Array (or similar), but we don't have a use case for it
- StaticType = null;
- Size = size ?? UnknownValue.Instance;
- ElementType = elementType;
- IndexValues = new Dictionary<int, ValueBasicBlockPair>();
- }
- private ArrayValue(ValueNode size, TypeDesc elementType, Dictionary<int, ValueBasicBlockPair> indexValues)
- : this(size, elementType)
- {
- IndexValues = indexValues;
- }
-
- public ValueNode Size { get; }
- public TypeDesc ElementType { get; }
- public Dictionary<int, ValueBasicBlockPair> IndexValues { get; }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind, Size);
- }
-
- public override bool Equals(ValueNode other)
- {
- if (!base.Equals(other))
- return false;
-
- ArrayValue otherArr = (ArrayValue)other;
- bool equals = Size.Equals(otherArr.Size);
- equals &= IndexValues.Count == otherArr.IndexValues.Count;
- if (!equals)
- return false;
- // If both sets T and O are the same size and "T intersect O" is empty, then T == O.
- HashSet<KeyValuePair<int, ValueBasicBlockPair>> thisValueSet = new(IndexValues);
- HashSet<KeyValuePair<int, ValueBasicBlockPair>> otherValueSet = new(otherArr.IndexValues);
- thisValueSet.ExceptWith(otherValueSet);
- return thisValueSet.Count == 0;
- }
-
- protected override string NodeToString()
- {
- // TODO: Use StringBuilder and remove Linq usage.
- return $"(Array Size:{ValueNodeDump.ValueNodeToString(this, Size)}, Values:({string.Join(',', IndexValues.Select(v => $"({v.Key},{ValueNodeDump.ValueNodeToString(v.Value.Value)})"))})";
- }
-
- protected override IEnumerable<ValueNode> EvaluateUniqueValues()
- {
- foreach (var sizeConst in Size.UniqueValuesInternal)
- yield return new ArrayValue(sizeConst, ElementType, IndexValues);
- }
-
- protected override ValueNode ChildAt(int index)
- {
- if (index == 0) return Size;
- if (index - 1 <= IndexValues.Count)
- return IndexValues.Values.ElementAt(index - 1).Value;
-
- throw new InvalidOperationException();
- }
- }
-
- #region ValueNode Collections
- public class ValueNodeList : List<ValueNode>
+ public class ValueNodeList : List<MultiValue>
{
public ValueNodeList()
{
@@ -1332,17 +21,20 @@ namespace ILCompiler.Dataflow
{
}
- public ValueNodeList(List<ValueNode> other)
+ public ValueNodeList(List<MultiValue> other)
: base(other)
{
}
public override int GetHashCode()
{
- return HashUtils.CalcHashCodeEnumerable(this);
+ HashCode hashCode = new HashCode();
+ foreach (var item in this)
+ hashCode.Add(item.GetHashCode());
+ return hashCode.ToHashCode();
}
- public override bool Equals(object other)
+ public override bool Equals(object? other)
{
if (!(other is ValueNodeList otherList))
return false;
@@ -1352,57 +44,22 @@ namespace ILCompiler.Dataflow
for (int i = 0; i < Count; i++)
{
- if (!(otherList[i]?.Equals(this[i]) ?? (this[i] is null)))
+ if (!otherList[i].Equals(this[i]))
return false;
}
return true;
}
}
- class ValueNodeHashSet : HashSet<ValueNode>
- {
- public override int GetHashCode()
- {
- return HashUtils.CalcHashCodeEnumerable(this);
- }
-
- public override bool Equals(object other)
- {
- if (!(other is ValueNodeHashSet otherSet))
- return false;
-
- if (otherSet.Count != Count)
- return false;
-
- IEnumerator<ValueNode> thisEnumerator = this.GetEnumerator();
- IEnumerator<ValueNode> otherEnumerator = otherSet.GetEnumerator();
-
- for (int i = 0; i < Count; i++)
- {
- thisEnumerator.MoveNext();
- otherEnumerator.MoveNext();
- if (!thisEnumerator.Current.Equals(otherEnumerator.Current))
- return false;
- }
- return true;
- }
- }
- #endregion
-
- static class HashUtils
+ public struct ValueBasicBlockPair
{
- public static int CalcHashCodeEnumerable<T>(IEnumerable<T> list) where T : class
+ public ValueBasicBlockPair(MultiValue value, int basicBlockIndex)
{
- HashCode hashCode = new HashCode();
- foreach (var item in list)
- hashCode.Add(item);
- return hashCode.ToHashCode();
+ Value = value;
+ BasicBlockIndex = basicBlockIndex;
}
- }
- public struct ValueBasicBlockPair
- {
- public ValueNode Value;
- public int BasicBlockIndex;
+ public MultiValue Value { get; }
+ public int BasicBlockIndex { get; }
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logger.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logger.cs
index 7efb6460e10..07a9e084257 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logger.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logger.cs
@@ -87,49 +87,13 @@ namespace ILCompiler
public void LogWarning(string text, int code, MethodIL origin, int ilOffset, string subcategory = MessageSubCategory.None)
{
- string document = null;
- int? lineNumber = null;
-
- IEnumerable<ILSequencePoint> sequencePoints = origin.GetDebugInfo()?.GetSequencePoints();
- if (sequencePoints != null)
- {
- foreach (var sequencePoint in sequencePoints)
- {
- if (sequencePoint.Offset <= ilOffset)
- {
- document = sequencePoint.Document;
- lineNumber = sequencePoint.LineNumber;
- }
- }
- }
-
- MethodDesc warnedMethod = CompilerGeneratedState.GetUserDefinedMethodForCompilerGeneratedMember(origin.OwningMethod) ?? origin.OwningMethod;
-
- MessageOrigin messageOrigin = new MessageOrigin(warnedMethod, document, lineNumber, null);
+ MessageOrigin messageOrigin = new MessageOrigin(origin, ilOffset);
LogWarning(text, code, messageOrigin, subcategory);
}
public void LogWarning(MethodIL origin, int ilOffset, DiagnosticId id, params string[] args)
{
- string document = null;
- int? lineNumber = null;
-
- IEnumerable<ILSequencePoint> sequencePoints = origin.GetDebugInfo()?.GetSequencePoints();
- if (sequencePoints != null)
- {
- foreach (var sequencePoint in sequencePoints)
- {
- if (sequencePoint.Offset <= ilOffset)
- {
- document = sequencePoint.Document;
- lineNumber = sequencePoint.LineNumber;
- }
- }
- }
-
- MethodDesc warnedMethod = CompilerGeneratedState.GetUserDefinedMethodForCompilerGeneratedMember(origin.OwningMethod) ?? origin.OwningMethod;
-
- MessageOrigin messageOrigin = new MessageOrigin(warnedMethod, document, lineNumber, null);
+ MessageOrigin messageOrigin = new MessageOrigin(origin, ilOffset);
LogWarning(messageOrigin, id, args);
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
index 4d1f784b224..c5b5a458afb 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
@@ -17,7 +17,7 @@ using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
using ILLink.Shared;
-using FlowAnnotations = ILCompiler.Dataflow.FlowAnnotations;
+using FlowAnnotations = ILLink.Shared.TrimAnalysis.FlowAnnotations;
using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
using CombinedDependencyList = System.Collections.Generic.List<ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.CombinedDependencyListEntry>;
using Debug = System.Diagnostics.Debug;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
index 754a4206182..6f19f9f7acc 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
@@ -314,16 +314,29 @@
<Compile Include="Compiler\CompilerTypeSystemContext.EnumMethods.cs" />
<Compile Include="Compiler\CompilerTypeSystemContext.ValueTypeMethods.cs" />
<Compile Include="Compiler\CompilerGeneratedInteropStubManager.cs" />
+ <Compile Include="Compiler\Dataflow\ArrayValue.cs" />
+ <Compile Include="Compiler\Dataflow\DiagnosticContext.cs" />
<Compile Include="Compiler\Dataflow\DynamicallyAccessedMembersBinder.cs" />
<Compile Include="Compiler\Dataflow\EcmaExtensions.cs" />
+ <Compile Include="Compiler\Dataflow\FieldValue.cs" />
<Compile Include="Compiler\Dataflow\FlowAnnotations.cs" />
+ <Compile Include="Compiler\Dataflow\GenericParameterProxy.cs" />
+ <Compile Include="Compiler\Dataflow\GenericParameterValue.cs" />
+ <Compile Include="Compiler\Dataflow\HandleCallAction.cs" />
+ <Compile Include="Compiler\Dataflow\IValueWithStaticType.cs" />
<Compile Include="Compiler\Dataflow\MethodBodyScanner.cs" />
+ <Compile Include="Compiler\Dataflow\MethodParameterValue.cs" />
+ <Compile Include="Compiler\Dataflow\MethodProxy.cs" />
+ <Compile Include="Compiler\Dataflow\MethodReturnValue.cs" />
+ <Compile Include="Compiler\Dataflow\MethodThisParameterValue.cs" />
<Compile Include="Compiler\Dataflow\DiagnosticUtilities.cs" />
<Compile Include="Compiler\Dataflow\Origin.cs" />
<Compile Include="Compiler\Dataflow\ReflectionMethodBodyScanner.cs" />
- <Compile Include="Compiler\Dataflow\ReflectionPatternContext.cs" />
+ <Compile Include="Compiler\Dataflow\ReflectionMarker.cs" />
+ <Compile Include="Compiler\Dataflow\RequireDynamicallyAccessedMembersAction.cs" />
<Compile Include="Compiler\Dataflow\ScannerExtensions.cs" />
<Compile Include="Compiler\Dataflow\TypeExtensions.cs" />
+ <Compile Include="Compiler\Dataflow\TypeProxy.cs" />
<Compile Include="Compiler\Dataflow\ValueNode.cs" />
<Compile Include="Compiler\DebugInformationProvider.cs" />
<Compile Include="Compiler\DependencyAnalysis\CustomAttributeMetadataNode.cs" />
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs
index beaf854a71a..817e136077f 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs
@@ -15,19 +15,8 @@ namespace ILCompiler
/// </summary>
public class NoMethodsCompilationModuleGroup : ReadyToRunCompilationModuleGroupBase
{
- public NoMethodsCompilationModuleGroup(
- CompilerTypeSystemContext context,
- bool isCompositeBuildMode,
- bool isInputBubble,
- IEnumerable<EcmaModule> compilationModuleSet,
- IEnumerable<ModuleDesc> versionBubbleModuleSet,
- bool compileGenericDependenciesFromVersionBubbleModuleSet) :
- base(context,
- isCompositeBuildMode,
- isInputBubble,
- compilationModuleSet,
- versionBubbleModuleSet,
- compileGenericDependenciesFromVersionBubbleModuleSet)
+ public NoMethodsCompilationModuleGroup(ReadyToRunCompilationModuleGroupConfig config) :
+ base(config)
{
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs
index 84ec3e175cb..d87baeff11f 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs
@@ -14,6 +14,16 @@ using Debug = System.Diagnostics.Debug;
namespace ILCompiler
{
+ public class ReadyToRunCompilationModuleGroupConfig
+ {
+ public CompilerTypeSystemContext Context;
+ public bool IsCompositeBuildMode;
+ public bool IsInputBubble;
+ public IEnumerable<EcmaModule> CompilationModuleSet;
+ public IEnumerable<ModuleDesc> VersionBubbleModuleSet;
+ public bool CompileGenericDependenciesFromVersionBubbleModuleSet;
+ }
+
public abstract class ReadyToRunCompilationModuleGroupBase : CompilationModuleGroup
{
protected readonly HashSet<EcmaModule> _compilationModuleSet;
@@ -30,26 +40,20 @@ namespace ILCompiler
private CompilationUnitIndex _nextCompilationUnit = CompilationUnitIndex.FirstDynamicallyAssigned;
private ModuleTokenResolver _tokenResolver = null;
- public ReadyToRunCompilationModuleGroupBase(
- CompilerTypeSystemContext context,
- bool isCompositeBuildMode,
- bool isInputBubble,
- IEnumerable<EcmaModule> compilationModuleSet,
- IEnumerable<ModuleDesc> versionBubbleModuleSet,
- bool compileGenericDependenciesFromVersionBubbleModuleSet)
+ public ReadyToRunCompilationModuleGroupBase(ReadyToRunCompilationModuleGroupConfig config)
{
- _compilationModuleSet = new HashSet<EcmaModule>(compilationModuleSet);
- _isCompositeBuildMode = isCompositeBuildMode;
- _isInputBubble = isInputBubble;
+ _compilationModuleSet = new HashSet<EcmaModule>(config.CompilationModuleSet);
+ _isCompositeBuildMode = config.IsCompositeBuildMode;
+ _isInputBubble = config.IsInputBubble;
Debug.Assert(_isCompositeBuildMode || _compilationModuleSet.Count == 1);
- _versionBubbleModuleSet = new HashSet<ModuleDesc>(versionBubbleModuleSet);
+ _versionBubbleModuleSet = new HashSet<ModuleDesc>(config.VersionBubbleModuleSet);
_versionBubbleModuleSet.UnionWith(_compilationModuleSet);
- _compileGenericDependenciesFromVersionBubbleModuleSet = compileGenericDependenciesFromVersionBubbleModuleSet;
+ _compileGenericDependenciesFromVersionBubbleModuleSet = config.CompileGenericDependenciesFromVersionBubbleModuleSet;
- _tokenResolver = new ModuleTokenResolver(this, context);
+ _tokenResolver = new ModuleTokenResolver(this, config.Context);
}
public ModuleTokenResolver Resolver => _tokenResolver;
@@ -345,23 +349,6 @@ namespace ILCompiler
public sealed override bool GeneratesPInvoke(MethodDesc method)
{
- // PInvokes depend on details of the core library, so for now only compile them if:
- // 1) We're compiling the core library module, or
- // 2) We're compiling any module, and no marshalling is needed
- //
- // TODO Future: consider compiling PInvokes with complex marshalling in version bubble
- // mode when the core library is included in the bubble.
-
- Debug.Assert(method is EcmaMethod);
-
- // If the PInvoke is declared on an external module, we can only compile it if
- // that module is part of the version bubble.
- if (!_versionBubbleModuleSet.Contains(((EcmaMethod)method).Module))
- return false;
-
- if (((EcmaMethod)method).Module.Equals(method.Context.SystemModule))
- return true;
-
return !Marshaller.IsMarshallingRequired(method);
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs
index f3c2bd46bc4..837708dead3 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunSingleAssemblyCompilationModuleGroup.cs
@@ -17,18 +17,8 @@ namespace ILCompiler
private bool _profileGuidedCompileRestrictionSet;
public ReadyToRunSingleAssemblyCompilationModuleGroup(
- CompilerTypeSystemContext context,
- bool isCompositeBuildMode,
- bool isInputBubble,
- IEnumerable<EcmaModule> compilationModuleSet,
- IEnumerable<ModuleDesc> versionBubbleModuleSet,
- bool compileGenericDependenciesFromVersionBubbleModuleSet) :
- base(context,
- isCompositeBuildMode,
- isInputBubble,
- compilationModuleSet,
- versionBubbleModuleSet,
- compileGenericDependenciesFromVersionBubbleModuleSet)
+ ReadyToRunCompilationModuleGroupConfig config) :
+ base(config)
{
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/SingleMethodCompilationModuleGroup.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/SingleMethodCompilationModuleGroup.cs
index e6bd80b73b5..3827c75a55f 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/SingleMethodCompilationModuleGroup.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/SingleMethodCompilationModuleGroup.cs
@@ -17,19 +17,9 @@ namespace ILCompiler
private MethodDesc _method;
public SingleMethodCompilationModuleGroup(
- CompilerTypeSystemContext context,
- bool isCompositeBuildMode,
- bool isInputBubble,
- IEnumerable<EcmaModule> compilationModuleSet,
- IEnumerable<ModuleDesc> versionBubbleModuleSet,
- bool compileGenericDependenciesFromVersionBubbleModuleSet,
+ ReadyToRunCompilationModuleGroupConfig config,
MethodDesc method) :
- base(context,
- isCompositeBuildMode,
- isInputBubble,
- compilationModuleSet,
- versionBubbleModuleSet,
- compileGenericDependenciesFromVersionBubbleModuleSet)
+ base(config)
{
_method = method;
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs
index 6fc1687d7a7..e34694b5019 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs
@@ -41,22 +41,6 @@ namespace Internal.IL.Stubs
TypeDesc nativeReturnType = _marshallers[0].NativeParameterType;
TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];
- MetadataType stubHelpersType = InteropTypes.GetStubHelpers(context);
-
- // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
- if (_importMetadata.Flags.SetLastError)
- {
- if (!MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)_targetMethod.OwningType).Module))
- {
- // When runtime marshalling is disabled, we don't support generating the stub IL
- // in Ready-to-Run so we can correctly throw an exception at runtime when the user tries to
- // use SetLastError=true when marshalling is disabled.
- throw new NotSupportedException();
- }
- callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
- stubHelpersType.GetKnownMethod("ClearLastError", null)));
- }
-
for (int i = 1; i < _marshallers.Length; i++)
{
nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
@@ -69,14 +53,6 @@ namespace Internal.IL.Stubs
var rawTargetMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig);
callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(rawTargetMethod));
-
- // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError
- // so that last error can be used later by calling Marshal.GetLastPInvokeError
- if (_importMetadata.Flags.SetLastError)
- {
- callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
- stubHelpersType.GetKnownMethod("SetLastError", null)));
- }
}
private MethodIL EmitIL()
@@ -93,6 +69,9 @@ namespace Internal.IL.Stubs
if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute"))
throw new NotSupportedException();
+ if (_importMetadata.Flags.SetLastError)
+ throw new NotSupportedException();
+
PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
ILEmitter emitter = pInvokeILCodeStreams.Emitter;
ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream;
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs
index ddb1d24c1b5..b7843dca9ea 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs
@@ -9,6 +9,7 @@ namespace Internal.TypeSystem.Interop
{
protected static Marshaller CreateMarshaller(MarshallerKind kind)
{
+ // ReadyToRun only supports emitting IL for blittable types
switch (kind)
{
case MarshallerKind.Enum:
@@ -16,23 +17,8 @@ namespace Internal.TypeSystem.Interop
case MarshallerKind.BlittableStruct:
case MarshallerKind.UnicodeChar:
return new BlittableValueMarshaller();
- case MarshallerKind.BlittableStructPtr:
- return new BlittableStructPtrMarshaller();
- case MarshallerKind.BlittableArray:
- return new BlittableArrayMarshaller();
- case MarshallerKind.Bool:
- case MarshallerKind.CBool:
- return new BooleanMarshaller();
- case MarshallerKind.AnsiString:
- return new AnsiStringMarshaller();
- case MarshallerKind.SafeHandle:
- return new SafeHandleMarshaller();
- case MarshallerKind.UnicodeString:
- return new UnicodeStringMarshaller();
case MarshallerKind.VoidReturn:
return new VoidReturnMarshaller();
- case MarshallerKind.FunctionPointer:
- return new DelegateMarshaller();
default:
// ensures we don't throw during create marshaller. We will throw NSE
// during EmitIL which will be handled.
diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs
index 647ee1f7a9e..925fd5c9a90 100644
--- a/src/coreclr/tools/aot/ILCompiler/Program.cs
+++ b/src/coreclr/tools/aot/ILCompiler/Program.cs
@@ -771,7 +771,7 @@ namespace ILCompiler
DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy = new DefaultDynamicInvokeThunkGenerationPolicy();
- var flowAnnotations = new Dataflow.FlowAnnotations(logger, ilProvider);
+ var flowAnnotations = new ILLink.Shared.TrimAnalysis.FlowAnnotations(logger, ilProvider);
MetadataManager metadataManager = new UsageBasedMetadataManager(
compilationGroup,
diff --git a/src/coreclr/tools/aot/ILLink.Shared/Annotations.cs b/src/coreclr/tools/aot/ILLink.Shared/Annotations.cs
new file mode 100644
index 00000000000..ca09218c0cc
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/Annotations.cs
@@ -0,0 +1,138 @@
+// 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;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using ILLink.Shared.TrimAnalysis;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared
+{
+ // Temporary workaround - should be removed once linker can be upgraded to build against
+ // high enough version of the framework which has this enum value.
+ internal static class DynamicallyAccessedMemberTypesOverlay
+ {
+ public const DynamicallyAccessedMemberTypes Interfaces = (DynamicallyAccessedMemberTypes) 0x2000;
+ }
+
+ internal static class Annotations
+ {
+ public static bool SourceHasRequiredAnnotations (
+ DynamicallyAccessedMemberTypes sourceMemberTypes,
+ DynamicallyAccessedMemberTypes targetMemberTypes,
+ out string missingMemberTypesString)
+ {
+ missingMemberTypesString = string.Empty;
+
+ var missingMemberTypes = GetMissingMemberTypes (targetMemberTypes, sourceMemberTypes);
+ if (missingMemberTypes == DynamicallyAccessedMemberTypes.None)
+ return true;
+
+ missingMemberTypesString = GetMemberTypesString (missingMemberTypes);
+ return false;
+ }
+
+ public static DynamicallyAccessedMemberTypes GetMissingMemberTypes (DynamicallyAccessedMemberTypes requiredMemberTypes, DynamicallyAccessedMemberTypes availableMemberTypes)
+ {
+ if (availableMemberTypes.HasFlag (requiredMemberTypes))
+ return DynamicallyAccessedMemberTypes.None;
+
+ if (requiredMemberTypes == DynamicallyAccessedMemberTypes.All)
+ return DynamicallyAccessedMemberTypes.All;
+
+ var missingMemberTypes = requiredMemberTypes & ~availableMemberTypes;
+
+ // PublicConstructors is a special case since its value is 3 - so PublicParameterlessConstructor (1) | _PublicConstructor_WithMoreThanOneParameter_ (2)
+ // The above bit logic only works for value with single bit set.
+ if (requiredMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors) &&
+ !availableMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors))
+ missingMemberTypes |= DynamicallyAccessedMemberTypes.PublicConstructors;
+
+ return missingMemberTypes;
+ }
+
+ public static string GetMemberTypesString (DynamicallyAccessedMemberTypes memberTypes)
+ {
+ Debug.Assert (memberTypes != DynamicallyAccessedMemberTypes.None);
+
+ if (memberTypes == DynamicallyAccessedMemberTypes.All)
+ return $"'{nameof (DynamicallyAccessedMemberTypes)}.{nameof (DynamicallyAccessedMemberTypes.All)}'";
+
+ var memberTypesList = AllDynamicallyAccessedMemberTypes
+ .Where (damt => (memberTypes & damt) == damt && damt != DynamicallyAccessedMemberTypes.None)
+ .ToList ();
+
+ if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors))
+ memberTypesList.Remove (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
+
+ return string.Join (", ", memberTypesList.Select (mt => {
+ string mtName = mt == DynamicallyAccessedMemberTypesOverlay.Interfaces
+ ? nameof (DynamicallyAccessedMemberTypesOverlay.Interfaces)
+ : mt.ToString ();
+
+ return $"'{nameof (DynamicallyAccessedMemberTypes)}.{mtName}'";
+ }));
+ }
+
+ static readonly DynamicallyAccessedMemberTypes[] AllDynamicallyAccessedMemberTypes = GetAllDynamicallyAccessedMemberTypes ();
+
+ static DynamicallyAccessedMemberTypes[] GetAllDynamicallyAccessedMemberTypes ()
+ {
+ var values = new HashSet<DynamicallyAccessedMemberTypes> (
+ Enum.GetValues (typeof (DynamicallyAccessedMemberTypes))
+ .Cast<DynamicallyAccessedMemberTypes> ());
+ if (!values.Contains (DynamicallyAccessedMemberTypesOverlay.Interfaces))
+ values.Add (DynamicallyAccessedMemberTypesOverlay.Interfaces);
+ return values.ToArray ();
+ }
+
+ public static (DiagnosticId Id, string[] Arguments) GetDiagnosticForAnnotationMismatch (ValueWithDynamicallyAccessedMembers source, ValueWithDynamicallyAccessedMembers target, string missingAnnotations)
+ {
+ DiagnosticId diagnosticId = (source, target) switch {
+ (MethodParameterValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter,
+ (MethodParameterValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType,
+ (MethodParameterValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField,
+ (MethodParameterValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter,
+ (MethodParameterValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsGenericParameter,
+ (MethodReturnValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter,
+ (MethodReturnValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType,
+ (MethodReturnValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField,
+ (MethodReturnValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter,
+ (MethodReturnValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsGenericParameter,
+ (FieldValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsParameter,
+ (FieldValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType,
+ (FieldValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsField,
+ (FieldValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter,
+ (FieldValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsGenericParameter,
+ (MethodThisParameterValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsParameter,
+ (MethodThisParameterValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType,
+ (MethodThisParameterValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsField,
+ (MethodThisParameterValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter,
+ (MethodThisParameterValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsGenericParameter,
+ (GenericParameterValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter,
+ (GenericParameterValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType,
+ (GenericParameterValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField,
+ (GenericParameterValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter,
+ (GenericParameterValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter,
+ (NullableValueWithDynamicallyAccessedMembers, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter,
+ (NullableValueWithDynamicallyAccessedMembers, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType,
+ (NullableValueWithDynamicallyAccessedMembers, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField,
+ (NullableValueWithDynamicallyAccessedMembers, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter,
+ (NullableValueWithDynamicallyAccessedMembers, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter,
+
+ _ => throw new NotImplementedException ($"Unsupported source context {source} or target context {target}.")
+ };
+
+ var args = new List<string> ();
+ args.AddRange (target.GetDiagnosticArgumentsForAnnotationMismatch ());
+ args.AddRange (source.GetDiagnosticArgumentsForAnnotationMismatch ());
+ args.Add (missingAnnotations);
+ return (diagnosticId, args.ToArray ());
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/DefaultValueDictionary.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/DefaultValueDictionary.cs
new file mode 100644
index 00000000000..679f70ca621
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/DefaultValueDictionary.cs
@@ -0,0 +1,88 @@
+// 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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // This is a dictionary along with a default value, where every possible key either maps to
+ // the default value, or another value. The default value is never explicitly stored in the dictionary,
+ // and the empty dictionary (where all possible keys have the default value) is represented without
+ // actually allocating a dictionary.
+ public struct DefaultValueDictionary<TKey, TValue> : IEquatable<DefaultValueDictionary<TKey, TValue>>,
+ IEnumerable<KeyValuePair<TKey, TValue>>
+ where TKey : IEquatable<TKey>
+ where TValue : IEquatable<TValue>
+ {
+ Dictionary<TKey, TValue>? Dictionary;
+
+ readonly TValue DefaultValue;
+
+ public DefaultValueDictionary (TValue defaultValue) => (Dictionary, DefaultValue) = (null, defaultValue);
+
+ public DefaultValueDictionary (DefaultValueDictionary<TKey, TValue> other)
+ {
+ Dictionary = other.Dictionary == null ? null : new Dictionary<TKey, TValue> (other.Dictionary);
+ DefaultValue = other.DefaultValue;
+ }
+
+ public TValue Get (TKey key) => Dictionary?.TryGetValue (key, out var value) == true ? value : DefaultValue;
+
+ public void Set (TKey key, TValue value)
+ {
+ if (value.Equals (DefaultValue))
+ Dictionary?.Remove (key);
+ else
+ (Dictionary ??= new Dictionary<TKey, TValue> ())[key] = value;
+ }
+
+ public bool Equals (DefaultValueDictionary<TKey, TValue> other)
+ {
+ if (!DefaultValue.Equals (other.DefaultValue))
+ return false;
+
+ if (Dictionary == null)
+ return other.Dictionary == null;
+
+ if (other.Dictionary == null)
+ return false;
+
+ if (Dictionary.Count != other.Dictionary.Count)
+ return false;
+
+ foreach (var kvp in other.Dictionary) {
+ if (!Get (kvp.Key).Equals (kvp.Value))
+ return false;
+ }
+
+ return true;
+ }
+
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()
+ {
+ return Dictionary?.GetEnumerator () ?? Enumerable.Empty<KeyValuePair<TKey, TValue>> ().GetEnumerator ();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new ();
+ sb.Append ("{");
+ if (Dictionary != null) {
+ foreach (var kvp in Dictionary)
+ sb.Append (Environment.NewLine).Append ('\t').Append (kvp.Key.ToString ()).Append (" -> ").Append (kvp.Value.ToString ());
+ }
+ sb.Append (Environment.NewLine).Append ("\t_ -> ").Append (DefaultValue.ToString ());
+ sb.Append (Environment.NewLine).Append ("}");
+ return sb.ToString ();
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/DictionaryLattice.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/DictionaryLattice.cs
new file mode 100644
index 00000000000..77732b28f4c
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/DictionaryLattice.cs
@@ -0,0 +1,38 @@
+// 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;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // A lattice over dictionaries where the stored values are also from a lattice.
+ public readonly struct DictionaryLattice<TKey, TValue, TValueLattice> : ILattice<DefaultValueDictionary<TKey, TValue>>
+ where TKey : IEquatable<TKey>
+ where TValue : IEquatable<TValue>
+ where TValueLattice : ILattice<TValue>
+ {
+ public readonly TValueLattice ValueLattice;
+
+ public DefaultValueDictionary<TKey, TValue> Top { get; }
+
+ public DictionaryLattice (TValueLattice valueLattice)
+ {
+ ValueLattice = valueLattice;
+ Top = new DefaultValueDictionary<TKey, TValue> (valueLattice.Top);
+ }
+
+ public DefaultValueDictionary<TKey, TValue> Meet (DefaultValueDictionary<TKey, TValue> left, DefaultValueDictionary<TKey, TValue> right)
+ {
+ var met = new DefaultValueDictionary<TKey, TValue> (left);
+ foreach (var kvp in right) {
+ TKey key = kvp.Key;
+ TValue rightValue = kvp.Value;
+ met.Set (key, ValueLattice.Meet (left.Get (key), rightValue));
+ }
+ return met;
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ForwardDataFlowAnalysis.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ForwardDataFlowAnalysis.cs
new file mode 100644
index 00000000000..345fbe8680a
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ForwardDataFlowAnalysis.cs
@@ -0,0 +1,356 @@
+// 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;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // A generic implementation of a forward dataflow analysis. Forward means that it flows facts
+ // across code in the order of execution, starting from the beginning of a method,
+ // and merging values from predecessors.
+ public abstract class ForwardDataFlowAnalysis<TValue, TState, TLattice, TBlock, TRegion, TControlFlowGraph, TTransfer>
+ where TValue : struct, IEquatable<TValue>
+ where TState : class, IDataFlowState<TValue, TLattice>, new()
+ where TLattice : ILattice<TValue>
+ where TTransfer : ITransfer<TBlock, TValue, TState, TLattice>
+ where TBlock : IEquatable<TBlock>
+ where TRegion : IRegion<TRegion>
+ where TControlFlowGraph : IControlFlowGraph<TBlock, TRegion>
+ {
+
+ // Data structure to store dataflow states for every basic block in the control flow graph,
+ // keeping the exception states shared across different basic blocks owned by the same try or catch region.
+ struct ControlFlowGraphState
+ {
+ // Dataflow states for each basic block
+ readonly Dictionary<TBlock, TState> blockOutput;
+
+ // The control flow graph doesn't contain edges for exceptional control flow:
+ // - From any point in a try region to the start of any catch or finally
+ // - From any point in a catch region to the start of a finally or the end of a try-catch block
+ // These implicit edges are handled by tracking an auxiliary state for each try and catch region,
+ // which the transfer functions are expected to update (in addition to the normal state updates)
+ // when visiting operations inside of a try or catch region.
+
+ // Dataflow states for exceptions propagating out of try or catch regions
+ readonly Dictionary<TRegion, Box<TValue>> exceptionState;
+
+ // Control may flow through a finally region when an exception is thrown from anywhere in the corresponding
+ // try or catch regions, or as part of non-exceptional control flow out of a try or catch.
+ // We track a separate finally state for the exceptional case. Only the normal (non-exceptional) state is
+ // propagated out of the finally.
+
+ // Dataflow states for finally blocks when exception propagate through the finally region
+ readonly Dictionary<TBlock, TValue> exceptionFinallyState;
+
+ // Finally regions may be reached (along non-exceptional paths)
+ // from multiple branches. This gets updated to track the normal finally input
+ // states from all of these branches (which aren't represented explicitly in the CFG).
+ readonly Dictionary<TRegion, TValue> finallyInputState;
+
+ readonly TControlFlowGraph cfg;
+ readonly TLattice lattice;
+
+ public ControlFlowGraphState (TControlFlowGraph cfg, TLattice lattice)
+ {
+ blockOutput = new ();
+ exceptionState = new ();
+ exceptionFinallyState = new ();
+ finallyInputState = new ();
+ this.cfg = cfg;
+ this.lattice = lattice;
+ }
+
+ public Box<TValue> GetExceptionState (TRegion tryOrCatchOrFilterRegion)
+ {
+ if (tryOrCatchOrFilterRegion.Kind is not (RegionKind.Try or RegionKind.Catch or RegionKind.Filter))
+ throw new ArgumentException (null, nameof (tryOrCatchOrFilterRegion));
+
+ if (!exceptionState.TryGetValue (tryOrCatchOrFilterRegion, out Box<TValue>? state)) {
+ state = new Box<TValue> (lattice.Top);
+ exceptionState.Add (tryOrCatchOrFilterRegion, state);
+ }
+ return state;
+ }
+
+ public bool TryGetExceptionState (TBlock block, out Box<TValue>? state)
+ {
+ state = null;
+ if (!cfg.TryGetEnclosingTryOrCatchOrFilter (block, out TRegion? tryOrCatchOrFilterRegion))
+ return false;
+
+ state = GetExceptionState (tryOrCatchOrFilterRegion);
+ return true;
+ }
+
+ public TValue GetFinallyInputState (TRegion finallyRegion)
+ {
+ if (finallyRegion.Kind is not RegionKind.Finally)
+ throw new ArgumentException (null, nameof (finallyRegion));
+
+ if (!finallyInputState.TryGetValue (finallyRegion, out TValue state)) {
+ state = lattice.Top;
+ finallyInputState.Add (finallyRegion, state);
+ }
+ return state;
+ }
+
+ public void SetFinallyInputState (TRegion finallyRegion, TValue state)
+ {
+ if (finallyRegion.Kind is not RegionKind.Finally)
+ throw new ArgumentException (null, nameof (finallyRegion));
+
+ finallyInputState[finallyRegion] = state;
+ }
+
+ public bool TryGetExceptionFinallyState (TBlock block, out TValue state)
+ {
+ state = default;
+ if (!cfg.TryGetEnclosingFinally (block, out _))
+ return false;
+
+ if (!exceptionFinallyState.TryGetValue (block, out state)) {
+ state = lattice.Top;
+ exceptionFinallyState.Add (block, state);
+ }
+ return true;
+ }
+
+ public void SetExceptionFinallyState (TBlock block, TValue state)
+ {
+ if (!cfg.TryGetEnclosingFinally (block, out _))
+ throw new InvalidOperationException ();
+
+ exceptionFinallyState[block] = state;
+ }
+
+ public TState Get (TBlock block)
+ {
+ if (!blockOutput.TryGetValue (block, out TState? state)) {
+ TryGetExceptionState (block, out Box<TValue>? exceptionState);
+ state = new TState () {
+ Lattice = lattice,
+ Current = lattice.Top,
+ Exception = exceptionState
+ };
+ blockOutput.Add (block, state);
+ }
+ return state;
+ }
+ }
+
+ [Conditional ("DEBUG")]
+ public virtual void TraceStart (TControlFlowGraph cfg) { }
+
+ [Conditional ("DEBUG")]
+ public virtual void TraceVisitBlock (TBlock block) { }
+
+ [Conditional ("DEBUG")]
+ public virtual void TraceBlockInput (TValue normalState, TValue? exceptionState, TValue? exceptionFinallyState) { }
+
+ [Conditional ("DEBUG")]
+ public virtual void TraceBlockOutput (TValue normalState, TValue? exceptionState, TValue? exceptionFinallyState) { }
+
+ // This just runs a dataflow algorithm until convergence. It doesn't cache any results,
+ // allowing each particular kind of analysis to decide what is worth saving.
+ public void Fixpoint (TControlFlowGraph cfg, TLattice lattice, TTransfer transfer)
+ {
+ TraceStart (cfg);
+
+ // Initialize output of each block to the Top value of the lattice
+ var cfgState = new ControlFlowGraphState (cfg, lattice);
+
+ // For now, the actual dataflow algorithm is the simplest possible version.
+ // It is written to be obviously correct, but has not been optimized for performance
+ // at all. As written it will almost always perform unnecessary passes over the entire
+ // control flow graph. The core abstractions shouldn't need to change even when we write
+ // an optimized version of this algorithm - ideally any optimizations will be generic,
+ // not specific to a particular analysis.
+
+ // Allocate some objects which will be reused to hold the current dataflow state,
+ // to avoid allocatons in the inner loop below.
+ var state = new TState () {
+ Lattice = lattice,
+ Current = lattice.Top,
+ Exception = null
+ };
+ var finallyState = new TState () {
+ Lattice = lattice,
+ Current = lattice.Top,
+ Exception = null
+ };
+
+ bool changed = true;
+ while (changed) {
+ changed = false;
+ foreach (var block in cfg.Blocks) {
+
+ TraceVisitBlock (block);
+
+ if (block.Equals (cfg.Entry))
+ continue;
+
+ bool isTryOrCatchOrFilterBlock = cfg.TryGetEnclosingTryOrCatchOrFilter (block, out TRegion? tryOrCatchOrFilterRegion);
+
+ bool isTryBlock = isTryOrCatchOrFilterBlock && tryOrCatchOrFilterRegion!.Kind == RegionKind.Try;
+ bool isTryStart = isTryBlock && block.Equals (cfg.FirstBlock (tryOrCatchOrFilterRegion!));
+ bool isCatchBlock = isTryOrCatchOrFilterBlock && tryOrCatchOrFilterRegion!.Kind == RegionKind.Catch;
+ bool isCatchStartWithoutFilter = isCatchBlock && block.Equals (cfg.FirstBlock (tryOrCatchOrFilterRegion!)) && !cfg.HasFilter (tryOrCatchOrFilterRegion!);
+ bool isFilterBlock = isTryOrCatchOrFilterBlock && tryOrCatchOrFilterRegion!.Kind == RegionKind.Filter;
+ bool isFilterStart = isFilterBlock && block.Equals (cfg.FirstBlock (tryOrCatchOrFilterRegion!));
+
+ bool isCatchOrFilterStart = isCatchStartWithoutFilter || isFilterStart;
+
+ bool isFinallyBlock = cfg.TryGetEnclosingFinally (block, out TRegion? finallyRegion);
+ bool isFinallyStart = isFinallyBlock && block.Equals (cfg.FirstBlock (finallyRegion!));
+
+
+ //
+ // Meet over predecessors to get the new value at the start of this block.
+ //
+
+ // Compute the dataflow state at the beginning of this block.
+ TValue currentState = lattice.Top;
+ foreach (var predecessor in cfg.GetPredecessors (block)) {
+ TValue predecessorState = cfgState.Get (predecessor.Block).Current;
+
+ // Propagate state through all finally blocks.
+ foreach (var exitedFinally in predecessor.FinallyRegions) {
+ TValue oldFinallyInputState = cfgState.GetFinallyInputState (exitedFinally);
+ TValue finallyInputState = lattice.Meet (oldFinallyInputState, predecessorState);
+
+ cfgState.SetFinallyInputState (exitedFinally, finallyInputState);
+
+ // Note: the current approach here is inefficient for long chains of finally regions because
+ // the states will not converge until we have visited each block along the chain
+ // and propagated the new states along this path.
+ if (!changed && !finallyInputState.Equals (oldFinallyInputState))
+ changed = true;
+
+ TBlock lastFinallyBlock = cfg.LastBlock (exitedFinally);
+ predecessorState = cfgState.Get (lastFinallyBlock).Current;
+ }
+
+ currentState = lattice.Meet (currentState, predecessorState);
+ }
+ // State at start of a catch also includes the exceptional state from
+ // try -> catch exceptional control flow.
+ if (isCatchOrFilterStart) {
+ TRegion correspondingTry = cfg.GetCorrespondingTry (tryOrCatchOrFilterRegion!);
+ Box<TValue> tryExceptionState = cfgState.GetExceptionState (correspondingTry);
+ currentState = lattice.Meet (currentState, tryExceptionState.Value);
+
+ // A catch or filter can also be reached from a previous filter.
+ foreach (TRegion previousFilter in cfg.GetPreviousFilters (tryOrCatchOrFilterRegion!)) {
+ // Control may flow from the last block of a previous filter region to this catch or filter region.
+ // Exceptions may also propagate from anywhere in a filter region to this catch or filter region.
+ // This covers both cases since the exceptional state is a superset of the normal state.
+ Box<TValue> previousFilterExceptionState = cfgState.GetExceptionState (previousFilter);
+ currentState = lattice.Meet (currentState, previousFilterExceptionState.Value);
+ }
+ }
+ if (isFinallyStart) {
+ TValue finallyInputState = cfgState.GetFinallyInputState (finallyRegion!);
+ currentState = lattice.Meet (currentState, finallyInputState);
+ }
+
+ // Compute the independent exceptional finally state at beginning of a finally.
+ TValue? exceptionFinallyState = null;
+ if (isFinallyBlock) {
+ // Inside finally regions, must compute the parallel meet state for unhandled exceptions.
+ // Using predecessors in the finally. But not from outside the finally.
+ exceptionFinallyState = lattice.Top;
+ foreach (var predecessor in cfg.GetPredecessors (block)) {
+ var isPredecessorInFinally = cfgState.TryGetExceptionFinallyState (predecessor.Block, out TValue predecessorFinallyState);
+ Debug.Assert (isPredecessorInFinally);
+ exceptionFinallyState = lattice.Meet (exceptionFinallyState.Value, predecessorFinallyState);
+ }
+
+ // For first block, also initialize it from the try or catch blocks.
+ if (isFinallyStart) {
+ // Note that try+catch+finally is represented in the region hierarchy like a
+ // try/finally where the try block contains a try/catch.
+ // So including the corresponding try exception state will also take care of the
+ // corresponding catch exception state.
+ TRegion correspondingTry = cfg.GetCorrespondingTry (finallyRegion!);
+ Box<TValue> tryExceptionState = cfgState.GetExceptionState (correspondingTry);
+ exceptionFinallyState = lattice.Meet (exceptionFinallyState.Value, tryExceptionState.Value);
+ }
+ }
+
+ // Initialize the exception state at the start of try/catch regions. Control flow edges from predecessors
+ // within the same try or catch region don't need to be handled here because the transfer functions update
+ // the exception state to reflect every operation in the region.
+ TState currentBlockState = cfgState.Get (block);
+ Box<TValue>? exceptionState = currentBlockState.Exception;
+ TValue? oldExceptionState = exceptionState?.Value;
+ if (isTryStart || isCatchOrFilterStart) {
+ // Catch/filter regions get the initial state from the exception state of the corresponding try region.
+ // This is already accounted for in the non-exceptional control flow state of the catch block above,
+ // so we can just use the state we already computed, for both try and catch regions.
+ exceptionState!.Value = lattice.Meet (exceptionState!.Value, currentState);
+
+ if (isFinallyBlock) {
+ // Exceptions could also be thrown from inside a finally that was entered due to a previous exception.
+ // So the exception state must also include values from the exceptional finally state (computed above).
+ exceptionState!.Value = lattice.Meet (exceptionState!.Value, exceptionFinallyState!.Value);
+ }
+ }
+
+ TraceBlockInput (currentState, exceptionState?.Value, exceptionFinallyState);
+
+ //
+ // Apply transfer functions to the met input to get an output value for this block.
+ //
+
+ state.Current = currentState;
+ state.Exception = exceptionState;
+ transfer.Transfer (block, state);
+
+ if (!changed && !cfgState.Get (block).Current.Equals (state.Current))
+ changed = true;
+
+ cfgState.Get (block).Current = state.Current;
+ Debug.Assert (cfgState.Get (block).Exception == state.Exception);
+
+ if (cfgState.TryGetExceptionFinallyState (block, out TValue oldFinallyState)) {
+ // Independently apply transfer functions for the exception finally state in finally regions.
+ finallyState.Current = exceptionFinallyState!.Value;
+ finallyState.Exception = exceptionState;
+ transfer.Transfer (block, finallyState);
+
+ if (!changed && !oldFinallyState.Equals (finallyState.Current))
+ changed = true;
+
+ Debug.Assert (cfgState.Get (block).Exception == state.Exception);
+ cfgState.SetExceptionFinallyState (block, finallyState.Current);
+ }
+
+ // Either the normal transfer or the finally transfer might change
+ // the try/catch state, so this check should happen after both transfers.
+ if (exceptionState?.Value.Equals (oldExceptionState!.Value) == false) {
+ Debug.Assert (exceptionState != null);
+ Debug.Assert (oldExceptionState != null);
+ changed = true;
+
+ // Bubble up the changed exception state to the next enclosing try or catch exception state.
+ while (cfg.TryGetEnclosingTryOrCatchOrFilter (tryOrCatchOrFilterRegion!, out TRegion? enclosingTryOrCatch)) {
+ // Filters can't contain try/catch/filters.
+ Debug.Assert (enclosingTryOrCatch.Kind != RegionKind.Filter);
+ Box<TValue> tryOrCatchExceptionState = cfgState.GetExceptionState (enclosingTryOrCatch);
+ tryOrCatchExceptionState.Value = lattice.Meet (tryOrCatchExceptionState!.Value, exceptionState!.Value);
+ tryOrCatchOrFilterRegion = enclosingTryOrCatch;
+ }
+ }
+
+ TraceBlockOutput (state.Current, exceptionState?.Value, exceptionFinallyState);
+ }
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IControlFlowGraph.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IControlFlowGraph.cs
new file mode 100644
index 00000000000..eb1b492aa30
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IControlFlowGraph.cs
@@ -0,0 +1,67 @@
+// 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.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ public enum RegionKind
+ {
+ Try,
+ Catch,
+ Filter,
+ Finally
+ }
+
+ public interface IRegion<TRegion> : IEquatable<TRegion>
+ {
+ RegionKind Kind { get; }
+ }
+
+ public interface IControlFlowGraph<TBlock, TRegion>
+ where TBlock : IEquatable<TBlock>
+ where TRegion : IRegion<TRegion>
+ {
+
+ public readonly struct Predecessor
+ {
+ public readonly TBlock Block;
+ public readonly ImmutableArray<TRegion> FinallyRegions;
+ public Predecessor (TBlock block, ImmutableArray<TRegion> finallyRegions)
+ {
+ (Block, FinallyRegions) = (block, finallyRegions);
+ }
+ }
+
+ IEnumerable<TBlock> Blocks { get; }
+
+ TBlock Entry { get; }
+
+ // This does not include predecessor edges for exceptional control flow into
+ // catch regions or finally regions. It also doesn't include edges for non-exceptional
+ // control flow from try -> finally or from catch -> finally.
+ IEnumerable<Predecessor> GetPredecessors (TBlock block);
+
+ bool TryGetEnclosingTryOrCatchOrFilter (TBlock block, [NotNullWhen (true)] out TRegion? tryOrCatchOrFilterRegion);
+
+ bool TryGetEnclosingTryOrCatchOrFilter (TRegion region, [NotNullWhen (true)] out TRegion? tryOrCatchOrFilterRegion);
+
+ bool TryGetEnclosingFinally (TBlock block, [NotNullWhen (true)] out TRegion? region);
+
+ TRegion GetCorrespondingTry (TRegion cathOrFilterOrFinallyRegion);
+
+ IEnumerable<TRegion> GetPreviousFilters (TRegion catchOrFilterRegion);
+
+ bool HasFilter (TRegion catchRegion);
+
+ TBlock FirstBlock (TRegion region);
+
+ TBlock LastBlock (TRegion region);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDataFlowState.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDataFlowState.cs
new file mode 100644
index 00000000000..26f056be835
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDataFlowState.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;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ public sealed class Box<T> where T : struct
+ {
+ public Box (T value) => Value = value;
+ public T Value { get; set; }
+
+ }
+
+ public interface IDataFlowState<TValue, TValueLattice>
+ where TValue : struct, IEquatable<TValue>
+ where TValueLattice : ILattice<TValue>
+ {
+ TValue Current { get; set; }
+ Box<TValue>? Exception { get; set; }
+ TValueLattice Lattice { get; init; }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDeepCopyValue.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDeepCopyValue.cs
new file mode 100644
index 00000000000..da127809495
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/IDeepCopyValue.cs
@@ -0,0 +1,14 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // Adds ability to deep copy a value
+ public interface IDeepCopyValue<TSingleValue>
+ {
+ public TSingleValue DeepCopy ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ILattice.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ILattice.cs
new file mode 100644
index 00000000000..07f31c4e5ed
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ILattice.cs
@@ -0,0 +1,42 @@
+// 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;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // ILattice represents a lattice (technically a semilattice) of values.
+ // A semilattice is a set of values along with a meet operation (or greatest lower bound).
+ // The meet operation imposes a partial order on the values: a <= b iff Meet(a, b) == a.
+
+ // In a dataflow analysis, the Meet operation is used to combine the tracked facts when
+ // there are multiple control flow paths that reach the same program point (or in a backwards
+ // analysis, to combine the tracked facts from multiple control flow paths out of a program point).
+
+ // The interface constraint on TValue ensures that trying to instantiate
+ // ILattice over a nullable type will produce a warning or error.
+
+ // The lattice might be better represented as an interface describing individual lattice values
+ // (as opposed to describing the lattice structure as ILattice does), with Top being a static
+ // virtual interface method. This would avoid the need to pass around multiple generic arguments
+ // (TValue and TLattice). However, we can't use static virtual interface methods in the analyzer
+ // so the lattice instance provides the Top value.
+ public interface ILattice<TValue> where TValue : IEquatable<TValue>
+ {
+ // We require that the lattice has a "Top" or maximum element.
+ // Top is >= a for every element a of the lattice.
+ // Top is an identity for Meet: Meet(a, Top) = a.
+
+ // The typical use in a dataflow analysis is for Top to represent the "unknown" initial state
+ // with the least possible information about the analysis.
+ public TValue Top { get; }
+
+ // The Meet operation is associative, commutative, and idempotent.
+ // This is used in dataflow analysis to iteratively Meet the tracked facts from different control
+ // flow paths until the analysis converges to the most specific set of tracked facts.
+ public TValue Meet (TValue left, TValue right);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ITransfer.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ITransfer.cs
new file mode 100644
index 00000000000..74c35c8613d
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ITransfer.cs
@@ -0,0 +1,38 @@
+// 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;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // ITransfer represents the transfer functions for a dataflow analysis.
+ // The transfer functions compute the effects of an operation on the set of facts
+ // tracked by a dataflow analysis. This simulates the execution of the operation
+ // on the domain of abstract values tracked in the dataflow analysis.
+
+ // TValue is the type of the information tracked in a dataflow analysis at each program point.
+ // TLattice is the type of the lattice formed by these values.
+
+ // TOperation is a type representing the operations that the transfer function
+ // "simulates". It isn't constrained by the interface, but is typically a basic block,
+ // where the transfer functions are defined in terms of transfer functions for individual
+ // operations in the block.
+
+ // TLattice isn't typically used in the implementation except to provide the "Top" value.
+ // This expresses the conceptual constraint that the transferred values are part of a lattice.
+ public interface ITransfer<TOperation, TValue, TState, TLattice>
+ where TValue : struct, IEquatable<TValue>
+ where TState : class, IDataFlowState<TValue, TLattice>
+ where TLattice : ILattice<TValue>
+ {
+ // Transfer should mutate the input value to reflect the effect of
+ // computing this operation. When using value types, ensure that
+ // any modifications to the values are observable by the caller (consider
+ // using readonly structs to prevent the implementation from making changes
+ // that won't be reflected in the caller).
+ void Transfer (TOperation operation, TState state);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/SingleValue.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/SingleValue.cs
new file mode 100644
index 00000000000..79963757b93
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/SingleValue.cs
@@ -0,0 +1,24 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // This is a sum type over the various kinds of values we track:
+ // - dynamicallyaccessedmembertypes-annotated locations (types or strings)
+ // - known typeof values and similar
+ // - known strings
+ // - known integers
+
+ public abstract record SingleValue : IDeepCopyValue<SingleValue>
+ {
+ // All values must explicitely declare their ability to deep copy itself.
+ // If the value is immutable, it can "return this" as an optimization.
+ // Note: Since immutability is relatively tricky to determine, we require all values
+ // to explicitly implement the DeepCopy, even though the expectation is that
+ // most values will just "return this".
+ public abstract SingleValue DeepCopy ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSet.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSet.cs
new file mode 100644
index 00000000000..120e9116eaf
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSet.cs
@@ -0,0 +1,193 @@
+// 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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ public readonly struct ValueSet<TValue> : IEquatable<ValueSet<TValue>>, IEnumerable<TValue>
+ where TValue : notnull
+ {
+ // Since we're going to do lot of type checks for this class a lot, it is much more efficient
+ // if the class is sealed (as then the runtime can do a simple method table pointer comparison)
+ sealed class EnumerableValues : HashSet<TValue>
+ {
+ public EnumerableValues (IEnumerable<TValue> values) : base (values) { }
+
+ public override int GetHashCode ()
+ {
+ int hashCode = 0;
+ foreach (var item in this)
+ hashCode = HashUtils.Combine (hashCode, item);
+ return hashCode;
+ }
+ }
+
+ public struct Enumerator : IEnumerator<TValue>, IDisposable, IEnumerator
+ {
+ readonly object? _value;
+ int _state; // 0 before begining, 1 at item, 2 after end
+ readonly IEnumerator<TValue>? _enumerator;
+
+ internal Enumerator (object? values)
+ {
+ _state = 0;
+ if (values is EnumerableValues valuesSet) {
+ _enumerator = valuesSet.GetEnumerator ();
+ _value = null;
+ } else {
+ _enumerator = null;
+ _value = values;
+ }
+ }
+
+ public TValue Current => _enumerator is not null
+ ? _enumerator.Current
+ : (_state == 1 ? (TValue) _value! : default!);
+
+ object? IEnumerator.Current => Current;
+
+ public void Dispose ()
+ {
+ }
+
+ public bool MoveNext ()
+ {
+ if (_enumerator is not null)
+ return _enumerator.MoveNext ();
+
+ if (_value is null)
+ return false;
+
+ if (_state > 1)
+ return false;
+
+ _state++;
+ return _state == 1;
+ }
+
+ public void Reset ()
+ {
+ if (_enumerator is not null)
+ _enumerator.Reset ();
+ else
+ _state = 0;
+ }
+ }
+
+ // This stores the values. By far the most common case will be either no values, or a single value.
+ // Cases where there are multiple values stored are relatively very rare.
+ // null - no values (empty set)
+ // TValue - single value itself
+ // EnumerableValues typed object - multiple values, stored in the hashset
+ readonly object? _values;
+
+ public ValueSet (TValue value) => _values = value;
+
+ public ValueSet (IEnumerable<TValue> values) => _values = new EnumerableValues (values);
+
+ ValueSet (EnumerableValues values) => _values = values;
+
+ public static implicit operator ValueSet<TValue> (TValue value) => new (value);
+
+ public override bool Equals (object? obj) => obj is ValueSet<TValue> other && Equals (other);
+
+ public bool Equals (ValueSet<TValue> other)
+ {
+ if (_values == null)
+ return other._values == null;
+ if (other._values == null)
+ return false;
+
+ if (_values is EnumerableValues enumerableValues) {
+ if (other._values is EnumerableValues otherValuesSet) {
+ return enumerableValues.SetEquals (otherValuesSet);
+ } else
+ return false;
+ } else {
+ if (other._values is EnumerableValues) {
+ return false;
+ }
+
+ return EqualityComparer<TValue>.Default.Equals ((TValue) _values, (TValue) other._values);
+ }
+ }
+
+ public override int GetHashCode ()
+ {
+ if (_values == null)
+ return typeof (ValueSet<TValue>).GetHashCode ();
+
+ if (_values is EnumerableValues enumerableValues)
+ return enumerableValues.GetHashCode ();
+
+ return _values.GetHashCode ();
+ }
+
+ public Enumerator GetEnumerator () => new (_values);
+
+ IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator () => GetEnumerator ();
+
+ IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
+
+ public bool Contains (TValue value) => _values is null
+ ? false
+ : _values is EnumerableValues valuesSet
+ ? valuesSet.Contains (value)
+ : EqualityComparer<TValue>.Default.Equals (value, (TValue) _values);
+
+ internal static ValueSet<TValue> Meet (ValueSet<TValue> left, ValueSet<TValue> right)
+ {
+ if (left._values == null)
+ return right.Clone ();
+ if (right._values == null)
+ return left.Clone ();
+
+ if (left._values is not EnumerableValues && right.Contains ((TValue) left._values))
+ return right.Clone ();
+
+ if (right._values is not EnumerableValues && left.Contains ((TValue) right._values))
+ return left.Clone ();
+
+ var values = new EnumerableValues (left.Clone ());
+ values.UnionWith (right.Clone ());
+ return new ValueSet<TValue> (values);
+ }
+
+ public bool IsEmpty () => _values == null;
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new ();
+ sb.Append ("{");
+ sb.Append (string.Join (",", this.Select (v => v.ToString ())));
+ sb.Append ("}");
+ return sb.ToString ();
+ }
+
+ // Meet should copy the values, but most SingleValues are immutable.
+ // Clone returns `this` if there are no mutable SingleValues (SingleValues that implement IDeepCopyValue), otherwise creates a new ValueSet with copies of the copiable Values
+ public ValueSet<TValue> Clone ()
+ {
+ if (_values is null)
+ return this;
+
+ // Optimize for the most common case with only a single value
+ if (_values is not EnumerableValues) {
+ if (_values is IDeepCopyValue<TValue> copyValue)
+ return new ValueSet<TValue> (copyValue.DeepCopy ());
+ else
+ return this;
+ }
+
+ return new ValueSet<TValue> (this.Select (value => value is IDeepCopyValue<TValue> copyValue ? copyValue.DeepCopy () : value));
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSetLattice.cs b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSetLattice.cs
new file mode 100644
index 00000000000..1acca955ce0
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/DataFlow/ValueSetLattice.cs
@@ -0,0 +1,19 @@
+// 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;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.DataFlow
+{
+ // A lattice over ValueSets where the Meet operation is just set union.
+ public readonly struct ValueSetLattice<TValue> : ILattice<ValueSet<TValue>>
+ where TValue : IEquatable<TValue>
+ {
+ public ValueSet<TValue> Top => default;
+
+ public ValueSet<TValue> Meet (ValueSet<TValue> left, ValueSet<TValue> right) => ValueSet<TValue>.Meet (left, right);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticCategory.cs b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticCategory.cs
index 427c7fabf8f..a1d1e116f77 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticCategory.cs
+++ b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticCategory.cs
@@ -1,12 +1,15 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
namespace ILLink.Shared
{
- internal static class DiagnosticCategory
- {
- public const string SingleFile = nameof(SingleFile);
- public const string Trimming = nameof(Trimming);
- public const string AOT = nameof(AOT);
- }
+ internal static class DiagnosticCategory
+ {
+ public const string SingleFile = nameof (SingleFile);
+ public const string Trimming = nameof (Trimming);
+ public const string AOT = nameof (AOT);
+ }
}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs
index e22574dbd33..ac417f4ee58 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs
+++ b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs
@@ -1,218 +1,224 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
namespace ILLink.Shared
{
- public enum DiagnosticId
- {
- // Linker error ids.
- XmlFeatureDoesNotSpecifyFeatureValue = 1001,
- XmlUnsupportedNonBooleanValueForFeature = 1002,
- XmlException = 1003,
- _unused_FailedToProcessDescriptorFile = 1004,
- CouldNotFindMethodInAssembly = 1005,
- CannotStubConstructorWhenBaseTypeDoesNotHaveConstructor = 1006,
- CouldNotFindType = 1007,
- CouldNotFindConstructor = 1008,
- CouldNotFindAssemblyReference = 1009,
- CouldNotLoadAssembly = 1010,
- FailedToWriteOutput = 1011,
- LinkerUnexpectedError = 1012,
- ErrorProcessingXmlLocation = 1013,
- XmlDocumentLocationHasInvalidFeatureDefault = 1014,
- UnrecognizedCommandLineOption = 1015,
- InvalidWarningVersion = 1016,
- InvalidGenerateWarningSuppressionsValue = 1017,
- MissingArgumentForCommanLineOptionName = 1018,
- CustomDataFormatIsInvalid = 1019,
- NoFilesToLinkSpecified = 1020,
- NewMvidAndDeterministicCannotBeUsedAtSameTime = 1021,
- AssemblyInCustomStepOptionCouldNotBeFound = 1022,
- AssemblyPathInCustomStepMustBeFullyQualified = 1023,
- InvalidArgForCustomStep = 1024,
- ExpectedSignToControlNewStepInsertion = 1025,
- PipelineStepCouldNotBeFound = 1026,
- CustomStepTypeCouldNotBeFound = 1027,
- CustomStepTypeIsIncompatibleWithLinkerVersion = 1028,
- InvalidOptimizationValue = 1029,
- InvalidArgumentForTokenOption = 1030,
- InvalidAssemblyAction = 1031,
- RootAssemblyCouldNotBeFound = 1032,
- XmlDescriptorCouldNotBeFound = 1033,
- RootAssemblyDoesNotHaveEntryPoint = 1034,
- RootAssemblyCannotUseAction = 1035,
- InvalidAssemblyName = 1036,
- InvalidAssemblyRootMode = 1037,
- ExportedTypeCannotBeResolved = 1038,
- ReferenceAssemblyCouldNotBeLoaded = 1039,
- FailedToResolveMetadataElement = 1040,
- TypeUsedWithAttributeValueCouldNotBeFound = 1041,
- CannotConverValueToType = 1042,
- CustomAttributeArgumentForTypeRequiresNestedNode = 1043,
- CouldNotResolveCustomAttributeTypeValue = 1044,
- UnexpectedAttributeArgumentType = 1045,
- InvalidMetadataOption = 1046,
+ public enum DiagnosticId
+ {
+ // Linker error ids.
+ XmlFeatureDoesNotSpecifyFeatureValue = 1001,
+ XmlUnsupportedNonBooleanValueForFeature = 1002,
+ XmlException = 1003,
+ _unused_FailedToProcessDescriptorFile = 1004,
+ CouldNotFindMethodInAssembly = 1005,
+ CannotStubConstructorWhenBaseTypeDoesNotHaveConstructor = 1006,
+ CouldNotFindType = 1007,
+ CouldNotFindConstructor = 1008,
+ CouldNotFindAssemblyReference = 1009,
+ CouldNotLoadAssembly = 1010,
+ FailedToWriteOutput = 1011,
+ LinkerUnexpectedError = 1012,
+ ErrorProcessingXmlLocation = 1013,
+ XmlDocumentLocationHasInvalidFeatureDefault = 1014,
+ UnrecognizedCommandLineOption = 1015,
+ InvalidWarningVersion = 1016,
+ InvalidGenerateWarningSuppressionsValue = 1017,
+ MissingArgumentForCommanLineOptionName = 1018,
+ CustomDataFormatIsInvalid = 1019,
+ NoFilesToLinkSpecified = 1020,
+ NewMvidAndDeterministicCannotBeUsedAtSameTime = 1021,
+ AssemblyInCustomStepOptionCouldNotBeFound = 1022,
+ AssemblyPathInCustomStepMustBeFullyQualified = 1023,
+ InvalidArgForCustomStep = 1024,
+ ExpectedSignToControlNewStepInsertion = 1025,
+ PipelineStepCouldNotBeFound = 1026,
+ CustomStepTypeCouldNotBeFound = 1027,
+ CustomStepTypeIsIncompatibleWithLinkerVersion = 1028,
+ InvalidOptimizationValue = 1029,
+ InvalidArgumentForTokenOption = 1030,
+ InvalidAssemblyAction = 1031,
+ RootAssemblyCouldNotBeFound = 1032,
+ XmlDescriptorCouldNotBeFound = 1033,
+ RootAssemblyDoesNotHaveEntryPoint = 1034,
+ RootAssemblyCannotUseAction = 1035,
+ InvalidAssemblyName = 1036,
+ InvalidAssemblyRootMode = 1037,
+ ExportedTypeCannotBeResolved = 1038,
+ ReferenceAssemblyCouldNotBeLoaded = 1039,
+ FailedToResolveMetadataElement = 1040,
+ TypeUsedWithAttributeValueCouldNotBeFound = 1041,
+ CannotConverValueToType = 1042,
+ CustomAttributeArgumentForTypeRequiresNestedNode = 1043,
+ CouldNotResolveCustomAttributeTypeValue = 1044,
+ UnexpectedAttributeArgumentType = 1045,
+ InvalidMetadataOption = 1046,
+
+ // Linker diagnostic ids.
+ TypeHasNoFieldsToPreserve = 2001,
+ TypeHasNoMethodsToPreserve = 2002,
+ CouldNotResolveDependencyAssembly = 2003,
+ CouldNotResolveDependencyType = 2004,
+ CouldNotResolveDependencyMember = 2005,
+ _unused_UnrecognizedReflectionPattern = 2006,
+ XmlCouldNotResolveAssembly = 2007,
+ XmlCouldNotResolveType = 2008,
+ XmlCouldNotFindMethodOnType = 2009,
+ XmlInvalidValueForStub = 2010,
+ XmlUnkownBodyModification = 2011,
+ XmlCouldNotFindFieldOnType = 2012,
+ XmlSubstitutedFieldNeedsToBeStatic = 2013,
+ XmlMissingSubstitutionValueForField = 2014,
+ XmlInvalidSubstitutionValueForField = 2015,
+ XmlCouldNotFindEventOnType = 2016,
+ XmlCouldNotFindPropertyOnType = 2017,
+ XmlCouldNotFindGetAccesorOfPropertyOnType = 2018,
+ XmlCouldNotFindSetAccesorOfPropertyOnType = 2019,
+ _unused_RearrangedXmlWarning1 = 2020,
+ _unused_RearrangedXmlWarning2 = 2021,
+ XmlCouldNotFindMatchingConstructorForCustomAttribute = 2022,
+ XmlMoreThanOneReturnElementForMethod = 2023,
+ XmlMoreThanOneValyForParameterOfMethod = 2024,
+ XmlDuplicatePreserveMember = 2025,
+ RequiresUnreferencedCode = 2026,
+ AttributeShouldOnlyBeUsedOnceOnMember = 2027,
+ AttributeDoesntHaveTheRequiredNumberOfParameters = 2028,
+ XmlElementDoesNotContainRequiredAttributeFullname = 2029,
+ XmlCouldNotResolveAssemblyForAttribute = 2030,
+ XmlAttributeTypeCouldNotBeFound = 2031,
+ UnrecognizedParameterInMethodCreateInstance = 2032,
+ DeprecatedPreserveDependencyAttribute = 2033,
+ DynamicDependencyAttributeCouldNotBeAnalyzed = 2034,
+ UnresolvedAssemblyInDynamicDependencyAttribute = 2035,
+ UnresolvedTypeInDynamicDependencyAttribute = 2036,
+ NoMembersResolvedForMemberSignatureOrType = 2037,
+ XmlMissingNameAttributeInResource = 2038,
+ XmlInvalidValueForAttributeActionForResource = 2039,
+ XmlCouldNotFindResourceToRemoveInAssembly = 2040,
+ DynamicallyAccessedMembersIsNotAllowedOnMethods = 2041,
+ DynamicallyAccessedMembersCouldNotFindBackingField = 2042,
+ DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor = 2043,
+ XmlCouldNotFindAnyTypeInNamespace = 2044,
+ AttributeIsReferencedButTrimmerRemoveAllInstances = 2045,
+ RequiresUnreferencedCodeAttributeMismatch = 2046,
+ _unused_DynamicallyAccessedMembersMismatchBetweenOverrides = 2047,
+ XmlRemoveAttributeInstancesCanOnlyBeUsedOnType = 2048,
+ UnrecognizedInternalAttribute = 2049,
+ CorrectnessOfCOMCannotBeGuaranteed = 2050,
+ XmlPropertyDoesNotContainAttributeName = 2051,
+ XmlCouldNotFindProperty = 2052,
+ _unused_XmlInvalidPropertyValueForProperty = 2053,
+ _unused_XmlInvalidArgumentForParameterOfType = 2054,
+ MakeGenericType = 2055,
+ DynamicallyAccessedMembersOnPropertyConflictsWithBackingField = 2056,
+ UnrecognizedTypeNameInTypeGetType = 2057,
+ ParametersOfAssemblyCreateInstanceCannotBeAnalyzed = 2058,
+ UnrecognizedTypeInRuntimeHelpersRunClassConstructor = 2059,
+ MakeGenericMethod = 2060,
+ UnresolvedAssemblyInCreateInstance = 2061,
- // Linker diagnostic ids.
- TypeHasNoFieldsToPreserve = 2001,
- TypeHasNoMethodsToPreserve = 2002,
- CouldNotResolveDependencyAssembly = 2003,
- CouldNotResolveDependencyType = 2004,
- CouldNotResolveDependencyMember = 2005,
- _unused_UnrecognizedReflectionPattern = 2006,
- XmlCouldNotResolveAssembly = 2007,
- XmlCouldNotResolveType = 2008,
- XmlCouldNotFindMethodOnType = 2009,
- XmlInvalidValueForStub = 2010,
- XmlUnkownBodyModification = 2011,
- XmlCouldNotFindFieldOnType = 2012,
- XmlSubstitutedFieldNeedsToBeStatic = 2013,
- XmlMissingSubstitutionValueForField = 2014,
- XmlInvalidSubstitutionValueForField = 2015,
- XmlCouldNotFindEventOnType = 2016,
- XmlCouldNotFindPropertyOnType = 2017,
- XmlCouldNotFindGetAccesorOfPropertyOnType = 2018,
- XmlCouldNotFindSetAccesorOfPropertyOnType = 2019,
- _unused_RearrangedXmlWarning1 = 2020,
- _unused_RearrangedXmlWarning2 = 2021,
- XmlCouldNotFindMatchingConstructorForCustomAttribute = 2022,
- XmlMoreThanOneReturnElementForMethod = 2023,
- XmlMoreThanOneValueForParameterOfMethod = 2024,
- XmlDuplicatePreserveMember = 2025,
- RequiresUnreferencedCode = 2026,
- AttributeShouldOnlyBeUsedOnceOnMember = 2027,
- AttributeDoesntHaveTheRequiredNumberOfParameters = 2028,
- XmlElementDoesNotContainRequiredAttributeFullname = 2029,
- XmlCouldNotResolveAssemblyForAttribute = 2030,
- XmlAttributeTypeCouldNotBeFound = 2031,
- UnrecognizedParameterInMethodCreateInstance = 2032,
- DeprecatedPreserveDependencyAttribute = 2033,
- DynamicDependencyAttributeCouldNotBeAnalyzed = 2034,
- UnresolvedAssemblyInDynamicDependencyAttribute = 2035,
- UnresolvedTypeInDynamicDependencyAttribute = 2036,
- NoMembersResolvedForMemberSignatureOrType = 2037,
- XmlMissingNameAttributeInResource = 2038,
- XmlInvalidValueForAttributeActionForResource = 2039,
- XmlCouldNotFindResourceToRemoveInAssembly = 2040,
- DynamicallyAccessedMembersIsNotAllowedOnMethods = 2041,
- DynamicallyAccessedMembersCouldNotFindBackingField = 2042,
- DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor = 2043,
- XmlCouldNotFindAnyTypeInNamespace = 2044,
- AttributeIsReferencedButTrimmerRemoveAllInstances = 2045,
- RequiresUnreferencedCodeAttributeMismatch = 2046,
- _unused_DynamicallyAccessedMembersMismatchBetweenOverrides = 2047,
- XmlRemoveAttributeInstancesCanOnlyBeUsedOnType = 2048,
- _unused_UnrecognizedInternalAttribute = 2049,
- CorrectnessOfCOMCannotBeGuaranteed = 2050,
- XmlPropertyDoesNotContainAttributeName = 2051,
- XmlCouldNotFindProperty = 2052,
- _unused_XmlInvalidPropertyValueForProperty = 2053,
- _unused_XmlInvalidArgumentForParameterOfType = 2054,
- MakeGenericType = 2055,
- DynamicallyAccessedMembersOnPropertyConflictsWithBackingField = 2056,
- UnrecognizedTypeNameInTypeGetType = 2057,
- ParametersOfAssemblyCreateInstanceCannotBeAnalyzed = 2058,
- UnrecognizedTypeInRuntimeHelpersRunClassConstructor = 2059,
- MakeGenericMethod = 2060,
- UnresolvedAssemblyInCreateInstance = 2061,
- MethodParameterCannotBeStaticallyDetermined = 2062,
- MethodReturnValueCannotBeStaticallyDetermined = 2063,
- FieldValueCannotBeStaticallyDetermined = 2064,
- ImplicitThisCannotBeStaticallyDetermined = 2065,
- TypePassedToGenericParameterCannotBeStaticallyDetermined = 2066,
+ // Unknown value used in a place which requires annotation
+ MethodParameterCannotBeStaticallyDetermined = 2062,
+ MethodReturnValueCannotBeStaticallyDetermined = 2063,
+ FieldValueCannotBeStaticallyDetermined = 2064,
+ ImplicitThisCannotBeStaticallyDetermined = 2065,
+ TypePassedToGenericParameterCannotBeStaticallyDetermined = 2066,
- // Dynamically Accessed Members attribute mismatch.
- DynamicallyAccessedMembersMismatchParameterTargetsParameter = 2067,
- DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType = 2068,
- DynamicallyAccessedMembersMismatchParameterTargetsField = 2069,
- DynamicallyAccessedMembersMismatchParameterTargetsThisParameter = 2070,
- DynamicallyAccessedMembersMismatchParameterTargetsGenericParameter = 2071,
- DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter = 2072,
- DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType = 2073,
- DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField = 2074,
- DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter = 2075,
- DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsGenericParameter = 2076,
- DynamicallyAccessedMembersMismatchFieldTargetsParameter = 2077,
- DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType = 2078,
- DynamicallyAccessedMembersMismatchFieldTargetsField = 2079,
- DynamicallyAccessedMembersMismatchFieldTargetsThisParameter = 2080,
- DynamicallyAccessedMembersMismatchFieldTargetsGenericParameter = 2081,
- DynamicallyAccessedMembersMismatchThisParameterTargetsParameter = 2082,
- DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType = 2083,
- DynamicallyAccessedMembersMismatchThisParameterTargetsField = 2084,
- DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter = 2085,
- DynamicallyAccessedMembersMismatchThisParameterTargetsGenericParameter = 2086,
- DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter = 2087,
- DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType = 2088,
- DynamicallyAccessedMembersMismatchTypeArgumentTargetsField = 2089,
- DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter = 2090,
- DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter = 2091,
- DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides = 2092,
- DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides = 2093,
- DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides = 2094,
- DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides = 2095,
+ // Dynamically Accessed Members attribute mismatch.
+ DynamicallyAccessedMembersMismatchParameterTargetsParameter = 2067,
+ DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType = 2068,
+ DynamicallyAccessedMembersMismatchParameterTargetsField = 2069,
+ DynamicallyAccessedMembersMismatchParameterTargetsThisParameter = 2070,
+ DynamicallyAccessedMembersMismatchParameterTargetsGenericParameter = 2071,
+ DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter = 2072,
+ DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType = 2073,
+ DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField = 2074,
+ DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter = 2075,
+ DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsGenericParameter = 2076,
+ DynamicallyAccessedMembersMismatchFieldTargetsParameter = 2077,
+ DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType = 2078,
+ DynamicallyAccessedMembersMismatchFieldTargetsField = 2079,
+ DynamicallyAccessedMembersMismatchFieldTargetsThisParameter = 2080,
+ DynamicallyAccessedMembersMismatchFieldTargetsGenericParameter = 2081,
+ DynamicallyAccessedMembersMismatchThisParameterTargetsParameter = 2082,
+ DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType = 2083,
+ DynamicallyAccessedMembersMismatchThisParameterTargetsField = 2084,
+ DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter = 2085,
+ DynamicallyAccessedMembersMismatchThisParameterTargetsGenericParameter = 2086,
+ DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter = 2087,
+ DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType = 2088,
+ DynamicallyAccessedMembersMismatchTypeArgumentTargetsField = 2089,
+ DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter = 2090,
+ DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter = 2091,
+ DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides = 2092,
+ DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides = 2093,
+ DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides = 2094,
+ DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides = 2095,
- CaseInsensitiveTypeGetTypeCallIsNotSupported = 2096,
- DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings = 2097,
- DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings = 2098,
- DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings = 2099,
- XmlUnsuportedWildcard = 2100,
- AssemblyWithEmbeddedXmlApplyToAnotherAssembly = 2101,
- InvalidIsTrimmableValue = 2102,
- PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined = 2103,
- AssemblyProducedTrimWarnings = 2104,
- TypeWasNotFoundInAssemblyNorBaseLibrary = 2105,
- DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings = 2106,
- MethodsAreAssociatedWithStateMachine = 2107,
- InvalidScopeInUnconditionalSuppressMessage = 2108,
- RequiresUnreferencedCodeOnBaseClass = 2109,
- DynamicallyAccessedMembersFieldAccessedViaReflection = 2110,
- DynamicallyAccessedMembersMethodAccessedViaReflection = 2111,
- DynamicallyAccessedMembersOnTypeReferencesMemberWithRequiresUnreferencedCode = 2112,
- DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode = 2113,
- DynamicallyAccessedMembersOnTypeReferencesMemberWithDynamicallyAccessedMembers = 2114,
- DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers = 2115,
- RequiresUnreferencedCodeOnStaticConstructor = 2116,
+ CaseInsensitiveTypeGetTypeCallIsNotSupported = 2096,
+ DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings = 2097,
+ DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings = 2098,
+ DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings = 2099,
+ XmlUnsuportedWildcard = 2100,
+ AssemblyWithEmbeddedXmlApplyToAnotherAssembly = 2101,
+ InvalidIsTrimmableValue = 2102,
+ PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined = 2103,
+ AssemblyProducedTrimWarnings = 2104,
+ TypeWasNotFoundInAssemblyNorBaseLibrary = 2105,
+ DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings = 2106,
+ MethodsAreAssociatedWithStateMachine = 2107,
+ InvalidScopeInUnconditionalSuppressMessage = 2108,
+ RequiresUnreferencedCodeOnBaseClass = 2109,
+ DynamicallyAccessedMembersFieldAccessedViaReflection = 2110,
+ DynamicallyAccessedMembersMethodAccessedViaReflection = 2111,
+ DynamicallyAccessedMembersOnTypeReferencesMemberWithRequiresUnreferencedCode = 2112,
+ DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode = 2113,
+ DynamicallyAccessedMembersOnTypeReferencesMemberWithDynamicallyAccessedMembers = 2114,
+ DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers = 2115,
+ RequiresUnreferencedCodeOnStaticConstructor = 2116,
+ MethodsAreAssociatedWithUserMethod = 2117,
- // Single-file diagnostic ids.
- AvoidAssemblyLocationInSingleFile = 3000,
- AvoidAssemblyGetFilesInSingleFile = 3001,
- RequiresAssemblyFiles = 3002,
- RequiresAssemblyFilesAttributeMismatch = 3003,
+ // Single-file diagnostic ids.
+ AvoidAssemblyLocationInSingleFile = 3000,
+ AvoidAssemblyGetFilesInSingleFile = 3001,
+ RequiresAssemblyFiles = 3002,
+ RequiresAssemblyFilesAttributeMismatch = 3003,
+ RequiresAssemblyFilesOnStaticConstructor = 3004,
- // Dynamic code diagnostic ids.
- RequiresDynamicCode = 3050,
- RequiresDynamicCodeAttributeMismatch = 3051,
- COMInteropNotSupportedInFullAOT = 3052,
- AssemblyProducedAOTWarnings = 3053,
- GenericRecursionCycle = 3054,
- CorrectnessOfAbstractDelegatesCannotBeGuaranteed = 3055,
- RequiresDynamicCodeOnStaticConstructor = 3056,
- }
+ // Dynamic code diagnostic ids.
+ RequiresDynamicCode = 3050,
+ RequiresDynamicCodeAttributeMismatch = 3051,
+ COMInteropNotSupportedInFullAOT = 3052,
+ AssemblyProducedAOTWarnings = 3053,
+ GenericRecursionCycle = 3054,
+ CorrectnessOfAbstractDelegatesCannotBeGuaranteed = 3055,
+ RequiresDynamicCodeOnStaticConstructor = 3056,
+ }
- public static class DiagnosticIdExtensions
- {
- public static string AsString(this DiagnosticId diagnosticId) => $"IL{(int)diagnosticId}";
+ public static class DiagnosticIdExtensions
+ {
+ public static string AsString (this DiagnosticId diagnosticId) => $"IL{(int) diagnosticId}";
- public static string GetDiagnosticSubcategory(this DiagnosticId diagnosticId) =>
- (int)diagnosticId switch
- {
- 2026 => MessageSubCategory.TrimAnalysis,
- 2032 => MessageSubCategory.TrimAnalysis,
- 2041 => MessageSubCategory.TrimAnalysis,
- 2042 => MessageSubCategory.TrimAnalysis,
- 2043 => MessageSubCategory.TrimAnalysis,
- 2045 => MessageSubCategory.TrimAnalysis,
- 2046 => MessageSubCategory.TrimAnalysis,
- 2050 => MessageSubCategory.TrimAnalysis,
- >= 2055 and <= 2099 => MessageSubCategory.TrimAnalysis,
- 2103 => MessageSubCategory.TrimAnalysis,
- 2106 => MessageSubCategory.TrimAnalysis,
- 2107 => MessageSubCategory.TrimAnalysis,
- >= 2109 and <= 2116 => MessageSubCategory.TrimAnalysis,
- >= 3050 and <= 3052 => MessageSubCategory.AotAnalysis,
- >= 3054 and <= 3055 => MessageSubCategory.AotAnalysis,
- _ => MessageSubCategory.None,
- };
- }
+ public static string GetDiagnosticSubcategory (this DiagnosticId diagnosticId) =>
+ (int) diagnosticId switch {
+ 2026 => MessageSubCategory.TrimAnalysis,
+ 2032 => MessageSubCategory.TrimAnalysis,
+ 2041 => MessageSubCategory.TrimAnalysis,
+ 2042 => MessageSubCategory.TrimAnalysis,
+ 2043 => MessageSubCategory.TrimAnalysis,
+ 2045 => MessageSubCategory.TrimAnalysis,
+ 2046 => MessageSubCategory.TrimAnalysis,
+ 2050 => MessageSubCategory.TrimAnalysis,
+ >= 2055 and <= 2099 => MessageSubCategory.TrimAnalysis,
+ 2103 => MessageSubCategory.TrimAnalysis,
+ 2106 => MessageSubCategory.TrimAnalysis,
+ 2107 => MessageSubCategory.TrimAnalysis,
+ >= 2109 and <= 2116 => MessageSubCategory.TrimAnalysis,
+ >= 3050 and <= 3052 => MessageSubCategory.AotAnalysis,
+ >= 3054 and <= 3055 => MessageSubCategory.AotAnalysis,
+ _ => MessageSubCategory.None,
+ };
+ }
}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs
index f14b58b0600..0102ae90c22 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs
+++ b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs
@@ -1,37 +1,40 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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;
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
namespace ILLink.Shared
{
- public readonly struct DiagnosticString
- {
- readonly string _titleFormat;
- readonly string _messageFormat;
-
- public DiagnosticString(DiagnosticId diagnosticId)
- {
- var resourceManager = SharedStrings.ResourceManager;
- _titleFormat = resourceManager.GetString($"{diagnosticId}Title") ?? throw new InvalidOperationException($"{diagnosticId} does not have a matching resource called {diagnosticId}Title");
- _messageFormat = resourceManager.GetString($"{diagnosticId}Message") ?? throw new InvalidOperationException($"{diagnosticId} does not have a matching resource called {diagnosticId}Message");
- }
-
- public DiagnosticString(string diagnosticResourceStringName)
- {
- var resourceManager = SharedStrings.ResourceManager;
- _titleFormat = resourceManager.GetString($"{diagnosticResourceStringName}Title") ?? throw new InvalidOperationException($"{diagnosticResourceStringName} does not have a matching resource called {diagnosticResourceStringName}Title");
- _messageFormat = resourceManager.GetString($"{diagnosticResourceStringName}Message") ?? throw new InvalidOperationException($"{diagnosticResourceStringName} does not have a matching resource called {diagnosticResourceStringName}Message");
- }
-
- public string GetMessage(params string[] args) =>
- string.Format(_messageFormat, args);
-
- public string GetMessageFormat() => _messageFormat;
-
- public string GetTitle(params string[] args) =>
- string.Format(_titleFormat, args);
-
- public string GetTitleFormat() => _titleFormat;
- }
+ public readonly struct DiagnosticString
+ {
+ readonly string _titleFormat;
+ readonly string _messageFormat;
+
+ public DiagnosticString (DiagnosticId diagnosticId)
+ {
+ var resourceManager = SharedStrings.ResourceManager;
+ _titleFormat = resourceManager.GetString ($"{diagnosticId}Title") ?? throw new InvalidOperationException ($"{diagnosticId} does not have a matching resource called {diagnosticId}Title");
+ _messageFormat = resourceManager.GetString ($"{diagnosticId}Message") ?? throw new InvalidOperationException ($"{diagnosticId} does not have a matching resource called {diagnosticId}Message");
+ }
+
+ public DiagnosticString (string diagnosticResourceStringName)
+ {
+ var resourceManager = SharedStrings.ResourceManager;
+ _titleFormat = resourceManager.GetString ($"{diagnosticResourceStringName}Title") ?? throw new InvalidOperationException ($"{diagnosticResourceStringName} does not have a matching resource called {diagnosticResourceStringName}Title");
+ _messageFormat = resourceManager.GetString ($"{diagnosticResourceStringName}Message") ?? throw new InvalidOperationException ($"{diagnosticResourceStringName} does not have a matching resource called {diagnosticResourceStringName}Message");
+ }
+
+ public string GetMessage (params string[] args) =>
+ string.Format (_messageFormat, args);
+
+ public string GetMessageFormat () => _messageFormat;
+
+ public string GetTitle (params string[] args) =>
+ string.Format (_titleFormat, args);
+
+ public string GetTitleFormat () => _titleFormat;
+ }
}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/HashUtils.cs b/src/coreclr/tools/aot/ILLink.Shared/HashUtils.cs
new file mode 100644
index 00000000000..cc9b259bedb
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/HashUtils.cs
@@ -0,0 +1,42 @@
+// 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.
+
+#if !NETSTANDARD2_0
+using System;
+#endif
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared
+{
+ static class HashUtils
+ {
+#if NETSTANDARD2_0
+ // This constant is taken from code that Roslyn generates for GetHashCode of records.
+ const int Multiplier = -1521134295;
+#endif
+ public static int Combine<T1, T2> (T1 value1, T2 value2)
+ where T1 : notnull
+ where T2 : notnull
+ {
+#if NETSTANDARD2_0
+ return value1.GetHashCode () * Multiplier + value2.GetHashCode ();
+#else
+ return HashCode.Combine (value1, value2);
+#endif
+ }
+
+ public static int Combine<T1, T2, T3> (T1 value1, T2 value2, T3 value3)
+ where T1 : notnull
+ where T2 : notnull
+ where T3 : notnull
+ {
+#if NETSTANDARD2_0
+ return (value1.GetHashCode () * Multiplier + value2.GetHashCode ()) * Multiplier + value3.GetHashCode ();
+#else
+ return HashCode.Combine (value1, value2, value3);
+#endif
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd b/src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd
index f1156b0a4d6..e6c21857a2c 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd
+++ b/src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd
@@ -3,122 +3,114 @@
elementFormDefault="unqualified"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:complexType name="membertype">
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="attribute" type="attribute" />
- </xsd:choice>
- <xsd:attribute name="feature" />
- <xsd:attribute name="featurevalue" type="xsd:boolean" />
- <xsd:attribute name="featuredefault" type="xsd:boolean" />
- <xsd:attribute name="name" />
- <xsd:attribute name="signature" />
- </xsd:complexType>
+ <xsd:complexType name="membertype">
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="attribute" type="attribute" />
+ </xsd:choice>
+ <xsd:attribute name="feature" />
+ <xsd:attribute name="featurevalue" type="xsd:boolean" />
+ <xsd:attribute name="featuredefault" type="xsd:boolean" />
+ <xsd:attribute name="name" />
+ <xsd:attribute name="signature" />
+ </xsd:complexType>
- <xsd:complexType name="method">
- <xsd:complexContent>
- <xsd:extension base="membertype">
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="parameter">
- <xsd:complexType>
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="attribute" type="attribute" />
- </xsd:choice>
- <xsd:attribute name="name" use="required" />
- </xsd:complexType>
- </xsd:element>
- </xsd:choice>
- <xsd:choice maxOccurs="1" minOccurs="0">
- <xsd:element name="return">
- <xsd:complexType>
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="attribute" type="attribute" />
- </xsd:choice>
- </xsd:complexType>
- </xsd:element>
- </xsd:choice>
- </xsd:choice>
- </xsd:extension>
- </xsd:complexContent>
- </xsd:complexType>
+ <xsd:complexType name="method">
+ <xsd:complexContent>
+ <xsd:extension base="membertype">
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="parameter">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="attribute" type="attribute" />
+ </xsd:choice>
+ <xsd:attribute name="name" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ <xsd:choice maxOccurs="1" minOccurs="0">
+ <xsd:element name="return">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="attribute" type="attribute" />
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:choice>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
- <xsd:complexType name="argument" mixed="true">
- <xsd:choice minOccurs="0" maxOccurs="1">
- <xsd:element name="argument">
- <xsd:complexType>
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute name="type" />
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
- </xsd:element>
- </xsd:choice>
- <xsd:attribute name="type" />
- </xsd:complexType>
+ <xsd:complexType name="argument" mixed="true">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="argument" type="argument" />
+ </xsd:choice>
+ <xsd:attribute name="type" />
+ </xsd:complexType>
- <xsd:complexType name="attribute">
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="argument" type="argument" />
- <xsd:element name="property">
- <xsd:complexType mixed="true">
- <xsd:attribute name="name" use="required" />
- </xsd:complexType>
- </xsd:element>
- </xsd:choice>
- <xsd:attribute name="internal" />
- <xsd:attribute name="fullname" />
- <xsd:attribute name="assembly" />
- </xsd:complexType>
+ <xsd:complexType name="attribute">
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="argument" type="argument" />
+ <xsd:element name="property">
+ <xsd:complexType mixed="true">
+ <xsd:attribute name="name" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ <xsd:attribute name="internal" />
+ <xsd:attribute name="fullname" />
+ <xsd:attribute name="assembly" />
+ </xsd:complexType>
- <xsd:complexType name="assembly">
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="attribute" type="attribute" />
- <xsd:element name="type" type="type" />
- </xsd:choice>
- <xsd:attribute name="fullname" use="required" />
- <xsd:attribute name="feature" />
- <xsd:attribute name="featurevalue" type="xsd:boolean" />
- <xsd:attribute name="featuredefault" type="xsd:boolean" />
- </xsd:complexType>
+ <xsd:complexType name="assembly">
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="attribute" type="attribute" />
+ <xsd:element name="type" type="type" />
+ </xsd:choice>
+ <xsd:attribute name="fullname" use="required" />
+ <xsd:attribute name="feature" />
+ <xsd:attribute name="featurevalue" type="xsd:boolean" />
+ <xsd:attribute name="featuredefault" type="xsd:boolean" />
+ </xsd:complexType>
- <xsd:complexType name ="nestedtype">
- <xsd:choice minOccurs="0" maxOccurs="unbounded">
- <xsd:element name="event" type="membertype" />
- <xsd:element name="method" type="method" />
- <xsd:element name="field" type="membertype" />
- <xsd:element name="property" type="membertype" />
- <xsd:element name="attribute" type="attribute" />
- <xsd:element name="type" type="nestedtype" />
- </xsd:choice>
- <xsd:attribute name="name" use="required"/>
- <xsd:attribute name="feature" />
- <xsd:attribute name="featurevalue" type="xsd:boolean" />
- <xsd:attribute name="featuredefault" type="xsd:boolean" />
- </xsd:complexType>
+ <xsd:complexType name ="nestedtype">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="event" type="membertype" />
+ <xsd:element name="method" type="method" />
+ <xsd:element name="field" type="membertype" />
+ <xsd:element name="property" type="membertype" />
+ <xsd:element name="attribute" type="attribute" />
+ <xsd:element name="type" type="nestedtype" />
+ </xsd:choice>
+ <xsd:attribute name="name" use="required"/>
+ <xsd:attribute name="feature" />
+ <xsd:attribute name="featurevalue" type="xsd:boolean" />
+ <xsd:attribute name="featuredefault" type="xsd:boolean" />
+ </xsd:complexType>
- <xsd:complexType name="type">
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="attribute" type="attribute" />
- <xsd:element name="event" type="membertype" />
- <xsd:element name="method" type="method" />
- <xsd:element name="field" type="membertype" />
- <xsd:element name="property" type="membertype" />
- <xsd:element name="type" type="nestedtype"/>
- </xsd:choice>
- <xsd:attribute name="feature" />
- <xsd:attribute name="featurevalue" type="xsd:boolean" />
- <xsd:attribute name="featuredefault" type="xsd:boolean" />
- <xsd:attribute name="fullname" use="required"/>
- </xsd:complexType>
+ <xsd:complexType name="type">
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="attribute" type="attribute" />
+ <xsd:element name="event" type="membertype" />
+ <xsd:element name="method" type="method" />
+ <xsd:element name="field" type="membertype" />
+ <xsd:element name="property" type="membertype" />
+ <xsd:element name="type" type="nestedtype"/>
+ </xsd:choice>
+ <xsd:attribute name="feature" />
+ <xsd:attribute name="featurevalue" type="xsd:boolean" />
+ <xsd:attribute name="featuredefault" type="xsd:boolean" />
+ <xsd:attribute name="fullname" use="required"/>
+ </xsd:complexType>
- <xsd:element name="linker">
- <xsd:complexType>
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="assembly" type="assembly" />
- <xsd:element name="type" type="type" />
- </xsd:choice>
- </xsd:complexType>
- </xsd:element>
+ <xsd:element name="linker">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="assembly" type="assembly" />
+ <xsd:element name="type" type="type" />
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
-</xsd:schema>
+</xsd:schema> \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems b/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems
index ffbfab3b984..66dd85465eb 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems
+++ b/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems
@@ -3,17 +3,13 @@
<PropertyGroup>
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
- <SharedGUID>ff598e93-8e9e-4091-9f50-61a7572663ae</SharedGUID>
+ <SharedGUID>92f5e753-2179-46dc-bdce-736858c18dc7</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>ILLink.Shared</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
- <Compile Include="$(MSBuildThisFileDirectory)DiagnosticCategory.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)DiagnosticId.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)DiagnosticString.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)MessageFormat.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)MessageSubCategory.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)/**/*.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)SharedStrings.resx">
@@ -23,8 +19,8 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
- <None Include="$(MSBuildThisFileDirectory)ILLink.LinkAttributes.xsd">
- <SubType>Designer</SubType>
- </None>
- </ItemGroup>
-</Project>
+ <None Include="$(MSBuildThisFileDirectory)ILLink.LinkAttributes.xsd">
+ <SubType>Designer</SubType>
+ </None>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.shproj b/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.shproj
index d632a98be0a..a581f2f0b42 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.shproj
+++ b/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.shproj
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
- <ProjectGuid>ff598e93-8e9e-4091-9f50-61a7572663ae</ProjectGuid>
+ <ProjectGuid>{FF598E93-8E9E-4091-9F50-61A7572663AE}</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
@@ -10,4 +10,4 @@
<PropertyGroup />
<Import Project="ILLink.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILLink.Shared/IsExternalInit.cs b/src/coreclr/tools/aot/ILLink.Shared/IsExternalInit.cs
new file mode 100644
index 00000000000..f2b081a032f
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/IsExternalInit.cs
@@ -0,0 +1,15 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+#if NETSTANDARD
+// Allow use of init setters on downlevel frameworks.
+namespace System.Runtime.CompilerServices
+{
+ public sealed class IsExternalInit
+ {
+ }
+}
+#endif \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILLink.Shared/MessageFormat.cs b/src/coreclr/tools/aot/ILLink.Shared/MessageFormat.cs
index 755279ea65a..0e67c71b676 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/MessageFormat.cs
+++ b/src/coreclr/tools/aot/ILLink.Shared/MessageFormat.cs
@@ -1,39 +1,39 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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.
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
#nullable enable
namespace ILLink.Shared
{
- internal static class MessageFormat
- {
- public static string FormatRequiresAttributeMessageArg(string? message)
- {
- if (!string.IsNullOrEmpty(message))
- return $" {message}{(message!.TrimEnd().EndsWith(".") ? "" : ".")}";
+ internal static class MessageFormat
+ {
+ public static string FormatRequiresAttributeMessageArg (string? message)
+ {
+ if (!string.IsNullOrEmpty (message))
+ return $" {message}{(message!.TrimEnd ().EndsWith (".") ? "" : ".")}";
- return string.Empty;
- }
+ return string.Empty;
+ }
- public static string FormatRequiresAttributeUrlArg(string? url)
- {
- if (!string.IsNullOrEmpty(url))
- return $" {url}";
+ public static string FormatRequiresAttributeUrlArg (string? url)
+ {
+ if (!string.IsNullOrEmpty (url))
+ return $" {url}";
- return string.Empty;
- }
+ return string.Empty;
+ }
- public static string FormatRequiresAttributeMismatch(bool memberHasAttribute, bool isInterface, params object[] args)
- {
- string format = (memberHasAttribute, isInterface) switch
- {
- (false, true) => SharedStrings.InterfaceRequiresMismatchMessage,
- (true, true) => SharedStrings.ImplementationRequiresMismatchMessage,
- (false, false) => SharedStrings.BaseRequiresMismatchMessage,
- (true, false) => SharedStrings.DerivedRequiresMismatchMessage
- };
+ public static string FormatRequiresAttributeMismatch (bool memberHasAttribute, bool isInterface, params object[] args)
+ {
+ string format = (memberHasAttribute, isInterface) switch {
+ (false, true) => SharedStrings.InterfaceRequiresMismatchMessage,
+ (true, true) => SharedStrings.ImplementationRequiresMismatchMessage,
+ (false, false) => SharedStrings.BaseRequiresMismatchMessage,
+ (true, false) => SharedStrings.DerivedRequiresMismatchMessage
+ };
- return string.Format(format, args);
- }
- }
+ return string.Format (format, args);
+ }
+ }
}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs b/src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs
index 92c1077b14b..4b47d266681 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs
+++ b/src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs
@@ -1,13 +1,16 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
namespace ILLink.Shared
{
- public static class MessageSubCategory
- {
- public const string None = "";
- public const string TrimAnalysis = "Trim analysis";
- public const string UnresolvedAssembly = "Unresolved assembly";
- public const string AotAnalysis = "AOT analysis";
- }
+ public static class MessageSubCategory
+ {
+ public const string None = "";
+ public const string TrimAnalysis = "Trim analysis";
+ public const string UnresolvedAssembly = "Unresolved assembly";
+ public const string AotAnalysis = "AOT analysis";
+ }
}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/README.md b/src/coreclr/tools/aot/ILLink.Shared/README.md
index 229b67e492b..ddd835b1d23 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/README.md
+++ b/src/coreclr/tools/aot/ILLink.Shared/README.md
@@ -1 +1 @@
-Sources taken from https://github.com/dotnet/linker/tree/890591b13da936d2c38a52afdaeac0db69858d4f/src/ILLink.Shared.
+Sources taken from https://github.com/dotnet/linker/tree/6aaa900a0b1268fe4a6ce3e8af4678e84ea154fd/src/ILLink.Shared.
diff --git a/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx b/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx
index cdcb30468f3..61e172189bd 100644
--- a/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx
+++ b/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@@ -53,6 +53,7 @@
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
+
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
@@ -135,7 +136,7 @@
<value>Error processing '{0}': {1}.</value>
</data>
<data name="CouldNotFindMethodInAssemblyTitle" xml:space="preserve">
- <value>An error occurred while processing a method in assembly.</value>
+ <value>An error ocurred while processing a method in assembly.</value>
</data>
<data name="CouldNotFindMethodInAssemblyMessage" xml:space="preserve">
<value>Error processing method '{0}' in assembly '{1}'.</value>
@@ -524,10 +525,10 @@
<data name="XmlMoreThanOneReturnElementForMethodMessage" xml:space="preserve">
<value>There is more than one 'return' child element specified for method '{0}'.</value>
</data>
- <data name="XmlMoreThanOneValueForParameterOfMethodTitle" xml:space="preserve">
+ <data name="XmlMoreThanOneValyForParameterOfMethodTitle" xml:space="preserve">
<value>Method has more than one parameter for the XML element 'parameter'. There can only be one value specified for each parameter.</value>
</data>
- <data name="XmlMoreThanOneValueForParameterOfMethodMessage" xml:space="preserve">
+ <data name="XmlMoreThanOneValyForParameterOfMethodMessage" xml:space="preserve">
<value>More than one value specified for parameter '{0}' of method '{1}'.</value>
</data>
<data name="XmlDuplicatePreserveMemberTitle" xml:space="preserve">
@@ -1064,6 +1065,12 @@
<data name="RequiresUnreferencedCodeOnStaticConstructorMessage" xml:space="preserve">
<value>'RequiresUnreferencedCodeAttribute' cannot be placed directly on static constructor '{0}', consider placing 'RequiresUnreferencedCodeAttribute' on the type declaration instead.</value>
</data>
+ <data name="MethodsAreAssociatedWithUserMethodTitle" xml:space="preserve">
+ <value>Trimmer currently can't correctly handle if the same compiler generated lambda or local function is associated with two different methods.</value>
+ </data>
+ <data name="MethodsAreAssociatedWithUserMethodMessage" xml:space="preserve">
+ <value>Methods '{0}' and '{1}' are both associated with lambda or local function '{2}'. This is currently unsupported and may lead to incorrectly reported warnings.</value>
+ </data>
<data name="AvoidAssemblyLocationInSingleFileTitle" xml:space="preserve">
<value>Avoid accessing Assembly file path when publishing as a single file</value>
</data>
@@ -1136,4 +1143,28 @@
<data name="InterfaceRequiresMismatchMessage" xml:space="preserve">
<value>Interface member '{2}' with '{0}' has an implementation member '{1}' without '{0}'</value>
</data>
-</root>
+ <data name="RequiresOnBaseClassMessage" xml:space="preserve">
+ <value>Type '{0}' derives from '{1}' which has 'RequiresUnreferencedCodeAttribute'. {2}{3}</value>
+ </data>
+ <data name="RequiresOnBaseClassTitle" xml:space="preserve">
+ <value>Types that derive from a base class with 'RequiresUnreferencedCodeAttribute' need to explicitly use the 'RequiresUnreferencedCodeAttribute' or suppress this warning</value>
+ </data>
+ <data name="RequiresDynamicCodeOnStaticConstructorMessage" xml:space="preserve">
+ <value>'RequiresDynamicCodeAttribute' cannot be placed directly on static constructor '{0}'.</value>
+ </data>
+ <data name="RequiresDynamicCodeOnStaticConstructorTitle" xml:space="preserve">
+ <value>The use of 'RequiresDynamicCodeAttribute' on static constructors is disallowed since is a method not callable by the user, is only called by the runtime. Placing the attribute directly on the static constructor will have no effect, instead use 'RequiresUnreferencedCodeAttribute' on the type which will handle warning and silencing from the static constructor.</value>
+ </data>
+ <data name="RequiresAssemblyFilesOnStaticConstructorMessage" xml:space="preserve">
+ <value>'RequiresAssemblyFilesAttribute' cannot be placed directly on static constructor '{0}'.</value>
+ </data>
+ <data name="RequiresAssemblyFilesOnStaticConstructorTitle" xml:space="preserve">
+ <value>The use of 'RequiresAssemblyFilesAttribute' on static constructors is disallowed since is a method not callable by the user, is only called by the runtime. Placing the attribute directly on the static constructor will have no effect, instead use 'RequiresUnreferencedCodeAttribute' on the type which will handle warning and silencing from the static constructor.</value>
+ </data>
+ <data name="UnrecognizedInternalAttributeMessage" xml:space="preserve">
+ <value>The internal attribute name '{0}' being used in the xml is not supported by the linker, check the spelling and the supported internal attributes.</value>
+ </data>
+ <data name="UnrecognizedInternalAttributeTitle" xml:space="preserve">
+ <value>Unrecognized internal attribute '{0}'</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ArrayValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ArrayValue.cs
new file mode 100644
index 00000000000..d8c39987837
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ArrayValue.cs
@@ -0,0 +1,20 @@
+// 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 ILLink.Shared.DataFlow;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ sealed partial record ArrayValue : SingleValue
+ {
+ static ValueSetLattice<SingleValue> MultiValueLattice => default;
+
+ public readonly SingleValue Size;
+
+ public partial bool TryGetValueByIndex (int index, out MultiValue value);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ConstIntValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ConstIntValue.cs
new file mode 100644
index 00000000000..e83a7cd5d37
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ConstIntValue.cs
@@ -0,0 +1,24 @@
+// 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 ILLink.Shared.DataFlow;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// Represents a ldc on an int32.
+ /// </summary>
+ sealed record ConstIntValue : SingleValue
+ {
+ public ConstIntValue (int value) => Value = value;
+
+ public readonly int Value;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (Value);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs
new file mode 100644
index 00000000000..06353c22285
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs
@@ -0,0 +1,13 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ readonly partial struct DiagnosticContext
+ {
+ public partial void AddDiagnostic (DiagnosticId id, params string[] args);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FieldValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FieldValue.cs
new file mode 100644
index 00000000000..0041e436313
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FieldValue.cs
@@ -0,0 +1,10 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ sealed partial record FieldValue : ValueWithDynamicallyAccessedMembers;
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
new file mode 100644
index 00000000000..7d3912e971e
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
@@ -0,0 +1,31 @@
+// 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.Diagnostics.CodeAnalysis;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ // Shared helpers to go from MethodProxy to dataflow values.
+ partial class FlowAnnotations
+ {
+ internal partial bool MethodRequiresDataFlowAnalysis (MethodProxy method);
+
+ internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+
+ internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method);
+
+ internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter);
+
+ internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+
+ internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method);
+
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex);
+ }
+} \ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/GenericParameterValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/GenericParameterValue.cs
new file mode 100644
index 00000000000..18bfa5fbbde
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/GenericParameterValue.cs
@@ -0,0 +1,19 @@
+// 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 ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is a System.Type value which represents generic parameter (basically result of typeof(T))
+ /// Its actual type is unknown, but it can have annotations.
+ /// </summary>
+ sealed partial record GenericParameterValue : ValueWithDynamicallyAccessedMembers
+ {
+ public readonly GenericParameterProxy GenericParameter;
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/HandleCallAction.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
new file mode 100644
index 00000000000..942310a0090
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
@@ -0,0 +1,1445 @@
+// 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.Collections.Immutable;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ [StructLayout (LayoutKind.Auto)] // A good way to avoid CS0282, we don't really care about field order
+ partial struct HandleCallAction
+ {
+ static ValueSetLattice<SingleValue> MultiValueLattice => default;
+
+ readonly DiagnosticContext _diagnosticContext;
+ readonly FlowAnnotations _annotations;
+ readonly RequireDynamicallyAccessedMembersAction _requireDynamicallyAccessedMembersAction;
+
+ public bool Invoke (MethodProxy calledMethod, MultiValue instanceValue, IReadOnlyList<MultiValue> argumentValues, out MultiValue methodReturnValue, out IntrinsicId intrinsicId)
+ {
+ MultiValue? returnValue = null;
+
+ bool requiresDataFlowAnalysis = _annotations.MethodRequiresDataFlowAnalysis (calledMethod);
+ var annotatedMethodReturnValue = _annotations.GetMethodReturnValue (calledMethod);
+ Debug.Assert (requiresDataFlowAnalysis || annotatedMethodReturnValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None);
+
+ intrinsicId = Intrinsics.GetIntrinsicIdForMethod (calledMethod);
+ switch (intrinsicId) {
+ case IntrinsicId.IntrospectionExtensions_GetTypeInfo:
+ Debug.Assert (instanceValue.IsEmpty ());
+ Debug.Assert (argumentValues.Count == 1);
+
+ // typeof(Foo).GetTypeInfo()... will be commonly present in code targeting
+ // the dead-end reflection refactoring. The call doesn't do anything and we
+ // don't want to lose the annotation.
+ returnValue = argumentValues[0];
+ break;
+
+ case IntrinsicId.TypeInfo_AsType:
+ // someType.AsType()... will be commonly present in code targeting
+ // the dead-end reflection refactoring. The call doesn't do anything and we
+ // don't want to lose the annotation.
+ returnValue = instanceValue;
+ break;
+
+ //
+ // UnderlyingSystemType
+ //
+ case IntrinsicId.Type_get_UnderlyingSystemType:
+ // This is identity for the purposes of the analysis.
+ returnValue = instanceValue;
+ break;
+
+ case IntrinsicId.Type_GetTypeFromHandle:
+ // Infrastructure piece to support "typeof(Foo)" in IL and direct calls everywhere
+ if (argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var value in argumentValues[0]) {
+ AddReturnValue (value switch {
+ RuntimeTypeHandleForNullableSystemTypeValue nullableSystemType
+ => new NullableSystemTypeValue (nullableSystemType.NullableType, nullableSystemType.UnderlyingTypeValue),
+ // When generating type handles from IL, the GenericParameterValue with DAM annotations is not available.
+ // Once we convert it to a Value with annotations here, there is no need to convert it back in get_TypeHandle
+ RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers nullableDamType when nullableDamType.UnderlyingTypeValue is RuntimeTypeHandleForGenericParameterValue underlyingGenericParameter
+ => new NullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, _annotations.GetGenericParameterValue (underlyingGenericParameter.GenericParameter)),
+ // This should only happen if the code does something like typeof(Nullable<>).MakeGenericType(methodParameter).TypeHandle
+ RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers nullableDamType when nullableDamType.UnderlyingTypeValue is ValueWithDynamicallyAccessedMembers underlyingTypeValue
+ => new NullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, underlyingTypeValue),
+ RuntimeTypeHandleValue typeHandle
+ => new SystemTypeValue (typeHandle.RepresentedType),
+ RuntimeTypeHandleForGenericParameterValue genericParam
+ => _annotations.GetGenericParameterValue (genericParam.GenericParameter),
+ _ => annotatedMethodReturnValue
+ });
+ }
+ break;
+
+ case IntrinsicId.Type_get_TypeHandle:
+ if (instanceValue.IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var value in instanceValue) {
+ if (value != NullValue.Instance)
+ AddReturnValue (value switch {
+ NullableSystemTypeValue nullableSystemType
+ => new RuntimeTypeHandleForNullableSystemTypeValue (nullableSystemType.NullableType, nullableSystemType.UnderlyingTypeValue),
+ NullableValueWithDynamicallyAccessedMembers nullableDamType when nullableDamType.UnderlyingTypeValue is GenericParameterValue genericParam
+ => new RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, new RuntimeTypeHandleForGenericParameterValue (genericParam.GenericParameter)),
+ NullableValueWithDynamicallyAccessedMembers nullableDamType
+ => new RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, nullableDamType.UnderlyingTypeValue),
+ SystemTypeValue typeHandle
+ => new RuntimeTypeHandleValue (typeHandle.RepresentedType),
+ GenericParameterValue genericParam
+ => new RuntimeTypeHandleForGenericParameterValue (genericParam.GenericParameter),
+ _ => annotatedMethodReturnValue
+ });
+ else
+ AddReturnValue (MultiValueLattice.Top);
+ }
+ break;
+
+ // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
+ // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
+ case IntrinsicId.MethodBase_GetMethodFromHandle: {
+ if (argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ // Infrastructure piece to support "ldtoken method -> GetMethodFromHandle"
+ foreach (var value in argumentValues[0]) {
+ if (value is RuntimeMethodHandleValue methodHandle)
+ AddReturnValue (new SystemReflectionMethodBaseValue (methodHandle.RepresentedMethod));
+ else
+ AddReturnValue (annotatedMethodReturnValue);
+ }
+ }
+ break;
+
+ case IntrinsicId.MethodBase_get_MethodHandle: {
+ if (instanceValue.IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var value in instanceValue) {
+ if (value is SystemReflectionMethodBaseValue methodBaseValue)
+ AddReturnValue (new RuntimeMethodHandleValue (methodBaseValue.RepresentedMethod));
+ else
+ AddReturnValue (annotatedMethodReturnValue);
+ }
+ }
+ break;
+
+ case IntrinsicId.TypeDelegator_Ctor:
+ // This needs additional validation that the .ctor is called from a "newobj" instruction/operation
+ // so it can't be done easily in shared code yet.
+ case IntrinsicId.Array_Empty:
+ // Array.Empty<T> must for now be handled by the specific implementation since it requires instantiated generic method handling
+ methodReturnValue = MultiValueLattice.Top;
+ return false;
+
+ //
+ // GetInterface (String)
+ // GetInterface (String, bool)
+ //
+ case IntrinsicId.Type_GetInterface: {
+ if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, DynamicallyAccessedMemberTypesOverlay.Interfaces);
+ foreach (var value in instanceValue) {
+ foreach (var interfaceName in argumentValues[0]) {
+ if (interfaceName == NullValue.Instance) {
+ // Throws on null string, so no return value.
+ AddReturnValue (MultiValueLattice.Top);
+ } else if (interfaceName is KnownStringValue stringValue && stringValue.Contents.Length == 0) {
+ AddReturnValue (NullValue.Instance);
+ } else {
+ // For now no support for marking a single interface by name. We would have to correctly support
+ // mangled names for generics to do that correctly. Simply mark all interfaces on the type for now.
+
+ // Require Interfaces annotation
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+
+ // Interfaces is transitive, so the return values will always have at least Interfaces annotation
+ DynamicallyAccessedMemberTypes returnMemberTypes = DynamicallyAccessedMemberTypesOverlay.Interfaces;
+
+ // Propagate All annotation across the call - All is a superset of Interfaces
+ if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
+ && valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
+ returnMemberTypes = DynamicallyAccessedMemberTypes.All;
+
+ AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, returnMemberTypes));
+ }
+ }
+ }
+ }
+ break;
+
+ //
+ // AssemblyQualifiedName
+ //
+ case IntrinsicId.Type_get_AssemblyQualifiedName: {
+ if (instanceValue.IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var value in instanceValue) {
+ if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers) {
+ // Currently we don't need to track the difference between Type and String annotated values
+ // that only matters when we use them, so Type.GetType is the difference really.
+ // For diagnostics we actually don't want to track the Type.AssemblyQualifiedName
+ // as the annotation does not come from that call, but from its input.
+ AddReturnValue (valueWithDynamicallyAccessedMembers);
+ } else if (value == NullValue.Instance) {
+ // NullReferenceException, no return value.
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ AddReturnValue (UnknownValue.Instance);
+ }
+ }
+ }
+ break;
+
+ //
+ // System.Runtime.CompilerServices.RuntimeHelpers
+ //
+ // RunClassConstructor (RuntimeTypeHandle type)
+ //
+ case IntrinsicId.RuntimeHelpers_RunClassConstructor:
+ if (argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var typeHandleValue in argumentValues[0]) {
+ if (typeHandleValue is RuntimeTypeHandleValue runtimeTypeHandleValue) {
+ MarkStaticConstructor (runtimeTypeHandleValue.RepresentedType);
+ } else {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedTypeInRuntimeHelpersRunClassConstructor, calledMethod.GetDisplayName ());
+ }
+ }
+ break;
+
+ //
+ // GetConstructors (BindingFlags)
+ // GetMethods (BindingFlags)
+ // GetFields (BindingFlags)
+ // GetEvents (BindingFlags)
+ // GetProperties (BindingFlags)
+ // GetNestedTypes (BindingFlags)
+ // GetMembers (BindingFlags)
+ //
+ case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
+ callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
+ && calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && !calledMethod.IsStatic (): {
+
+ BindingFlags? bindingFlags;
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[0]);
+ DynamicallyAccessedMemberTypes memberTypes;
+ if (BindingFlagsAreUnsupported (bindingFlags)) {
+ memberTypes = callType switch {
+ IntrinsicId.Type_GetConstructors => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors,
+ IntrinsicId.Type_GetMethods => DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods,
+ IntrinsicId.Type_GetEvents => DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents,
+ IntrinsicId.Type_GetFields => DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields,
+ IntrinsicId.Type_GetProperties => DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties,
+ IntrinsicId.Type_GetNestedTypes => DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
+ IntrinsicId.Type_GetMembers => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
+ DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
+ DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
+ DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
+ DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
+ DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+ } else {
+ memberTypes = callType switch {
+ IntrinsicId.Type_GetConstructors => GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags),
+ IntrinsicId.Type_GetMethods => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags),
+ IntrinsicId.Type_GetEvents => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
+ IntrinsicId.Type_GetFields => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
+ IntrinsicId.Type_GetProperties => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
+ IntrinsicId.Type_GetNestedTypes => GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags),
+ IntrinsicId.Type_GetMembers => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags),
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+ }
+
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, memberTypes);
+ _requireDynamicallyAccessedMembersAction.Invoke (instanceValue, targetValue);
+ }
+ break;
+
+ //
+ // GetField (string)
+ // GetField (string, BindingFlags)
+ // GetEvent (string)
+ // GetEvent (string, BindingFlags)
+ // GetProperty (string)
+ // GetProperty (string, BindingFlags)
+ // GetProperty (string, Type)
+ // GetProperty (string, Type[])
+ // GetProperty (string, Type, Type[])
+ // GetProperty (string, Type, Type[], ParameterModifier[])
+ // GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
+ //
+ case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
+ && calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic (): {
+
+ if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+
+ DynamicallyAccessedMemberTypes memberTypes = fieldPropertyOrEvent switch {
+ IntrinsicId.Type_GetEvent => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
+ IntrinsicId.Type_GetField => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
+ IntrinsicId.Type_GetProperty => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, memberTypes);
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[0]) {
+ if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
+ switch (fieldPropertyOrEvent) {
+ case IntrinsicId.Type_GetEvent:
+ MarkEventsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.Type_GetField:
+ MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.Type_GetProperty:
+ MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ default:
+ Debug.Fail ("Unreachable.");
+ break;
+ }
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // GetMember (String)
+ // GetMember (String, BindingFlags)
+ // GetMember (String, MemberTypes, BindingFlags)
+ //
+ case IntrinsicId.Type_GetMember: {
+ if (instanceValue.IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParametersCount (1)) {
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Public | BindingFlags.Instance;
+ } else if (calledMethod.HasParametersCount (2) && calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else if (calledMethod.HasParametersCount (3) && calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags")) {
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
+ } else // Non recognized intrinsic
+ throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is an unexpected intrinsic.");
+
+ DynamicallyAccessedMemberTypes requiredMemberTypes;
+ if (BindingFlagsAreUnsupported (bindingFlags)) {
+ requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
+ DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
+ DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
+ DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
+ DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
+ DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
+ } else {
+ requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags);
+ }
+
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, requiredMemberTypes);
+
+ // Go over all types we've seen
+ foreach (var value in instanceValue) {
+ // Mark based on bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ break;
+
+ //
+ // GetMethod (string)
+ // GetMethod (string, BindingFlags)
+ // GetMethod (string, Type[])
+ // GetMethod (string, Type[], ParameterModifier[])
+ // GetMethod (string, BindingFlags, Type[])
+ // GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
+ // GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
+ // GetMethod (string, int, Type[])
+ // GetMethod (string, int, Type[], ParameterModifier[]?)
+ // GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
+ // GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
+ //
+ case IntrinsicId.Type_GetMethod: {
+ if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else if (calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
+ else
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags));
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[0]) {
+ if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
+ AddReturnValue (MultiValueLattice.Top); ; // Initialize return value (so that it's not autofilled if there are no matching methods)
+ foreach (var methodValue in ProcessGetMethodByName (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags))
+ AddReturnValue (methodValue);
+ } else if (stringParam is NullValue) {
+ // GetMethod(null) throws - so track empty value set as its result
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ AddReturnValue (annotatedMethodReturnValue);
+ }
+ }
+ } else if (value is NullValue) {
+ // null.GetMethod(...) throws - so track empty value set as its result
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ AddReturnValue (annotatedMethodReturnValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // GetNestedType (string)
+ // GetNestedType (string, BindingFlags)
+ //
+ case IntrinsicId.Type_GetNestedType: {
+ if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags));
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[0]) {
+ if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
+ AddReturnValue (MultiValueLattice.Top);
+ foreach (var nestedTypeValue in GetNestedTypesOnType (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags)) {
+ MarkType (nestedTypeValue.RepresentedType);
+ AddReturnValue (nestedTypeValue);
+ }
+ } else if (stringParam is NullValue) {
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+
+ // 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));
+ }
+ }
+ } else if (value is NullValue) {
+ // null.GetNestedType(..) throws - so track empty value set
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+
+ // If the input is an annotated value which has All - we can propagate that to the return value
+ // 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));
+ else
+ AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, DynamicallyAccessedMemberTypes.None));
+ }
+ }
+ }
+ break;
+
+ //
+ // System.Reflection.RuntimeReflectionExtensions
+ //
+ // static GetRuntimeEvent (this Type type, string name)
+ // static GetRuntimeField (this Type type, string name)
+ // static GetRuntimeMethod (this Type type, string name, Type[] parameters)
+ // static GetRuntimeProperty (this Type type, string name)
+ //
+ case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty: {
+
+ if (argumentValues[0].IsEmpty () || argumentValues[1].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+ DynamicallyAccessedMemberTypes requiredMemberTypes = getRuntimeMember switch {
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent => DynamicallyAccessedMemberTypes.PublicEvents,
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField => DynamicallyAccessedMemberTypes.PublicFields,
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod => DynamicallyAccessedMemberTypes.PublicMethods,
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty => DynamicallyAccessedMemberTypes.PublicProperties,
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+
+ var targetValue = _annotations.GetMethodParameterValue (calledMethod, 0, requiredMemberTypes);
+
+ foreach (var value in argumentValues[0]) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[1]) {
+ if (stringParam is KnownStringValue stringValue) {
+ switch (getRuntimeMember) {
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent:
+ MarkEventsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField:
+ MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod:
+ AddReturnValue (MultiValueLattice.Top); // Initialize return value (so that it's not autofilled if there are no matching methods)
+ foreach (var methodValue in ProcessGetMethodByName (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags))
+ AddReturnValue (methodValue);
+ break;
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
+ MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ default:
+ throw new ArgumentException ($"Error processing reflection call '{calledMethod.GetDisplayName ()}' inside {GetContainingSymbolDisplayName ()}. Unexpected member kind.");
+ }
+ } else if (stringParam is NullValue) {
+ // GetRuntimeMethod(type, null) throws - so track empty value set as its result
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ AddReturnValue (annotatedMethodReturnValue);
+ }
+ }
+ } else if (value is NullValue) {
+ // GetRuntimeMethod(null, ...) throws - so track empty value set as its result
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ AddReturnValue (annotatedMethodReturnValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // System.Linq.Expressions.Expression
+ //
+ // static New (Type)
+ //
+ case IntrinsicId.Expression_New: {
+ var targetValue = _annotations.GetMethodParameterValue (calledMethod, 0, DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
+ foreach (var value in argumentValues[0]) {
+ if (value is SystemTypeValue systemTypeValue) {
+ MarkConstructorsOnType (systemTypeValue.RepresentedType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, parameterCount: null);
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // System.Linq.Expressions.Expression
+ //
+ // static Property (Expression, MethodInfo)
+ //
+ case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo"): {
+ if (argumentValues[1].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var value in argumentValues[1]) {
+ if (value is SystemReflectionMethodBaseValue methodBaseValue) {
+ // We have one of the accessors for the property. The Expression.Property will in this case search
+ // for the matching PropertyInfo and store that. So to be perfectly correct we need to mark the
+ // respective PropertyInfo as "accessed via reflection".
+ if (MarkAssociatedProperty (methodBaseValue.RepresentedMethod))
+ continue;
+ } else if (value == NullValue.Instance) {
+ continue;
+ }
+
+ // In all other cases we may not even know which type this is about, so there's nothing we can do
+ // report it as a warning.
+ _diagnosticContext.AddDiagnostic (DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined,
+ _annotations.GetMethodParameterValue (calledMethod, 1, DynamicallyAccessedMemberTypes.None).GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ());
+ }
+ }
+ break;
+
+ //
+ // System.Linq.Expressions.Expression
+ //
+ // static Field (Expression, Type, String)
+ // static Property (Expression, Type, String)
+ //
+ case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property: {
+ DynamicallyAccessedMemberTypes memberTypes = fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property
+ ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties
+ : DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields;
+
+ if (argumentValues[1].IsEmpty () || argumentValues[2].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ var targetValue = _annotations.GetMethodParameterValue (calledMethod, 1, memberTypes);
+ foreach (var value in argumentValues[1]) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[2]) {
+ if (stringParam is KnownStringValue stringValue) {
+ BindingFlags bindingFlags = argumentValues[0].AsSingleValue () is NullValue ? BindingFlags.Static : BindingFlags.Default;
+ if (fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property) {
+ MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ } else {
+ MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ }
+ } else if (stringParam is NullValue) {
+ // Null name will always throw, so there's nothing to do
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // System.Linq.Expressions.Expression
+ //
+ // static Call (Type, String, Type[], Expression[])
+ //
+ case IntrinsicId.Expression_Call: {
+ BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
+
+ var targetValue = _annotations.GetMethodParameterValue (
+ calledMethod,
+ 0,
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags));
+
+ // This is true even if we "don't know" - so it's only false if we're sure that there are no type arguments
+ bool hasTypeArguments = (argumentValues[2].AsSingleValue () as ArrayValue)?.Size.AsConstInt () != 0;
+ foreach (var value in argumentValues[0]) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[1]) {
+ if (stringParam is KnownStringValue stringValue) {
+ foreach (var method in GetMethodsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags)) {
+ ValidateGenericMethodInstantiation (method.RepresentedMethod, argumentValues[2], calledMethod);
+ MarkMethod (method.RepresentedMethod);
+ }
+ } else {
+ if (hasTypeArguments) {
+ // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
+ // that the method may have requirements which we can't fullfil -> warn.
+ _diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericMethod, calledMethod.GetDisplayName ());
+ }
+
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ } else {
+ if (hasTypeArguments) {
+ // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
+ // that the method may have requirements which we can't fullfil -> warn.
+ _diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericMethod, calledMethod.GetDisplayName ());
+ }
+
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // Nullable.GetUnderlyingType(Type)
+ //
+ case IntrinsicId.Nullable_GetUnderlyingType:
+ if (argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var singlevalue in argumentValues[0].AsEnumerable ()) {
+ AddReturnValue (singlevalue switch {
+ SystemTypeValue systemType =>
+ systemType.RepresentedType.IsTypeOf ("System", "Nullable`1")
+ // This will happen if there's typeof(Nullable<>).MakeGenericType(unknown) - we know the return value is Nullable<>
+ // but we don't know of what. So we represent it as known type, but not as known nullable type.
+ // Has to be special cased here, since we need to return "unknown" type.
+ ? annotatedMethodReturnValue
+ : MultiValueLattice.Top, // This returns null at runtime, so return empty value
+ NullableSystemTypeValue nullableSystemType => nullableSystemType.UnderlyingTypeValue,
+ NullableValueWithDynamicallyAccessedMembers nullableDamValue => nullableDamValue.UnderlyingTypeValue,
+ ValueWithDynamicallyAccessedMembers damValue => damValue,
+ _ => annotatedMethodReturnValue
+ });
+ }
+ break;
+
+ //
+ // System.Type
+ //
+ // GetType (string)
+ // GetType (string, Boolean)
+ // GetType (string, Boolean, Boolean)
+ // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>)
+ // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
+ // GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
+ //
+ case IntrinsicId.Type_GetType: {
+ if (argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ if ((calledMethod.HasParametersCount (3) && calledMethod.HasParameterOfType (2, "System.Boolean") && argumentValues[2].AsConstInt () != 0) ||
+ (calledMethod.HasParametersCount (5) && argumentValues[4].AsConstInt () != 0)) {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.CaseInsensitiveTypeGetTypeCallIsNotSupported, calledMethod.GetDisplayName ());
+ returnValue = MultiValueLattice.Top; // This effectively disables analysis of anything which uses the return value
+ break;
+ }
+
+ foreach (var typeNameValue in argumentValues[0]) {
+ if (typeNameValue is KnownStringValue knownStringValue) {
+ if (!_requireDynamicallyAccessedMembersAction.TryResolveTypeNameAndMark (knownStringValue.Contents, false, out TypeProxy foundType)) {
+ // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ AddReturnValue (new SystemTypeValue (foundType));
+ }
+ } else if (typeNameValue == NullValue.Instance) {
+ // Nothing to do - this throws at runtime
+ AddReturnValue (MultiValueLattice.Top);
+ } 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 fullfilled 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));
+ } else {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedTypeNameInTypeGetType, calledMethod.GetDisplayName ());
+ AddReturnValue (MultiValueLattice.Top);
+ }
+ }
+
+ }
+ break;
+
+ //
+ // System.Type
+ //
+ // Type MakeGenericType (params Type[] typeArguments)
+ //
+ case IntrinsicId.Type_MakeGenericType:
+ if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue typeValue) {
+ var genericParameterValues = GetGenericParameterValues (typeValue.RepresentedType.GetGenericParameters ());
+ if (!AnalyzeGenericInstantiationTypeArray (argumentValues[0], calledMethod, genericParameterValues)) {
+ bool hasUncheckedAnnotation = false;
+ foreach (var genericParameter in genericParameterValues) {
+ if (genericParameter.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None ||
+ (genericParameter.GenericParameter.HasDefaultConstructorConstraint () && !typeValue.RepresentedType.IsTypeOf ("System", "Nullable`1"))) {
+ // If we failed to analyze the array, we go through the analyses again
+ // and intentionally ignore one particular annotation:
+ // Special case: Nullable<T> where T : struct
+ // The struct constraint in C# implies new() constraints, but Nullable doesn't make a use of that part.
+ // There are several places even in the framework where typeof(Nullable<>).MakeGenericType would warn
+ // without any good reason to do so.
+ hasUncheckedAnnotation = true;
+ break;
+ }
+ }
+ if (hasUncheckedAnnotation) {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericType, calledMethod.GetDisplayName ());
+ }
+ }
+
+ // Nullables without a type argument are considered SystemTypeValues
+ if (typeValue.RepresentedType.IsTypeOf ("System", "Nullable`1")) {
+ foreach (var argumentValue in argumentValues[0]) {
+ if ((argumentValue as ArrayValue)?.TryGetValueByIndex (0, out var underlyingMultiValue) == true) {
+ foreach (var underlyingValue in underlyingMultiValue) {
+ switch (underlyingValue) {
+ // Don't warn on these types - it will throw instead
+ case NullableValueWithDynamicallyAccessedMembers:
+ case NullableSystemTypeValue:
+ case SystemTypeValue maybeArrayValue when maybeArrayValue.RepresentedType.IsTypeOf ("System", "Array"):
+ AddReturnValue (MultiValueLattice.Top);
+ break;
+ case SystemTypeValue systemTypeValue:
+ AddReturnValue (new NullableSystemTypeValue (typeValue.RepresentedType, new SystemTypeValue (systemTypeValue.RepresentedType)));
+ break;
+ // Generic Parameters and method parameters with annotations
+ case ValueWithDynamicallyAccessedMembers damValue:
+ AddReturnValue (new NullableValueWithDynamicallyAccessedMembers (typeValue.RepresentedType, damValue));
+ break;
+ // Everything else assume it has no annotations
+ default:
+ // This returns just Nullable<> SystemTypeValue - so some things will work, but GetUnderlyingType won't propagate anything
+ // It's special cased to do that.
+ AddReturnValue (value);
+ break;
+ }
+ }
+ } else {
+ // This returns just Nullable<> SystemTypeValue - so some things will work, but GetUnderlyingType won't propagate anything
+ // It's special cased to do that.
+ AddReturnValue (value);
+ }
+ }
+ // We want to skip adding the `value` to the return Value because we have already added Nullable<value>
+ continue;
+ }
+ // We haven't found any generic parameters with annotations, so there's nothing to validate.
+ } else if (value == NullValue.Instance) {
+ // At runtime this would throw - so it has no effect on analysis
+ AddReturnValue (MultiValueLattice.Top);
+ } else {
+ // We have no way to "include more" to fix this if we don't know, so we have to warn
+ _diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericType, calledMethod.GetDisplayName ());
+ }
+
+ // We don't want to lose track of the type
+ // in case this is e.g. Activator.CreateInstance(typeof(Foo<>).MakeGenericType(...));
+ // Note this is not called in the Nullable case - we skipt this via the 'continue'.
+ AddReturnValue (value);
+ }
+ break;
+
+ //
+ // Type.BaseType
+ //
+ case IntrinsicId.Type_get_BaseType: {
+ if (instanceValue.IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var value in instanceValue) {
+ if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers) {
+ DynamicallyAccessedMemberTypes propagatedMemberTypes = DynamicallyAccessedMemberTypes.None;
+ if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
+ propagatedMemberTypes = DynamicallyAccessedMemberTypes.All;
+ else {
+ // PublicConstructors are not propagated to base type
+
+ if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicEvents))
+ propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicEvents;
+
+ if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicFields))
+ propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicFields;
+
+ if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicMethods))
+ propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicMethods;
+
+ // PublicNestedTypes are not propagated to base type
+
+ // PublicParameterlessConstructor is not propagated to base type
+
+ if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicProperties))
+ propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicProperties;
+
+ if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.Interfaces))
+ propagatedMemberTypes |= DynamicallyAccessedMemberTypes.Interfaces;
+ }
+
+ AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, propagatedMemberTypes));
+ } else if (value is SystemTypeValue systemTypeValue) {
+ if (TryGetBaseType (systemTypeValue.RepresentedType, out var baseType))
+ AddReturnValue (new SystemTypeValue (baseType.Value));
+ else
+ AddReturnValue (annotatedMethodReturnValue);
+ } else if (value == NullValue.Instance) {
+ // Ignore nulls - null.BaseType will fail at runtime, but it has no effect on static analysis
+ AddReturnValue (MultiValueLattice.Top);
+ continue;
+ } else {
+ // Unknown input - propagate a return value without any annotation - we know it's a Type but we know nothing about it
+ AddReturnValue (annotatedMethodReturnValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // GetConstructor (Type[])
+ // GetConstructor (BindingFlags, Type[])
+ // GetConstructor (BindingFlags, Binder, Type[], ParameterModifier [])
+ // GetConstructor (BindingFlags, Binder, CallingConventions, Type[], ParameterModifier [])
+ //
+ case IntrinsicId.Type_GetConstructor: {
+ if (instanceValue.IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[0]);
+ else
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Public | BindingFlags.Instance;
+
+ int? ctorParameterCount = calledMethod.GetParametersCount () switch {
+ 1 => (argumentValues[0].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
+ 2 => (argumentValues[1].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
+ 4 => (argumentValues[2].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
+ 5 => (argumentValues[3].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
+ _ => null,
+ };
+
+ // Go over all types we've seen
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue systemTypeValue && !BindingFlagsAreUnsupported (bindingFlags)) {
+ if (HasBindingFlag (bindingFlags, BindingFlags.Public) && !HasBindingFlag (bindingFlags, BindingFlags.NonPublic)
+ && ctorParameterCount == 0) {
+ MarkPublicParameterlessConstructorOnType (systemTypeValue.RepresentedType);
+ } else {
+ MarkConstructorsOnType (systemTypeValue.RepresentedType, bindingFlags, parameterCount: null);
+ }
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags);
+ // We can scope down the public constructors requirement if we know the number of parameters is 0
+ if (requiredMemberTypes == DynamicallyAccessedMemberTypes.PublicConstructors && ctorParameterCount == 0)
+ requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
+
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, requiredMemberTypes);
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // System.Reflection.MethodInfo
+ //
+ // MakeGenericMethod (Type[] typeArguments)
+ //
+ case IntrinsicId.MethodInfo_MakeGenericMethod: {
+ if (instanceValue.IsEmpty ()) {
+ returnValue = MultiValueLattice.Top;
+ break;
+ }
+
+ foreach (var methodValue in instanceValue) {
+ if (methodValue is SystemReflectionMethodBaseValue methodBaseValue) {
+ ValidateGenericMethodInstantiation (methodBaseValue.RepresentedMethod, argumentValues[0], calledMethod);
+ } else if (methodValue == NullValue.Instance) {
+ // Nothing to do
+ } else {
+ // We don't know what method the `MakeGenericMethod` was called on, so we have to assume
+ // that the method may have requirements which we can't fullfil -> warn.
+ _diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericMethod, calledMethod.GetDisplayName ());
+ }
+ }
+
+ // MakeGenericMethod doesn't change the identity of the MethodBase we're tracking so propagate to the return value
+ AddReturnValue (instanceValue);
+ }
+ break;
+
+ //
+ // System.Activator
+ //
+ // static CreateInstance (System.Type type)
+ // static CreateInstance (System.Type type, bool nonPublic)
+ // static CreateInstance (System.Type type, params object?[]? args)
+ // static CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
+ // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
+ // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
+ //
+ case IntrinsicId.Activator_CreateInstance_Type: {
+ int? ctorParameterCount = null;
+ BindingFlags bindingFlags = BindingFlags.Instance;
+ if (calledMethod.GetParametersCount () > 1) {
+ if (calledMethod.HasParameterOfType (1, "System.Boolean")) {
+ // The overload that takes a "nonPublic" bool
+ bool nonPublic = argumentValues[1].AsConstInt () != 0;
+
+ if (nonPublic)
+ bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
+ else
+ bindingFlags |= BindingFlags.Public;
+ ctorParameterCount = 0;
+ } else {
+ // Overload that has the parameters as the second or fourth argument
+ int argsParam = calledMethod.HasParametersCount (2) || calledMethod.HasParametersCount (3) ? 1 : 3;
+
+ if (argumentValues.Count > argsParam) {
+ if (argumentValues[argsParam].AsSingleValue () is ArrayValue arrayValue &&
+ arrayValue.Size.AsConstInt () != null)
+ ctorParameterCount = arrayValue.Size.AsConstInt ();
+ else if (argumentValues[argsParam].AsSingleValue () is NullValue)
+ ctorParameterCount = 0;
+ }
+
+ if (calledMethod.GetParametersCount () > 3) {
+ if (argumentValues[1].AsConstInt () is int constInt)
+ bindingFlags |= (BindingFlags) constInt;
+ else
+ bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
+ } else {
+ bindingFlags |= BindingFlags.Public;
+ }
+ }
+ } else {
+ // The overload with a single System.Type argument
+ ctorParameterCount = 0;
+ bindingFlags |= BindingFlags.Public;
+ }
+
+ // Go over all types we've seen
+ foreach (var value in argumentValues[0]) {
+ if (value is SystemTypeValue systemTypeValue) {
+ // Special case known type values as we can do better by applying exact binding flags and parameter count.
+ MarkConstructorsOnType (systemTypeValue.RepresentedType, bindingFlags, ctorParameterCount);
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags);
+
+ // Special case the public parameterless constructor if we know that there are 0 args passed in
+ if (ctorParameterCount == 0 && requiredMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors)) {
+ requiredMemberTypes &= ~DynamicallyAccessedMemberTypes.PublicConstructors;
+ requiredMemberTypes |= DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
+ }
+
+ var targetValue = _annotations.GetMethodParameterValue (calledMethod, 0, requiredMemberTypes);
+
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // System.Activator
+ //
+ // static CreateInstance (string assemblyName, string typeName)
+ // static CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
+ // static CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
+ //
+ case IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName:
+ ProcessCreateInstanceByName (calledMethod, argumentValues);
+ break;
+
+ //
+ // System.Activator
+ //
+ // static CreateInstanceFrom (string assemblyFile, string typeName)
+ // static CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // static CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
+ //
+ case IntrinsicId.Activator_CreateInstanceFrom:
+ ProcessCreateInstanceByName (calledMethod, argumentValues);
+ break;
+
+ //
+ // System.AppDomain
+ //
+ // CreateInstance (string assemblyName, string typeName)
+ // CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
+ //
+ // CreateInstanceAndUnwrap (string assemblyName, string typeName)
+ // CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
+ //
+ // CreateInstanceFrom (string assemblyFile, string typeName)
+ // CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
+ //
+ // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
+ // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
+ //
+ case var appDomainCreateInstance when appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstance
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceAndUnwrap
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFrom
+ || appDomainCreateInstance == IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap:
+ ProcessCreateInstanceByName (calledMethod, argumentValues);
+ break;
+
+ //
+ // System.Reflection.Assembly
+ //
+ // CreateInstance (string typeName)
+ // CreateInstance (string typeName, bool ignoreCase)
+ // CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
+ //
+ case IntrinsicId.Assembly_CreateInstance:
+ // For now always fail since we don't track assemblies (dotnet/linker/issues/1947)
+ _diagnosticContext.AddDiagnostic (DiagnosticId.ParametersOfAssemblyCreateInstanceCannotBeAnalyzed, calledMethod.GetDisplayName ());
+ break;
+
+ case IntrinsicId.None:
+ // Verify the argument values match the annotations on the parameter definition
+ if (requiresDataFlowAnalysis) {
+ if (!calledMethod.IsStatic ()) {
+ _requireDynamicallyAccessedMembersAction.Invoke (instanceValue, _annotations.GetMethodThisParameterValue (calledMethod));
+ }
+ for (int argumentIndex = 0; argumentIndex < argumentValues.Count; argumentIndex++) {
+ _requireDynamicallyAccessedMembersAction.Invoke (argumentValues[argumentIndex], _annotations.GetMethodParameterValue (calledMethod, argumentIndex));
+ }
+ }
+ break;
+
+ // Disable warnings for all unimplemented intrinsics. Some intrinsic methods have annotations, but analyzing them
+ // would produce unnecessary warnings even for cases that are intrinsically handled. So we disable handling these calls
+ // until a proper intrinsic handling is made
+ default:
+ methodReturnValue = MultiValueLattice.Top;
+ return true;
+ }
+
+ // For now, if the intrinsic doesn't set a return value, fall back on the annotations.
+ // Note that this will be DynamicallyAccessedMembers.None for the intrinsics which don't return types.
+ returnValue ??= calledMethod.ReturnsVoid () ? MultiValueLattice.Top : annotatedMethodReturnValue;
+
+ if (MethodIsTypeConstructor (calledMethod))
+ returnValue = UnknownValue.Instance;
+
+ // Validate that the return value has the correct annotations as per the method return value annotations
+ if (annotatedMethodReturnValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) {
+ foreach (var uniqueValue in returnValue.Value) {
+ if (uniqueValue is ValueWithDynamicallyAccessedMembers methodReturnValueWithMemberTypes) {
+ if (!methodReturnValueWithMemberTypes.DynamicallyAccessedMemberTypes.HasFlag (annotatedMethodReturnValue.DynamicallyAccessedMemberTypes))
+ throw new InvalidOperationException ($"Internal linker error: in {GetContainingSymbolDisplayName ()} processing call to {calledMethod.GetDisplayName ()} returned value which is not correctly annotated with the expected dynamic member access kinds.");
+ } else if (uniqueValue is SystemTypeValue) {
+ // SystemTypeValue can fullfill any requirement, so it's always valid
+ // The requirements will be applied at the point where it's consumed (passed as a method parameter, set as field value, returned from the method)
+ } else if (uniqueValue == NullValue.Instance) {
+ // NullValue can fulfill any requirements because reflection access to it will typically throw.
+ } else {
+ throw new InvalidOperationException ($"Internal linker error: in {GetContainingSymbolDisplayName ()} processing call to {calledMethod.GetDisplayName ()} returned value which is not correctly annotated with the expected dynamic member access kinds.");
+ }
+ }
+ }
+
+ methodReturnValue = returnValue.Value;
+
+ return true;
+
+ void AddReturnValue (MultiValue value)
+ {
+ returnValue = (returnValue == null) ? value : MultiValueLattice.Meet (returnValue.Value, value);
+ }
+ }
+
+ IEnumerable<MultiValue> ProcessGetMethodByName (TypeProxy type, string methodName, BindingFlags? bindingFlags)
+ {
+ bool foundAny = false;
+ foreach (var method in GetMethodsOnTypeHierarchy (type, methodName, bindingFlags)) {
+ MarkMethod (method.RepresentedMethod);
+ yield return method;
+ foundAny = true;
+ }
+
+ // If there were no methods found the API will return null at runtime, so we should
+ // track the null as a return value as well.
+ // This also prevents warnings in such case, since if we don't set the return value it will be
+ // "unknown" and consumers may warn.
+ if (!foundAny)
+ yield return NullValue.Instance;
+ }
+
+ bool AnalyzeGenericInstantiationTypeArray (in MultiValue arrayParam, in MethodProxy calledMethod, ImmutableArray<GenericParameterValue> genericParameters)
+ {
+ bool hasRequirements = false;
+ foreach (var genericParameter in genericParameters) {
+ if (genericParameter.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) {
+ hasRequirements = true;
+ break;
+ }
+ }
+
+ // If there are no requirements, then there's no point in warning
+ if (!hasRequirements)
+ return true;
+
+ foreach (var typesValue in arrayParam) {
+ if (typesValue is not ArrayValue array) {
+ return false;
+ }
+
+ int? size = array.Size.AsConstInt ();
+ if (size == null || size != genericParameters.Length) {
+ return false;
+ }
+
+ bool allIndicesKnown = true;
+ for (int i = 0; i < size.Value; i++) {
+ if (!array.TryGetValueByIndex (i, out MultiValue value) || value.AsSingleValue () is UnknownValue) {
+ allIndicesKnown = false;
+ break;
+ }
+ }
+
+ if (!allIndicesKnown) {
+ return false;
+ }
+
+ for (int i = 0; i < size.Value; i++) {
+ if (array.TryGetValueByIndex (i, out MultiValue value)) {
+ // https://github.com/dotnet/linker/issues/2428
+ // We need to report the target as "this" - as that was the previous behavior
+ // but with the annotation from the generic parameter.
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, genericParameters[i].DynamicallyAccessedMemberTypes);
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ return true;
+ }
+
+ void ValidateGenericMethodInstantiation (
+ MethodProxy genericMethod,
+ in MultiValue genericParametersArray,
+ MethodProxy reflectionMethod)
+ {
+ if (!genericMethod.HasGenericParameters ()) {
+ return;
+ }
+
+ var genericParameterValues = GetGenericParameterValues (genericMethod.GetGenericParameters ());
+ if (!AnalyzeGenericInstantiationTypeArray (genericParametersArray, reflectionMethod, genericParameterValues)) {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericMethod, reflectionMethod.GetDisplayName ());
+ }
+ }
+
+ ImmutableArray<GenericParameterValue> GetGenericParameterValues (ImmutableArray<GenericParameterProxy> genericParameters)
+ {
+ if (genericParameters.IsEmpty)
+ return ImmutableArray<GenericParameterValue>.Empty;
+
+ var builder = ImmutableArray.CreateBuilder<GenericParameterValue> (genericParameters.Length);
+ foreach (var genericParameter in genericParameters) {
+ builder.Add (_annotations.GetGenericParameterValue (genericParameter));
+ }
+ return builder.ToImmutableArray ();
+ }
+
+ void ProcessCreateInstanceByName (MethodProxy calledMethod, IReadOnlyList<MultiValue> argumentValues)
+ {
+ BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
+ bool parameterlessConstructor = true;
+ if (calledMethod.HasParametersCount (8) && calledMethod.HasParameterOfType (2, "System.Boolean")) {
+ parameterlessConstructor = false;
+ bindingFlags = BindingFlags.Instance;
+ if (argumentValues[3].AsConstInt () is int bindingFlagsInt)
+ bindingFlags |= (BindingFlags) bindingFlagsInt;
+ else
+ bindingFlags |= BindingFlags.Public | BindingFlags.NonPublic;
+ }
+
+ foreach (var assemblyNameValue in argumentValues[0]) {
+ if (assemblyNameValue is KnownStringValue assemblyNameStringValue) {
+ if (assemblyNameStringValue.Contents is string assemblyName && assemblyName.Length == 0) {
+ // Throws exception for zero-length assembly name.
+ continue;
+ }
+ foreach (var typeNameValue in argumentValues[1]) {
+ if (typeNameValue is NullValue) {
+ // Throws exception for null type name.
+ continue;
+ }
+ if (typeNameValue is KnownStringValue typeNameStringValue) {
+ if (!TryResolveTypeNameForCreateInstance (calledMethod, assemblyNameStringValue.Contents, typeNameStringValue.Contents, out TypeProxy resolvedType)) {
+ // It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case
+ // Note that we did find the assembly, so it's not a linker config problem, it's either intentional, or wrong versions of assemblies
+ // but linker can't know that. In case a user tries to create an array using System.Activator we should simply ignore it, the user
+ // might expect an exception to be thrown.
+ continue;
+ }
+
+ MarkConstructorsOnType (resolvedType, bindingFlags, parameterlessConstructor ? 0 : null);
+ } else {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedParameterInMethodCreateInstance, calledMethod.GetParameterDisplayName (1), calledMethod.GetDisplayName ());
+ }
+ }
+ } else {
+ _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedParameterInMethodCreateInstance, calledMethod.GetParameterDisplayName (0), calledMethod.GetDisplayName ());
+ }
+ }
+ }
+
+ internal static BindingFlags? GetBindingFlagsFromValue (in MultiValue parameter) => (BindingFlags?) parameter.AsConstInt ();
+
+ internal static bool BindingFlagsAreUnsupported (BindingFlags? bindingFlags)
+ {
+ if (bindingFlags == null)
+ return true;
+
+ // Binding flags we understand
+ const BindingFlags UnderstoodBindingFlags =
+ BindingFlags.DeclaredOnly |
+ BindingFlags.Instance |
+ BindingFlags.Static |
+ BindingFlags.Public |
+ BindingFlags.NonPublic |
+ BindingFlags.FlattenHierarchy |
+ BindingFlags.ExactBinding;
+
+ // Binding flags that don't affect binding outside InvokeMember (that we don't analyze).
+ const BindingFlags IgnorableBindingFlags =
+ BindingFlags.InvokeMethod |
+ BindingFlags.CreateInstance |
+ BindingFlags.GetField |
+ BindingFlags.SetField |
+ BindingFlags.GetProperty |
+ BindingFlags.SetProperty;
+
+ BindingFlags flags = bindingFlags.Value;
+ return (flags & ~(UnderstoodBindingFlags | IgnorableBindingFlags)) != 0;
+ }
+
+ internal static bool HasBindingFlag (BindingFlags? bindingFlags, BindingFlags? search) => bindingFlags != null && (bindingFlags & search) == search;
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicConstructors : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicMethods : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicFields : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicProperties : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicEvents : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (BindingFlags? bindingFlags) =>
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags);
+
+ /// <Summary>
+ /// Returns true if the method is a .ctor for System.Type or a type that derives from System.Type (i.e. fields and params of this type can have DynamicallyAccessedMembers annotations)
+ /// </Summary>
+ private partial bool MethodIsTypeConstructor (MethodProxy method);
+
+ private partial IEnumerable<SystemReflectionMethodBaseValue> GetMethodsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial IEnumerable<SystemTypeValue> GetNestedTypesOnType (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial bool TryGetBaseType (TypeProxy type, [NotNullWhen (true)] out TypeProxy? baseType);
+
+ private partial bool TryResolveTypeNameForCreateInstance (in MethodProxy calledMethod, string assemblyName, string typeName, out TypeProxy resolvedType);
+
+ private partial void MarkStaticConstructor (TypeProxy type);
+
+ private partial void MarkEventsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial void MarkFieldsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial void MarkPropertiesOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial void MarkPublicParameterlessConstructorOnType (TypeProxy type);
+
+ private partial void MarkConstructorsOnType (TypeProxy type, BindingFlags? bindingFlags, int? parameterCount);
+
+ private partial void MarkMethod (MethodProxy method);
+
+ private partial void MarkType (TypeProxy type);
+
+ private partial bool MarkAssociatedProperty (MethodProxy method);
+
+ // Only used for internal diagnostic purposes (not even for warning messages)
+ private partial string GetContainingSymbolDisplayName ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/IntrinsicId.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/IntrinsicId.cs
new file mode 100644
index 00000000000..7a2a40b068a
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/IntrinsicId.cs
@@ -0,0 +1,71 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ enum IntrinsicId
+ {
+ None = 0,
+ IntrospectionExtensions_GetTypeInfo,
+ Type_GetTypeFromHandle,
+ Type_get_TypeHandle,
+ Object_GetType,
+ TypeDelegator_Ctor,
+ Array_Empty,
+ TypeInfo_AsType,
+ MethodBase_GetMethodFromHandle,
+ MethodBase_get_MethodHandle,
+
+ // Anything above this marker will require the method to be run through
+ // the reflection body scanner.
+ RequiresReflectionBodyScanner_Sentinel = 1000,
+ Type_MakeGenericType,
+ Type_GetType,
+ Type_GetConstructor,
+ Type_GetConstructors,
+ Type_GetMethod,
+ Type_GetMethods,
+ Type_GetField,
+ Type_GetFields,
+ Type_GetProperty,
+ Type_GetProperties,
+ Type_GetEvent,
+ Type_GetEvents,
+ Type_GetNestedType,
+ Type_GetNestedTypes,
+ Type_GetMember,
+ Type_GetMembers,
+ Type_GetInterface,
+ Type_get_AssemblyQualifiedName,
+ Type_get_UnderlyingSystemType,
+ Type_get_BaseType,
+ Expression_Call,
+ Expression_Field,
+ Expression_Property,
+ Expression_New,
+ Enum_GetValues,
+ Marshal_SizeOf,
+ Marshal_OffsetOf,
+ Marshal_PtrToStructure,
+ Marshal_DestroyStructure,
+ Marshal_GetDelegateForFunctionPointer,
+ Activator_CreateInstance_Type,
+ Activator_CreateInstance_AssemblyName_TypeName,
+ Activator_CreateInstanceFrom,
+ AppDomain_CreateInstance,
+ AppDomain_CreateInstanceAndUnwrap,
+ AppDomain_CreateInstanceFrom,
+ AppDomain_CreateInstanceFromAndUnwrap,
+ Assembly_CreateInstance,
+ RuntimeReflectionExtensions_GetRuntimeEvent,
+ RuntimeReflectionExtensions_GetRuntimeField,
+ RuntimeReflectionExtensions_GetRuntimeMethod,
+ RuntimeReflectionExtensions_GetRuntimeProperty,
+ RuntimeHelpers_RunClassConstructor,
+ MethodInfo_MakeGenericMethod,
+ Nullable_GetUnderlyingType
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/Intrinsics.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/Intrinsics.cs
new file mode 100644
index 00000000000..872f943e9fa
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/Intrinsics.cs
@@ -0,0 +1,378 @@
+// 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 ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ static class Intrinsics
+ {
+ public static IntrinsicId GetIntrinsicIdForMethod (MethodProxy calledMethod)
+ {
+ return calledMethod.Name switch {
+ // static System.Reflection.IntrospectionExtensions.GetTypeInfo (Type type)
+ "GetTypeInfo" when calledMethod.IsDeclaredOnType ("System.Reflection.IntrospectionExtensions") => IntrinsicId.IntrospectionExtensions_GetTypeInfo,
+
+ // System.Reflection.TypeInfo.AsType ()
+ "AsType" when calledMethod.IsDeclaredOnType ("System.Reflection.TypeInfo") => IntrinsicId.TypeInfo_AsType,
+
+ // System.Type.GetTypeInfo (Type type)
+ "GetTypeFromHandle" when calledMethod.IsDeclaredOnType ("System.Type") => IntrinsicId.Type_GetTypeFromHandle,
+
+ // System.Type.TypeHandle getter
+ "get_TypeHandle" when calledMethod.IsDeclaredOnType ("System.Type") => IntrinsicId.Type_get_TypeHandle,
+
+ // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
+ // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
+ "GetMethodFromHandle" when calledMethod.IsDeclaredOnType ("System.Reflection.MethodBase")
+ && calledMethod.HasParameterOfType (0, "System.RuntimeMethodHandle")
+ && (calledMethod.HasParametersCount (1) || calledMethod.HasParametersCount (2))
+ => IntrinsicId.MethodBase_GetMethodFromHandle,
+
+ // System.Reflection.MethodBase.MethodHandle getter
+ "get_MethodHandle" when calledMethod.IsDeclaredOnType ("System.Reflection.MethodBase") => IntrinsicId.MethodBase_get_MethodHandle,
+
+ // static System.Type.MakeGenericType (Type [] typeArguments)
+ "MakeGenericType" when calledMethod.IsDeclaredOnType ("System.Type") => IntrinsicId.Type_MakeGenericType,
+
+ // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeEvent (this Type type, string name)
+ "GetRuntimeEvent" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent,
+
+ // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeField (this Type type, string name)
+ "GetRuntimeField" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParameterOfType (1, "System.,String")
+ => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField,
+
+ // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeMethod (this Type type, string name, Type[] parameters)
+ "GetRuntimeMethod" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod,
+
+ // static System.Reflection.RuntimeReflectionExtensions.GetRuntimeProperty (this Type type, string name)
+ "GetRuntimeProperty" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty,
+
+ // static System.Linq.Expressions.Expression.Call (Type, String, Type[], Expression[])
+ "Call" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParametersCount (4)
+ => IntrinsicId.Expression_Call,
+
+ // static System.Linq.Expressions.Expression.Field (Expression, Type, String)
+ "Field" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
+ && calledMethod.HasParameterOfType (1, "System.Type")
+ && calledMethod.HasParametersCount (3)
+ => IntrinsicId.Expression_Field,
+
+ // static System.Linq.Expressions.Expression.Property (Expression, Type, String)
+ // static System.Linq.Expressions.Expression.Property (Expression, MethodInfo)
+ "Property" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
+ && ((calledMethod.HasParameterOfType (1, "System.Type") && calledMethod.HasParametersCount (3))
+ || (calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo") && calledMethod.HasParametersCount (2)))
+ => IntrinsicId.Expression_Property,
+
+ // static System.Linq.Expressions.Expression.New (Type)
+ "New" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParametersCount (1)
+ => IntrinsicId.Expression_New,
+
+ // static Array System.Enum.GetValues (Type)
+ "GetValues" when calledMethod.IsDeclaredOnType ("System.Enum")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParametersCount (1)
+ => IntrinsicId.Enum_GetValues,
+
+ // static int System.Runtime.InteropServices.Marshal.SizeOf (Type)
+ "SizeOf" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParametersCount (1)
+ => IntrinsicId.Marshal_SizeOf,
+
+ // static int System.Runtime.InteropServices.Marshal.OffsetOf (Type, string)
+ "OffsetOf" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParametersCount (2)
+ => IntrinsicId.Marshal_OffsetOf,
+
+ // static object System.Runtime.InteropServices.Marshal.PtrToStructure (IntPtr, Type)
+ "PtrToStructure" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
+ && calledMethod.HasParameterOfType (1, "System.Type")
+ && calledMethod.HasParametersCount (2)
+ => IntrinsicId.Marshal_PtrToStructure,
+
+ // static void System.Runtime.InteropServices.Marshal.DestroyStructure (IntPtr, Type)
+ "DestroyStructure" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
+ && calledMethod.HasParameterOfType (1, "System.Type")
+ && calledMethod.HasParametersCount (2)
+ => IntrinsicId.Marshal_DestroyStructure,
+
+ // static Delegate System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer (IntPtr, Type)
+ "GetDelegateForFunctionPointer" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
+ && calledMethod.HasParameterOfType (1, "System.Type")
+ && calledMethod.HasParametersCount (2)
+ => IntrinsicId.Marshal_GetDelegateForFunctionPointer,
+
+ // static System.Type.GetType (string)
+ // static System.Type.GetType (string, Boolean)
+ // static System.Type.GetType (string, Boolean, Boolean)
+ // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>)
+ // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
+ // static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
+ "GetType" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ => IntrinsicId.Type_GetType,
+
+ // System.Type.GetConstructor (Type[])
+ // System.Type.GetConstructor (BindingFlags, Type[])
+ // System.Type.GetConstructor (BindingFlags, Binder, Type[], ParameterModifier [])
+ // System.Type.GetConstructor (BindingFlags, Binder, CallingConventions, Type[], ParameterModifier [])
+ "GetConstructor" when calledMethod.IsDeclaredOnType ("System.Type")
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetConstructor,
+
+ // System.Type.GetConstructors (BindingFlags)
+ "GetConstructors" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && calledMethod.HasParametersCount (1)
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetConstructors,
+
+ // System.Type.GetMethod (string)
+ // System.Type.GetMethod (string, BindingFlags)
+ // System.Type.GetMethod (string, Type[])
+ // System.Type.GetMethod (string, Type[], ParameterModifier[])
+ // System.Type.GetMethod (string, BindingFlags, Type[])
+ // System.Type.GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
+ // System.Type.GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
+ // System.Type.GetMethod (string, int, Type[])
+ // System.Type.GetMethod (string, int, Type[], ParameterModifier[]?)
+ // System.Type.GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
+ // System.Type.GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
+ "GetMethod" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetMethod,
+
+ // System.Type.GetMethods (BindingFlags)
+ "GetMethods" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && calledMethod.HasParametersCount (1)
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetMethods,
+
+ // System.Type.GetField (string)
+ // System.Type.GetField (string, BindingFlags)
+ "GetField" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetField,
+
+ // System.Type.GetFields (BindingFlags)
+ "GetFields" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && calledMethod.HasParametersCount (1)
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetFields,
+
+ // System.Type.GetEvent (string)
+ // System.Type.GetEvent (string, BindingFlags)
+ "GetEvent" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetEvent,
+
+ // System.Type.GetEvents (BindingFlags)
+ "GetEvents" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && calledMethod.HasParametersCount (1)
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetEvents,
+
+ // System.Type.GetNestedType (string)
+ // System.Type.GetNestedType (string, BindingFlags)
+ "GetNestedType" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetNestedType,
+
+ // System.Type.GetNestedTypes (BindingFlags)
+ "GetNestedTypes" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && calledMethod.HasParametersCount (1)
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetNestedTypes,
+
+ // System.Type.GetMember (String)
+ // System.Type.GetMember (String, BindingFlags)
+ // System.Type.GetMember (String, MemberTypes, BindingFlags)
+ "GetMember" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic ()
+ && (calledMethod.HasParametersCount (1) ||
+ (calledMethod.HasParametersCount (2) && calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags")) ||
+ (calledMethod.HasParametersCount (3) && calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags")))
+ => IntrinsicId.Type_GetMember,
+
+ // System.Type.GetMembers (BindingFlags)
+ "GetMembers" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && calledMethod.HasParametersCount (1)
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetMembers,
+
+ // System.Type.GetInterface (string)
+ // System.Type.GetInterface (string, bool)
+ "GetInterface" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic ()
+ && (calledMethod.HasParametersCount (1) ||
+ (calledMethod.HasParametersCount (2) && calledMethod.HasParameterOfType (1, "System.Boolean")))
+ => IntrinsicId.Type_GetInterface,
+
+ // System.Type.AssemblyQualifiedName
+ "get_AssemblyQualifiedName" when calledMethod.IsDeclaredOnType ("System.Type")
+ && !calledMethod.HasParameters ()
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_get_AssemblyQualifiedName,
+
+ // System.Type.UnderlyingSystemType
+ "get_UnderlyingSystemType" when calledMethod.IsDeclaredOnType ("System.Type")
+ && !calledMethod.HasParameters ()
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_get_UnderlyingSystemType,
+
+ // System.Type.BaseType
+ "get_BaseType" when calledMethod.IsDeclaredOnType ("System.Type")
+ && !calledMethod.HasParameters ()
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_get_BaseType,
+
+ // System.Type.GetProperty (string)
+ // System.Type.GetProperty (string, BindingFlags)
+ // System.Type.GetProperty (string, Type)
+ // System.Type.GetProperty (string, Type[])
+ // System.Type.GetProperty (string, Type, Type[])
+ // System.Type.GetProperty (string, Type, Type[], ParameterModifier[])
+ // System.Type.GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
+ "GetProperty" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetProperty,
+
+ // System.Type.GetProperties (BindingFlags)
+ "GetProperties" when calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && calledMethod.HasParametersCount (1)
+ && !calledMethod.IsStatic ()
+ => IntrinsicId.Type_GetProperties,
+
+ // static System.Object.GetType ()
+ "GetType" when calledMethod.IsDeclaredOnType ("System.Object")
+ => IntrinsicId.Object_GetType,
+
+ ".ctor" when calledMethod.IsDeclaredOnType ("System.Reflection.TypeDelegator")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ => IntrinsicId.TypeDelegator_Ctor,
+
+ "Empty" when calledMethod.IsDeclaredOnType ("System.Array")
+ => IntrinsicId.Array_Empty,
+
+ // static System.Activator.CreateInstance (System.Type type)
+ // static System.Activator.CreateInstance (System.Type type, bool nonPublic)
+ // static System.Activator.CreateInstance (System.Type type, params object?[]? args)
+ // static System.Activator.CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
+ // static System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
+ // static System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
+ "CreateInstance" when calledMethod.IsDeclaredOnType ("System.Activator")
+ && !calledMethod.HasGenericParameters ()
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ => IntrinsicId.Activator_CreateInstance_Type,
+
+ // static System.Activator.CreateInstance (string assemblyName, string typeName)
+ // static System.Activator.CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
+ // static System.Activator.CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
+ "CreateInstance" when calledMethod.IsDeclaredOnType ("System.Activator")
+ && !calledMethod.HasGenericParameters ()
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.Activator_CreateInstance_AssemblyName_TypeName,
+
+ // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName)
+ // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
+ "CreateInstanceFrom" when calledMethod.IsDeclaredOnType ("System.Activator")
+ && !calledMethod.HasGenericParameters ()
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.Activator_CreateInstanceFrom,
+
+ // System.AppDomain.CreateInstance (string assemblyName, string typeName)
+ // System.AppDomain.CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // System.AppDomain.CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
+ "CreateInstance" when calledMethod.IsDeclaredOnType ("System.AppDomain")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.AppDomain_CreateInstance,
+
+ // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName)
+ // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
+ "CreateInstanceAndUnwrap" when calledMethod.IsDeclaredOnType ("System.AppDomain")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.AppDomain_CreateInstanceAndUnwrap,
+
+ // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName)
+ // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
+ "CreateInstanceFrom" when calledMethod.IsDeclaredOnType ("System.AppDomain")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.AppDomain_CreateInstanceFrom,
+
+ // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
+ // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
+ "CreateInstanceFromAndUnwrap" when calledMethod.IsDeclaredOnType ("System.AppDomain")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType (1, "System.String")
+ => IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap,
+
+ // System.Reflection.Assembly.CreateInstance (string typeName)
+ // System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase)
+ // System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
+ "CreateInstance" when calledMethod.IsDeclaredOnType ("System.Reflection.Assembly")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ => IntrinsicId.Assembly_CreateInstance,
+
+ // System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (RuntimeTypeHandle type)
+ "RunClassConstructor" when calledMethod.IsDeclaredOnType ("System.Runtime.CompilerServices.RuntimeHelpers")
+ && calledMethod.HasParameterOfType (0, "System.RuntimeTypeHandle")
+ => IntrinsicId.RuntimeHelpers_RunClassConstructor,
+
+ // System.Reflection.MethodInfo.MakeGenericMethod (Type[] typeArguments)
+ "MakeGenericMethod" when calledMethod.IsDeclaredOnType ("System.Reflection.MethodInfo")
+ && !calledMethod.IsStatic ()
+ && calledMethod.HasParametersCount (1)
+ => IntrinsicId.MethodInfo_MakeGenericMethod,
+
+ "GetUnderlyingType" when calledMethod.IsDeclaredOnType ("System.Nullable")
+ && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.IsStatic ()
+ => IntrinsicId.Nullable_GetUnderlyingType,
+ _ => IntrinsicId.None,
+ };
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/KnownStringValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/KnownStringValue.cs
new file mode 100644
index 00000000000..bbdedf5bf02
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/KnownStringValue.cs
@@ -0,0 +1,24 @@
+// 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 ILLink.Shared.DataFlow;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// A known string - such as the result of a ldstr.
+ /// </summary>
+ sealed partial record KnownStringValue : SingleValue
+ {
+ public KnownStringValue (string contents) => Contents = contents;
+
+ public readonly string Contents;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString ("\"" + Contents + "\"");
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs
new file mode 100644
index 00000000000..8d2b4a6a64b
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs
@@ -0,0 +1,10 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ sealed partial record MethodParameterValue : ValueWithDynamicallyAccessedMembers;
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodReturnValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodReturnValue.cs
new file mode 100644
index 00000000000..708b5f469c3
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodReturnValue.cs
@@ -0,0 +1,10 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ sealed partial record class MethodReturnValue : ValueWithDynamicallyAccessedMembers;
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs
new file mode 100644
index 00000000000..baf12d256d8
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs
@@ -0,0 +1,10 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ sealed partial record MethodThisParameterValue : ValueWithDynamicallyAccessedMembers;
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullValue.cs
new file mode 100644
index 00000000000..90afd5a8792
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullValue.cs
@@ -0,0 +1,23 @@
+// 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 ILLink.Shared.DataFlow;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ sealed record NullValue : SingleValue
+ {
+ private NullValue ()
+ {
+ }
+
+ public static NullValue Instance { get; } = new NullValue ();
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableSystemTypeValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableSystemTypeValue.cs
new file mode 100644
index 00000000000..1f54cc2779b
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableSystemTypeValue.cs
@@ -0,0 +1,33 @@
+// 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.Diagnostics;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This represents a Nullable<T> where T is a known SystemTypeValue.
+ /// It is necessary to track the underlying type to propagate DynamicallyAccessedMembers annotations to the underlying type when applied to a Nullable.
+ /// </summary>
+ sealed record NullableSystemTypeValue : SingleValue
+ {
+ public NullableSystemTypeValue (in TypeProxy nullableType, in SystemTypeValue underlyingTypeValue)
+ {
+ Debug.Assert (nullableType.IsTypeOf (WellKnownType.System_Nullable_T));
+ UnderlyingTypeValue = underlyingTypeValue;
+ NullableType = nullableType;
+ }
+ public readonly TypeProxy NullableType;
+
+ public readonly SystemTypeValue UnderlyingTypeValue;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (UnderlyingTypeValue, NullableType);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableValueWithDynamicallyAccessedMembers.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableValueWithDynamicallyAccessedMembers.cs
new file mode 100644
index 00000000000..4c09d6f7f17
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/NullableValueWithDynamicallyAccessedMembers.cs
@@ -0,0 +1,39 @@
+// 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.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This represents a Nullable<T> where T is an unknown value with DynamicallyAccessedMembers annotations.
+ /// It is necessary to track the underlying type to ensure DynamicallyAccessedMembers annotations on the underlying type match the target parameters where the Nullable is used.
+ /// </summary>
+ sealed record NullableValueWithDynamicallyAccessedMembers : ValueWithDynamicallyAccessedMembers
+ {
+ public NullableValueWithDynamicallyAccessedMembers (in TypeProxy nullableType, in ValueWithDynamicallyAccessedMembers underlyingTypeValue)
+ {
+ Debug.Assert (nullableType.IsTypeOf (WellKnownType.System_Nullable_T));
+ NullableType = nullableType;
+ UnderlyingTypeValue = underlyingTypeValue;
+ }
+
+ public readonly TypeProxy NullableType;
+ public readonly ValueWithDynamicallyAccessedMembers UnderlyingTypeValue;
+
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes => UnderlyingTypeValue.DynamicallyAccessedMemberTypes;
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => UnderlyingTypeValue.GetDiagnosticArgumentsForAnnotationMismatch ();
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (UnderlyingTypeValue, NullableType);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs
new file mode 100644
index 00000000000..9eb5db78804
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs
@@ -0,0 +1,72 @@
+// 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.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Runtime.InteropServices;
+using ILLink.Shared.TypeSystemProxy;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ [StructLayout (LayoutKind.Auto)]
+ partial struct RequireDynamicallyAccessedMembersAction
+ {
+ readonly DiagnosticContext _diagnosticContext;
+
+ public void Invoke (in MultiValue value, ValueWithDynamicallyAccessedMembers targetValue)
+ {
+ if (targetValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None)
+ return;
+
+ foreach (var uniqueValue in value) {
+ if (targetValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.PublicParameterlessConstructor
+ && uniqueValue is GenericParameterValue genericParam
+ && genericParam.GenericParameter.HasDefaultConstructorConstraint ()) {
+ // We allow a new() constraint on a generic parameter to satisfy DynamicallyAccessedMemberTypes.PublicParameterlessConstructor
+ } else if (uniqueValue is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers) {
+ if (uniqueValue is NullableValueWithDynamicallyAccessedMembers nullableValue) {
+ MarkTypeForDynamicallyAccessedMembers (nullableValue.NullableType, nullableValue.DynamicallyAccessedMemberTypes);
+ }
+ var availableMemberTypes = valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes;
+ if (!Annotations.SourceHasRequiredAnnotations (availableMemberTypes, targetValue.DynamicallyAccessedMemberTypes, out var missingMemberTypes)) {
+ (var diagnosticId, var diagnosticArguments) = Annotations.GetDiagnosticForAnnotationMismatch (valueWithDynamicallyAccessedMembers, targetValue, missingMemberTypes);
+ _diagnosticContext.AddDiagnostic (diagnosticId, diagnosticArguments);
+ }
+ } else if (uniqueValue is SystemTypeValue systemTypeValue) {
+ MarkTypeForDynamicallyAccessedMembers (systemTypeValue.RepresentedType, targetValue.DynamicallyAccessedMemberTypes);
+ } else if (uniqueValue is KnownStringValue knownStringValue) {
+ if (!TryResolveTypeNameAndMark (knownStringValue.Contents, true, out TypeProxy foundType)) {
+ // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
+ } else {
+ MarkTypeForDynamicallyAccessedMembers (foundType, targetValue.DynamicallyAccessedMemberTypes);
+ }
+ } else if (uniqueValue is NullableSystemTypeValue nullableSystemTypeValue) {
+ MarkTypeForDynamicallyAccessedMembers (nullableSystemTypeValue.NullableType, targetValue.DynamicallyAccessedMemberTypes);
+ MarkTypeForDynamicallyAccessedMembers (nullableSystemTypeValue.UnderlyingTypeValue.RepresentedType, targetValue.DynamicallyAccessedMemberTypes);
+ } else if (uniqueValue == NullValue.Instance) {
+ // Ignore - probably unreachable path as it would fail at runtime anyway.
+ } else {
+ DiagnosticId diagnosticId = targetValue switch {
+ MethodParameterValue => DiagnosticId.MethodParameterCannotBeStaticallyDetermined,
+ MethodReturnValue => DiagnosticId.MethodReturnValueCannotBeStaticallyDetermined,
+ FieldValue => DiagnosticId.FieldValueCannotBeStaticallyDetermined,
+ MethodThisParameterValue => DiagnosticId.ImplicitThisCannotBeStaticallyDetermined,
+ GenericParameterValue => DiagnosticId.TypePassedToGenericParameterCannotBeStaticallyDetermined,
+ _ => throw new NotImplementedException ($"unsupported target value {targetValue}")
+ };
+
+ _diagnosticContext.AddDiagnostic (diagnosticId, targetValue.GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ());
+ }
+ }
+ }
+
+ public partial bool TryResolveTypeNameAndMark (string typeName, bool needsAssemblyName, out TypeProxy type);
+
+ private partial void MarkTypeForDynamicallyAccessedMembers (in TypeProxy type, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeMethodHandleValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeMethodHandleValue.cs
new file mode 100644
index 00000000000..7ef048f224b
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeMethodHandleValue.cs
@@ -0,0 +1,28 @@
+// 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 ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is the System.RuntimeMethodHandle equivalent to a <see cref="SystemReflectionMethodBaseValue"/> node.
+ /// </summary>
+ sealed partial record RuntimeMethodHandleValue : SingleValue
+ {
+ public RuntimeMethodHandleValue (in MethodProxy representedMethod)
+ {
+ RepresentedMethod = representedMethod;
+ }
+
+ public readonly MethodProxy RepresentedMethod;
+
+ public override SingleValue DeepCopy () => this; // immutable value
+
+ public override string ToString () => this.ValueToString ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForGenericParameterValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForGenericParameterValue.cs
new file mode 100644
index 00000000000..1eb108e5fae
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForGenericParameterValue.cs
@@ -0,0 +1,25 @@
+// 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 ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is the System.RuntimeTypeHandle equivalent to a <see cref="GenericParameterValue"/> node.
+ /// </summary>
+ sealed record RuntimeTypeHandleForGenericParameterValue : SingleValue
+ {
+ public readonly GenericParameterProxy GenericParameter;
+
+ public RuntimeTypeHandleForGenericParameterValue (GenericParameterProxy genericParameter) => GenericParameter = genericParameter;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (GenericParameter);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableSystemTypeValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableSystemTypeValue.cs
new file mode 100644
index 00000000000..c92d4274b2d
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableSystemTypeValue.cs
@@ -0,0 +1,33 @@
+// 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.Diagnostics;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This represents a type handle Nullable<T> where T is a known SystemTypeValue.
+ /// It is necessary to track the underlying type to propagate DynamicallyAccessedMembers annotations to the underlying type when applied to a Nullable.
+ /// </summary>
+ sealed record RuntimeTypeHandleForNullableSystemTypeValue : SingleValue
+ {
+ public RuntimeTypeHandleForNullableSystemTypeValue (in TypeProxy nullableType, in SystemTypeValue underlyingTypeValue)
+ {
+ Debug.Assert (nullableType.IsTypeOf (WellKnownType.System_Nullable_T));
+ UnderlyingTypeValue = underlyingTypeValue;
+ NullableType = nullableType;
+ }
+ public readonly TypeProxy NullableType;
+
+ public readonly SystemTypeValue UnderlyingTypeValue;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (UnderlyingTypeValue, NullableType);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers.cs
new file mode 100644
index 00000000000..b4b0653931d
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers.cs
@@ -0,0 +1,33 @@
+// 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.Diagnostics;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This represents a type handle of a Nullable<T> where T is an unknown value with DynamicallyAccessedMembers annotations.
+ /// It is necessary to track the underlying type to ensure DynamicallyAccessedMembers annotations on the underlying type match the target parameters where the Nullable is used.
+ /// </summary>
+ sealed record RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers : SingleValue
+ {
+ public RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers (in TypeProxy nullableType, in SingleValue underlyingTypeValue)
+ {
+ Debug.Assert (nullableType.IsTypeOf (WellKnownType.System_Nullable_T));
+ NullableType = nullableType;
+ UnderlyingTypeValue = underlyingTypeValue;
+ }
+
+ public readonly TypeProxy NullableType;
+ public readonly SingleValue UnderlyingTypeValue;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable }
+
+ public override string ToString () => this.ValueToString (UnderlyingTypeValue, NullableType);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleValue.cs
new file mode 100644
index 00000000000..c508c1f784d
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/RuntimeTypeHandleValue.cs
@@ -0,0 +1,28 @@
+// 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 ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is the System.RuntimeTypeHandle equivalent to a <see cref="SystemTypeValue"/> node.
+ /// </summary>
+ sealed record RuntimeTypeHandleValue : SingleValue
+ {
+ public RuntimeTypeHandleValue (in TypeProxy representedType)
+ {
+ RepresentedType = representedType;
+ }
+
+ public readonly TypeProxy RepresentedType;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (RepresentedType);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs
new file mode 100644
index 00000000000..3ef755cb7aa
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs
@@ -0,0 +1,25 @@
+// 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 ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is a known System.Reflection.MethodBase value. MethodRepresented is the 'value' of the MethodBase.
+ /// </summary>
+ sealed partial record SystemReflectionMethodBaseValue : SingleValue
+ {
+ public SystemReflectionMethodBaseValue (MethodProxy representedMethod) => RepresentedMethod = representedMethod;
+
+ public readonly MethodProxy RepresentedMethod;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (RepresentedMethod);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemTypeValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemTypeValue.cs
new file mode 100644
index 00000000000..71af91c4e56
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/SystemTypeValue.cs
@@ -0,0 +1,28 @@
+// 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 ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ /// <summary>
+ /// This is a known System.Type value. TypeRepresented is the 'value' of the System.Type.
+ /// </summary>
+ sealed record SystemTypeValue : SingleValue
+ {
+ public SystemTypeValue (in TypeProxy representedType)
+ {
+ RepresentedType = representedType;
+ }
+
+ public readonly TypeProxy RepresentedType;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString (RepresentedType);
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/UnknownValue.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/UnknownValue.cs
new file mode 100644
index 00000000000..7dc49dc6662
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/UnknownValue.cs
@@ -0,0 +1,23 @@
+// 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 ILLink.Shared.DataFlow;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ sealed record UnknownValue : SingleValue
+ {
+ private UnknownValue ()
+ {
+ }
+
+ public static UnknownValue Instance { get; } = new UnknownValue ();
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public override string ToString () => this.ValueToString ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueExtensions.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueExtensions.cs
new file mode 100644
index 00000000000..d9358f2910f
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueExtensions.cs
@@ -0,0 +1,59 @@
+// 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.Linq;
+using System.Text;
+using ILLink.Shared.DataFlow;
+using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ static partial class ValueExtensions
+ {
+ internal static string ValueToString (this SingleValue value, params object[] args)
+ {
+ if (value == null)
+ return "<null>";
+
+ StringBuilder sb = new ();
+ sb.Append (value.GetType ().Name);
+ sb.Append ("(");
+ if (args != null) {
+ for (int i = 0; i < args.Length; i++) {
+ if (i > 0)
+ sb.Append (",");
+ sb.Append (args[i] == null ? "<null>" : args[i].ToString ());
+ }
+ }
+ sb.Append (")");
+ return sb.ToString ();
+ }
+
+ internal static int? AsConstInt (this SingleValue value)
+ {
+ if (value is ConstIntValue constInt)
+ return constInt.Value;
+
+ return null;
+ }
+
+ internal static int? AsConstInt (this in MultiValue value)
+ {
+ if (value.AsSingleValue () is ConstIntValue constInt)
+ return constInt.Value;
+
+ return null;
+ }
+
+ internal static SingleValue? AsSingleValue (this in MultiValue node)
+ {
+ if (node.Count () != 1)
+ return null;
+
+ return node.Single ();
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueWithDynamicallyAccessedMembers.cs b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueWithDynamicallyAccessedMembers.cs
new file mode 100644
index 00000000000..c67d30040d2
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TrimAnalysis/ValueWithDynamicallyAccessedMembers.cs
@@ -0,0 +1,19 @@
+// 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.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.DataFlow;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ public abstract record ValueWithDynamicallyAccessedMembers : SingleValue
+ {
+ public abstract DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
+
+ public abstract IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/GenericParameterProxy.cs b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/GenericParameterProxy.cs
new file mode 100644
index 00000000000..09ddbc4ae05
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/GenericParameterProxy.cs
@@ -0,0 +1,13 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal readonly partial struct GenericParameterProxy
+ {
+ internal partial bool HasDefaultConstructorConstraint ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/IMemberProxy.cs b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/IMemberProxy.cs
new file mode 100644
index 00000000000..3e358b9a5b8
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/IMemberProxy.cs
@@ -0,0 +1,15 @@
+// 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.
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ interface IMemberProxy
+ {
+ public string Name { get; }
+
+ public string GetDisplayName ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/MethodProxy.cs b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/MethodProxy.cs
new file mode 100644
index 00000000000..a30ce2200e3
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/MethodProxy.cs
@@ -0,0 +1,29 @@
+// 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.Collections.Immutable;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal readonly partial struct MethodProxy : IMemberProxy
+ {
+ // Currently this only needs to work on non-nested, non-generic types.
+ // The format of the fullTypeName parameter is 'namespace.typename', so for example 'System.Reflection.Assembly'
+ internal partial bool IsDeclaredOnType (string fullTypeName);
+ internal partial bool HasParameters ();
+ internal partial int GetParametersCount ();
+ internal bool HasParametersCount (int parameterCount) => GetParametersCount () == parameterCount;
+ // Currently this only needs to work on non-nested, non-generic types.
+ // The format of the fullTypeName parameter is 'namespace.typename', so for example 'System.Reflection.Assembly'
+ internal partial bool HasParameterOfType (int parameterIndex, string fullTypeName);
+ internal partial string GetParameterDisplayName (int parameterIndex);
+ internal partial bool HasGenericParameters ();
+ internal partial bool HasGenericParametersCount (int genericParameterCount);
+ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ();
+ internal partial bool IsStatic ();
+ internal partial bool ReturnsVoid ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/TypeProxy.cs b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/TypeProxy.cs
new file mode 100644
index 00000000000..0c459f05df2
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/TypeProxy.cs
@@ -0,0 +1,15 @@
+// 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.Collections.Immutable;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal readonly partial struct TypeProxy : IMemberProxy
+ {
+ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ();
+ }
+}
diff --git a/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/WellKnownType.cs b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/WellKnownType.cs
new file mode 100644
index 00000000000..9d6f580c06d
--- /dev/null
+++ b/src/coreclr/tools/aot/ILLink.Shared/TypeSystemProxy/WellKnownType.cs
@@ -0,0 +1,71 @@
+// 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;
+
+// This is needed due to NativeAOT which doesn't enable nullable globally yet
+#nullable enable
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ public enum WellKnownType
+ {
+ System_String,
+ System_Nullable_T,
+ System_Type,
+ System_Reflection_IReflect,
+ System_Array,
+ System_Object,
+ System_Attribute,
+ System_NotSupportedException,
+ System_Runtime_CompilerServices_DisablePrivateReflectionAttribute,
+ System_Void
+ }
+
+ public static partial class WellKnownTypeExtensions
+ {
+ public static (string Namespace, string Name) GetNamespaceAndName (this WellKnownType type)
+ {
+ return type switch {
+ WellKnownType.System_String => ("System", "String"),
+ WellKnownType.System_Nullable_T => ("System", "Nullable`1"),
+ WellKnownType.System_Type => ("System", "Type"),
+ WellKnownType.System_Reflection_IReflect => ("System.Reflection", "IReflect"),
+ WellKnownType.System_Array => ("System", "Array"),
+ WellKnownType.System_Object => ("System", "Object"),
+ WellKnownType.System_Attribute => ("System", "Attribute"),
+ WellKnownType.System_NotSupportedException => ("System", "NotSupportedException"),
+ WellKnownType.System_Runtime_CompilerServices_DisablePrivateReflectionAttribute => ("System.Runtime.CompilerServices", "DisablePrivateReflectionAttribute"),
+ WellKnownType.System_Void => ("System", "Void"),
+ _ => throw new ArgumentException ($"{nameof (type)} is not a well-known type."),
+ };
+ }
+ public static string GetNamespace (this WellKnownType type) => GetNamespaceAndName (type).Namespace;
+ public static string GetName (this WellKnownType type) => GetNamespaceAndName (type).Name;
+ public static WellKnownType? GetWellKnownType (string @namespace, string name)
+ {
+ return @namespace switch {
+ "System" => name switch {
+ "String" => WellKnownType.System_String,
+ "Nullable`1" => WellKnownType.System_Nullable_T,
+ "Type" => WellKnownType.System_Type,
+ "Array" => WellKnownType.System_Array,
+ "Attribute" => WellKnownType.System_Attribute,
+ "Object" => WellKnownType.System_Object,
+ "NotSupportedException" => WellKnownType.System_NotSupportedException,
+ "Void" => WellKnownType.System_Void,
+ _ => null
+ },
+ "System.Reflection" => name switch {
+ "IReflect" => WellKnownType.System_Reflection_IReflect,
+ _ => null
+ },
+ "System.Runtime.CompilerServices" => name switch {
+ "DisablePrivateReflectionAttribute" => WellKnownType.System_Runtime_CompilerServices_DisablePrivateReflectionAttribute,
+ _ => null
+ },
+ _ => null
+ };
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs
index 3302cf5be43..8667b0bb1ee 100644
--- a/src/coreclr/tools/aot/crossgen2/Program.cs
+++ b/src/coreclr/tools/aot/crossgen2/Program.cs
@@ -472,7 +472,10 @@ namespace ILCompiler
{
try
{
- EcmaModule module = _typeSystemContext.GetModuleFromPath(referenceFile);
+ EcmaModule module = _typeSystemContext.GetModuleFromPath(referenceFile, throwOnFailureToLoad: false);
+ if (module == null)
+ continue;
+
_referenceableModules.Add(module);
if (_commandLineOptions.InputBubble && _inputbubblereferenceFilePaths.Count == 0)
{
@@ -490,7 +493,11 @@ namespace ILCompiler
{
try
{
- EcmaModule module = _typeSystemContext.GetModuleFromPath(referenceFile);
+ EcmaModule module = _typeSystemContext.GetModuleFromPath(referenceFile, throwOnFailureToLoad: false);
+
+ if (module == null)
+ continue;
+
versionBubbleModulesHash.Add(module);
}
catch { } // Ignore non-managed pe files
@@ -623,39 +630,30 @@ namespace ILCompiler
ReadyToRunCompilationModuleGroupBase compilationGroup;
List<ICompilationRootProvider> compilationRoots = new List<ICompilationRootProvider>();
+ ReadyToRunCompilationModuleGroupConfig groupConfig = new ReadyToRunCompilationModuleGroupConfig();
+ groupConfig.Context = typeSystemContext;
+ groupConfig.IsCompositeBuildMode = _commandLineOptions.Composite;
+ groupConfig.IsInputBubble = _commandLineOptions.InputBubble;
+ groupConfig.CompilationModuleSet = inputModules;
+ groupConfig.VersionBubbleModuleSet = versionBubbleModules;
+ groupConfig.CompileGenericDependenciesFromVersionBubbleModuleSet = _commandLineOptions.CompileBubbleGenerics;
+
if (singleMethod != null)
{
// Compiling just a single method
compilationGroup = new SingleMethodCompilationModuleGroup(
- typeSystemContext,
- _commandLineOptions.Composite,
- _commandLineOptions.InputBubble,
- inputModules,
- versionBubbleModules,
- _commandLineOptions.CompileBubbleGenerics,
+ groupConfig,
singleMethod);
compilationRoots.Add(new SingleMethodRootProvider(singleMethod));
}
else if (_commandLineOptions.CompileNoMethods)
{
- compilationGroup = new NoMethodsCompilationModuleGroup(
- typeSystemContext,
- _commandLineOptions.Composite,
- _commandLineOptions.InputBubble,
- inputModules,
- versionBubbleModules,
- _commandLineOptions.CompileBubbleGenerics);
+ compilationGroup = new NoMethodsCompilationModuleGroup(groupConfig);
}
else
{
// Single assembly compilation.
- compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup(
- typeSystemContext,
- _commandLineOptions.Composite,
- _commandLineOptions.InputBubble,
- inputModules,
- versionBubbleModules,
- _commandLineOptions.CompileBubbleGenerics);
+ compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup(groupConfig);
}
// Load any profiles generated by method call chain analyis
diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h
index 2b6e0c14837..d182b8fee80 100644
--- a/src/coreclr/tools/aot/jitinterface/jitinterface.h
+++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h
@@ -183,7 +183,6 @@ struct JitInterfaceCallbacks
uint16_t (* getRelocTypeHint)(void * thisHandle, CorInfoExceptionClass** ppException, void* target);
uint32_t (* getExpectedTargetArchitecture)(void * thisHandle, CorInfoExceptionClass** ppException);
uint32_t (* getJitFlags)(void * thisHandle, CorInfoExceptionClass** ppException, CORJIT_FLAGS* flags, uint32_t sizeInBytes);
- bool (* doesFieldBelongToClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd, CORINFO_CLASS_HANDLE cls);
};
@@ -1858,14 +1857,4 @@ public:
if (pException != nullptr) throw pException;
return temp;
}
-
- virtual bool doesFieldBelongToClass(
- CORINFO_FIELD_HANDLE fldHnd,
- CORINFO_CLASS_HANDLE cls)
-{
- CorInfoExceptionClass* pException = nullptr;
- bool temp = _callbacks->doesFieldBelongToClass(_thisHandle, &pException, fldHnd, cls);
- if (pException != nullptr) throw pException;
- return temp;
-}
};
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index 9c9d235c481..4ce8db66561 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -2034,13 +2034,3 @@ bool interceptor_ICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instruct
{
return original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supported);
}
-
-bool interceptor_ICJI::doesFieldBelongToClass(
- CORINFO_FIELD_HANDLE fldHnd,
- CORINFO_CLASS_HANDLE cls)
-{
- mc->cr->AddCall("doesFieldBelongToClass");
- bool result = original_ICorJitInfo->doesFieldBelongToClass(fldHnd, cls);
- mc->recDoesFieldBelongToClass(fldHnd, cls, result);
- return result;
-}
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index df7d67a6a0f..79e3536ba52 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -1389,11 +1389,3 @@ uint32_t interceptor_ICJI::getJitFlags(
return original_ICorJitInfo->getJitFlags(flags, sizeInBytes);
}
-bool interceptor_ICJI::doesFieldBelongToClass(
- CORINFO_FIELD_HANDLE fldHnd,
- CORINFO_CLASS_HANDLE cls)
-{
- mcs->AddCall("doesFieldBelongToClass");
- return original_ICorJitInfo->doesFieldBelongToClass(fldHnd, cls);
-}
-
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index 5efd8516cec..7d4feacc10d 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -1217,10 +1217,3 @@ uint32_t interceptor_ICJI::getJitFlags(
return original_ICorJitInfo->getJitFlags(flags, sizeInBytes);
}
-bool interceptor_ICJI::doesFieldBelongToClass(
- CORINFO_FIELD_HANDLE fldHnd,
- CORINFO_CLASS_HANDLE cls)
-{
- return original_ICorJitInfo->doesFieldBelongToClass(fldHnd, cls);
-}
-
diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
index a57b14cbee9..7f2203edd7a 100644
--- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
@@ -1576,13 +1576,6 @@ uint32_t MyICJI::getJitFlags(CORJIT_FLAGS* jitFlags, uint32_t sizeInBytes)
return ret;
}
-bool MyICJI::doesFieldBelongToClass(CORINFO_FIELD_HANDLE fldHnd, CORINFO_CLASS_HANDLE cls)
-{
- jitInstance->mc->cr->AddCall("doesFieldBelongToClass");
- bool result = jitInstance->mc->repDoesFieldBelongToClass(fldHnd, cls);
- return result;
-}
-
// Runs the given function with the given parameter under an error trap
// and returns true if the function completes successfully. We fake this
// up a bit for SuperPMI and simply catch all exceptions.
diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp
index 980949df7a4..dd6541a1f74 100644
--- a/src/coreclr/vm/appdomain.cpp
+++ b/src/coreclr/vm/appdomain.cpp
@@ -84,7 +84,6 @@
//#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain");
-static const WCHAR OTHER_DOMAIN_FRIENDLY_NAME_PREFIX[] = W("Domain");
#define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020
@@ -109,8 +108,6 @@ static BYTE g_pSystemDomainMemory[sizeof(SystemDomain)];
CrstStatic SystemDomain::m_SystemDomainCrst;
CrstStatic SystemDomain::m_DelayedUnloadCrst;
-DWORD SystemDomain::m_dwLowestFreeIndex = 0;
-
// Constructor for the PinnedHeapHandleBucket class.
PinnedHeapHandleBucket::PinnedHeapHandleBucket(PinnedHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
: m_pNext(pNext)
@@ -1602,58 +1599,6 @@ struct CallersDataWithStackMark
};
/*static*/
-MethodDesc* SystemDomain::GetCallersMethod(StackCrawlMark* stackMark)
-
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM(););
- }
- CONTRACTL_END;
-
- GCX_COOP();
-
- CallersDataWithStackMark cdata;
- ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
- cdata.stackMark = stackMark;
-
- GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
-
- if(cdata.pFoundMethod) {
- return cdata.pFoundMethod;
- } else
- return NULL;
-}
-
-/*static*/
-MethodTable* SystemDomain::GetCallersType(StackCrawlMark* stackMark)
-
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- INJECT_FAULT(COMPlusThrowOM(););
- }
- CONTRACTL_END;
-
- CallersDataWithStackMark cdata;
- ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
- cdata.stackMark = stackMark;
-
- GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
-
- if(cdata.pFoundMethod) {
- return cdata.pFoundMethod->GetMethodTable();
- } else
- return NULL;
-}
-
-/*static*/
Module* SystemDomain::GetCallersModule(StackCrawlMark* stackMark)
{
diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp
index 5a5a1d97c6b..de8264b5984 100644
--- a/src/coreclr/vm/appdomain.hpp
+++ b/src/coreclr/vm/appdomain.hpp
@@ -2489,8 +2489,6 @@ public:
//****************************************************************************************
// Methods used to get the callers module and hence assembly and app domain.
- static MethodDesc* GetCallersMethod(StackCrawlMark* stackMark);
- static MethodTable* GetCallersType(StackCrawlMark* stackMark);
static Module* GetCallersModule(StackCrawlMark* stackMark);
static Assembly* GetCallersAssembly(StackCrawlMark* stackMark);
@@ -2650,8 +2648,6 @@ private:
static CrstStatic m_SystemDomainCrst;
static GlobalStringLiteralMap *m_pGlobalStringLiteralMap;
-
- static DWORD m_dwLowestFreeIndex;
#endif // DACCESS_COMPILE
public:
diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp
index 359d68855c5..dceb6f6b89f 100644
--- a/src/coreclr/vm/dllimport.cpp
+++ b/src/coreclr/vm/dllimport.cpp
@@ -3366,7 +3366,7 @@ BOOL NDirect::MarshalingRequired(
default:
{
- if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
+ if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_PTR || type == ELEMENT_TYPE_FNPTR)
{
if (i > 0)
diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp
index 9fe9d2b9b95..5dfb7de70ba 100644
--- a/src/coreclr/vm/jithelpers.cpp
+++ b/src/coreclr/vm/jithelpers.cpp
@@ -3375,34 +3375,6 @@ NOINLINE HCIMPL3(CORINFO_MethodPtr, JIT_VirtualFunctionPointer_Framed, Object *
}
HCIMPLEND
-HCIMPL3(void, JIT_StaticVirtualAmbiguousResolution,
- MethodDesc *method,
- MethodTable *interfaceType,
- MethodTable *targetType)
-{
- FCALL_CONTRACT;
-
- SString strMethodName;
- SString strInterfaceName;
- SString strTargetClassName;
-
- HELPER_METHOD_FRAME_BEGIN_0(); // Set up a frame
-
- TypeString::AppendMethod(strMethodName, method, method->GetMethodInstantiation());
- TypeString::AppendType(strInterfaceName, TypeHandle(interfaceType));
- TypeString::AppendType(strTargetClassName, targetType);
-
- HELPER_METHOD_FRAME_END(); // Set up a frame
-
- FCThrowExVoid(
- kAmbiguousImplementationException,
- IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE,
- strMethodName,
- strInterfaceName,
- strTargetClassName);
-}
-HCIMPLEND
-
HCIMPL1(Object*, JIT_GetRuntimeFieldStub, CORINFO_FIELD_HANDLE field)
{
FCALL_CONTRACT;
@@ -4182,6 +4154,35 @@ HCIMPL0(void, JIT_ThrowTypeNotSupportedException)
HCIMPLEND
/*********************************************************************/
+HCIMPL3(void, JIT_ThrowAmbiguousResolutionException,
+ MethodDesc *method,
+ MethodTable *interfaceType,
+ MethodTable *targetType)
+{
+ FCALL_CONTRACT;
+
+ SString strMethodName;
+ SString strInterfaceName;
+ SString strTargetClassName;
+
+ HELPER_METHOD_FRAME_BEGIN_0(); // Set up a frame
+
+ TypeString::AppendMethod(strMethodName, method, method->GetMethodInstantiation());
+ TypeString::AppendType(strInterfaceName, TypeHandle(interfaceType));
+ TypeString::AppendType(strTargetClassName, targetType);
+
+ HELPER_METHOD_FRAME_END(); // Set up a frame
+
+ FCThrowExVoid(
+ kAmbiguousImplementationException,
+ IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE,
+ strMethodName,
+ strInterfaceName,
+ strTargetClassName);
+}
+HCIMPLEND
+
+/*********************************************************************/
HCIMPL0(void, JIT_Overflow)
{
FCALL_CONTRACT;
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 4837e51ab89..7026aae2953 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -5433,7 +5433,7 @@ void CEEInfo::getCallInfo(
// shared generics is covered by the ConstrainedMethodEntrySlot dictionary entry.
pResult->kind = CORINFO_CALL;
pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
- pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_STATIC_VIRTUAL_AMBIGUOUS_RESOLUTION;
+ pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_THROW_AMBIGUOUS_RESOLUTION_EXCEPTION;
pResult->callsiteCalloutHelper.numArgs = 3;
pResult->callsiteCalloutHelper.args[0].methodHandle = (CORINFO_METHOD_HANDLE)pMD;
pResult->callsiteCalloutHelper.args[0].argType = CORINFO_HELPER_ARG_TYPE_Method;
@@ -11617,50 +11617,6 @@ uint32_t CEEJitInfo::getExpectedTargetArchitecture()
return IMAGE_FILE_MACHINE_NATIVE;
}
-bool CEEJitInfo::doesFieldBelongToClass(CORINFO_FIELD_HANDLE fldHnd, CORINFO_CLASS_HANDLE cls)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_PREEMPTIVE;
- } CONTRACTL_END;
-
- bool result = false;
-
- JIT_TO_EE_TRANSITION();
-
- FieldDesc* field = (FieldDesc*) fldHnd;
- TypeHandle th(cls);
-
- _ASSERTE(!field->IsStatic());
-
- // doesFieldBelongToClass implements the predicate of...
- // if field is not associated with the class in any way, return false.
- // if field is the only FieldDesc that the JIT might see for a given class handle
- // and logical field pair then return true. This is needed as the field handle here
- // is used as a key into a hashtable mapping writes to fields to value numbers.
- //
- // In the CoreCLR VM implementation, verifying that the canonical MethodTable of
- // the field matches the type found via GetExactDeclaringType, as all instance fields
- // are only held on the canonical MethodTable.
- // This yields a truth table such as
-
- // BaseType._field, BaseType -> true
- // BaseType._field, DerivedType -> true
- // BaseType<__Canon>._field, BaseType<__Canon> -> true
- // BaseType<__Canon>._field, BaseType<string> -> true
- // BaseType<__Canon>._field, BaseType<object> -> true
- // BaseType<sbyte>._field, BaseType<sbyte> -> true
- // BaseType<sbyte>._field, BaseType<byte> -> false
-
- MethodTable* pMT = field->GetExactDeclaringType(th.GetMethodTable());
- result = (pMT != nullptr) && (pMT->GetCanonicalMethodTable() == field->GetApproxEnclosingMethodTable()->GetCanonicalMethodTable());
-
- EE_TO_JIT_TRANSITION();
-
- return result;
-}
-
void CEEInfo::JitProcessShutdownWork()
{
LIMITED_METHOD_CONTRACT;
@@ -14283,12 +14239,6 @@ uint32_t CEEInfo::getExpectedTargetArchitecture()
return IMAGE_FILE_MACHINE_NATIVE;
}
-bool CEEInfo::doesFieldBelongToClass(CORINFO_FIELD_HANDLE fld, CORINFO_CLASS_HANDLE cls)
-{
- LIMITED_METHOD_CONTRACT;
- UNREACHABLE_RET(); // only called on derived class.
-}
-
void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
ICorDebugInfo::OffsetMapping *pMap)
{
diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h
index 349be865c88..492b2fbe5fe 100644
--- a/src/coreclr/vm/jitinterface.h
+++ b/src/coreclr/vm/jitinterface.h
@@ -670,8 +670,6 @@ public:
uint32_t getExpectedTargetArchitecture() override final;
- bool doesFieldBelongToClass(CORINFO_FIELD_HANDLE fld, CORINFO_CLASS_HANDLE cls) override final;
-
void ResetForJitRetry()
{
CONTRACTL {
diff --git a/src/coreclr/vm/util.cpp b/src/coreclr/vm/util.cpp
index 5f3a5bf922c..5422fdaa71b 100644
--- a/src/coreclr/vm/util.cpp
+++ b/src/coreclr/vm/util.cpp
@@ -44,184 +44,6 @@ void ClrFlsClearThreadType(TlsThreadTypeFlag flag)
thread_local size_t t_CantStopCount;
-// Helper function that encapsulates the parsing rules.
-//
-// Called first with *pdstout == NULL to figure out how many args there are
-// and the size of the required destination buffer.
-//
-// Called again with a nonnull *pdstout to fill in the actual buffer.
-//
-// Returns the # of arguments.
-static UINT ParseCommandLine(LPCWSTR psrc, __inout LPWSTR *pdstout)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- FORBID_FAULT;
- }
- CONTRACTL_END
-
- UINT argcount = 1; // discovery of arg0 is unconditional, below
- LPWSTR pdst = *pdstout;
- BOOL fDoWrite = (pdst != NULL);
-
- BOOL fInQuotes;
- int iSlash;
-
- /* A quoted program name is handled here. The handling is much
- simpler than for other arguments. Basically, whatever lies
- between the leading double-quote and next one, or a terminal null
- character is simply accepted. Fancier handling is not required
- because the program name must be a legal NTFS/HPFS file name.
- Note that the double-quote characters are not copied, nor do they
- contribute to numchars.
-
- This "simplification" is necessary for compatibility reasons even
- though it leads to mishandling of certain cases. For example,
- "c:\tests\"test.exe will result in an arg0 of c:\tests\ and an
- arg1 of test.exe. In any rational world this is incorrect, but
- we need to preserve compatibility.
- */
-
- LPCWSTR pStart = psrc;
- BOOL skipQuote = FALSE;
-
- if (*psrc == W('\"'))
- {
- // scan from just past the first double-quote through the next
- // double-quote, or up to a null, whichever comes first
- while ((*(++psrc) != W('\"')) && (*psrc != W('\0')))
- continue;
-
- skipQuote = TRUE;
- }
- else
- {
- /* Not a quoted program name */
-
- while (!ISWWHITE(*psrc) && *psrc != W('\0'))
- psrc++;
- }
-
- // We have now identified arg0 as pStart (or pStart+1 if we have a leading
- // quote) through psrc-1 inclusive
- if (skipQuote)
- pStart++;
- while (pStart < psrc)
- {
- if (fDoWrite)
- *pdst = *pStart;
-
- pStart++;
- pdst++;
- }
-
- // And terminate it.
- if (fDoWrite)
- *pdst = W('\0');
-
- pdst++;
-
- // if we stopped on a double-quote when arg0 is quoted, skip over it
- if (skipQuote && *psrc == W('\"'))
- psrc++;
-
- while ( *psrc != W('\0'))
- {
-LEADINGWHITE:
-
- // The outofarg state.
- while (ISWWHITE(*psrc))
- psrc++;
-
- if (*psrc == W('\0'))
- break;
- else
- if (*psrc == W('#'))
- {
- while (*psrc != W('\0') && *psrc != W('\n'))
- psrc++; // skip to end of line
-
- goto LEADINGWHITE;
- }
-
- argcount++;
- fInQuotes = FALSE;
-
- while ((!ISWWHITE(*psrc) || fInQuotes) && *psrc != W('\0'))
- {
- switch (*psrc)
- {
- case W('\\'):
- iSlash = 0;
- while (*psrc == W('\\'))
- {
- iSlash++;
- psrc++;
- }
-
- if (*psrc == W('\"'))
- {
- for ( ; iSlash >= 2; iSlash -= 2)
- {
- if (fDoWrite)
- *pdst = W('\\');
-
- pdst++;
- }
-
- if (iSlash & 1)
- {
- if (fDoWrite)
- *pdst = *psrc;
-
- psrc++;
- pdst++;
- }
- else
- {
- fInQuotes = !fInQuotes;
- psrc++;
- }
- }
- else
- for ( ; iSlash > 0; iSlash--)
- {
- if (fDoWrite)
- *pdst = W('\\');
-
- pdst++;
- }
-
- break;
-
- case W('\"'):
- fInQuotes = !fInQuotes;
- psrc++;
- break;
-
- default:
- if (fDoWrite)
- *pdst = *psrc;
-
- psrc++;
- pdst++;
- }
- }
-
- if (fDoWrite)
- *pdst = W('\0');
-
- pdst++;
- }
-
-
- _ASSERTE(*psrc == W('\0'));
- *pdstout = pdst;
- return argcount;
-}
-
//************************************************************************
// CQuickHeap
diff --git a/src/coreclr/vm/util.hpp b/src/coreclr/vm/util.hpp
index aaae98e569f..c508d0c4f09 100644
--- a/src/coreclr/vm/util.hpp
+++ b/src/coreclr/vm/util.hpp
@@ -87,8 +87,6 @@ void * __cdecl _alloca(size_t);
#pragma warning(disable:6255)
#endif // _PREFAST_
-#define ISWWHITE(x) ((x)==W(' ') || (x)==W('\t') || (x)==W('\n') || (x)==W('\r') )
-
BOOL inline FitsInI1(__int64 val)
{
LIMITED_METHOD_DAC_CONTRACT;
diff --git a/src/installer/pkg/sfx/installers/host.wxs b/src/installer/pkg/sfx/installers/host.wxs
index 6ff59fa6c29..322b9038d92 100644
--- a/src/installer/pkg/sfx/installers/host.wxs
+++ b/src/installer/pkg/sfx/installers/host.wxs
@@ -42,6 +42,9 @@
<?if $(var.Platform)~=x64 ?>
<!-- For x64 installer, only add to PATH when actually on native architecture -->
<Condition>NOT NON_NATIVE_ARCHITECTURE</Condition>
+ <?elseif $(var.Platform)~=x86 ?>
+ <!-- For x86 installer, only add to PATH when not on 64-bit platform -->
+ <Condition>NOT VersionNT64</Condition>
<?endif?>
<!-- A stable keypath with the right SxS characteristics for our PATH entry-->
diff --git a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPathTempDirectory.cs
index 9a7cb5b18d8..9a7cb5b18d8 100644
--- a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs
+++ b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPathTempDirectory.cs
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.Android.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.AnyMobile.cs
index 2edaca1e8ad..2edaca1e8ad 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.Android.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.AnyMobile.cs
diff --git a/src/libraries/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs b/src/libraries/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs
index 6befa440a5c..17fe421cb5a 100644
--- a/src/libraries/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs
+++ b/src/libraries/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs
@@ -51,5 +51,6 @@ internal static partial class Interop
DowngradeDetected = unchecked((int)0x80090350),
ApplicationProtocolMismatch = unchecked((int)0x80090367),
NoRenegotiation = unchecked((int)0x00090360),
+ KeySetDoesNotExist = unchecked((int)0x80090016)
}
}
diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/Http3SettingType.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/Http3SettingType.cs
index 40958e3e0fc..4919e8979c3 100644
--- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/Http3SettingType.cs
+++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/Http3SettingType.cs
@@ -33,6 +33,19 @@ namespace System.Net.Http
/// The maximum number of request streams that can be blocked waiting for QPack instructions. The default is 0.
/// https://tools.ietf.org/html/draft-ietf-quic-qpack-11#section-5
/// </summary>
- QPackBlockedStreams = 0x7
+ QPackBlockedStreams = 0x7,
+
+ /// <summary>
+ /// SETTINGS_ENABLE_WEBTRANSPORT, default is 0 (off)
+ /// https://www.ietf.org/archive/id/draft-ietf-webtrans-http3-01.html#name-http-3-settings-parameter-r
+ /// </summary>
+ EnableWebTransport = 0x2b603742,
+
+ /// <summary>
+ /// H3_DATAGRAM, default is 0 (off)
+ /// indicates that the server suppprts sending individual datagrams over Http/3
+ /// rather than just streams.
+ /// </summary>
+ H3Datagram = 0xffd277
}
}
diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs
index b2ea95a05fe..d7e41077e7e 100644
--- a/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs
+++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs
@@ -530,6 +530,7 @@ namespace System.Net
}
[NonEvent]
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Can safely serialize primitive arguments.")]
private unsafe void WriteEvent(int eventId, string? arg1, int arg2, int arg3, int arg4)
{
if (IsEnabled())
@@ -568,6 +569,7 @@ namespace System.Net
}
[NonEvent]
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Can safely serialize primitive arguments.")]
private unsafe void WriteEvent(int eventId, string? arg1, int arg2, string? arg3)
{
if (IsEnabled())
@@ -603,6 +605,7 @@ namespace System.Net
}
[NonEvent]
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Can safely serialize primitive arguments.")]
private unsafe void WriteEvent(int eventId, string? arg1, string? arg2, int arg3)
{
if (IsEnabled())
@@ -638,6 +641,7 @@ namespace System.Net
}
[NonEvent]
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Can safely serialize primitive arguments.")]
private unsafe void WriteEvent(int eventId, string? arg1, string? arg2, string? arg3, int arg4)
{
if (IsEnabled())
diff --git a/src/libraries/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs b/src/libraries/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs
index 0967f8e32e5..f804caddbd0 100644
--- a/src/libraries/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs
+++ b/src/libraries/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs
@@ -9,7 +9,7 @@ namespace System.Net
{
internal static class SecurityStatusAdapterPal
{
- private const int StatusDictionarySize = 43;
+ private const int StatusDictionarySize = 44;
#if DEBUG
static SecurityStatusAdapterPal()
@@ -62,7 +62,8 @@ namespace System.Net
{ Interop.SECURITY_STATUS.Unsupported, SecurityStatusPalErrorCode.Unsupported },
{ Interop.SECURITY_STATUS.UntrustedRoot, SecurityStatusPalErrorCode.UntrustedRoot },
{ Interop.SECURITY_STATUS.WrongPrincipal, SecurityStatusPalErrorCode.WrongPrincipal },
- { Interop.SECURITY_STATUS.NoRenegotiation, SecurityStatusPalErrorCode.NoRenegotiation }
+ { Interop.SECURITY_STATUS.NoRenegotiation, SecurityStatusPalErrorCode.NoRenegotiation },
+ { Interop.SECURITY_STATUS.KeySetDoesNotExist, SecurityStatusPalErrorCode.KeySetDoesNotExist }
};
internal static SecurityStatusPal GetSecurityStatusPalFromNativeInt(int win32SecurityStatus)
diff --git a/src/libraries/Common/src/System/Net/SecurityStatusPal.cs b/src/libraries/Common/src/System/Net/SecurityStatusPal.cs
index 4b99938aeb0..064aa974d6b 100644
--- a/src/libraries/Common/src/System/Net/SecurityStatusPal.cs
+++ b/src/libraries/Common/src/System/Net/SecurityStatusPal.cs
@@ -70,6 +70,7 @@ namespace System.Net
BadBinding,
DowngradeDetected,
ApplicationProtocolMismatch,
- NoRenegotiation
+ NoRenegotiation,
+ KeySetDoesNotExist
}
}
diff --git a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs
index f12aa873104..1086ffeed62 100644
--- a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs
+++ b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs
@@ -1855,7 +1855,7 @@ namespace System.IO.Tests
{
write = Task.Run(async () =>
{
- await writeable.WriteAsync(Encoding.UTF8.GetBytes("hello"));
+ await writeable.WriteAsync("hello"u8.ToArray());
await writeable.DisposeAsync();
});
}
@@ -2206,7 +2206,7 @@ namespace System.IO.Tests
Task write = Task.Run(async () =>
{
- await writeable.WriteAsync(Encoding.UTF8.GetBytes("hello"));
+ await writeable.WriteAsync("hello"u8.ToArray());
if (FlushRequiredToWriteData)
{
if (FlushGuaranteesAllDataWritten)
@@ -2261,7 +2261,7 @@ namespace System.IO.Tests
[SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets")]
public virtual async Task ZeroByteWrite_OtherDataReceivedSuccessfully(ReadWriteMode mode)
{
- byte[][] buffers = new[] { Array.Empty<byte>(), Encoding.UTF8.GetBytes("hello"), Array.Empty<byte>(), Encoding.UTF8.GetBytes("world") };
+ byte[][] buffers = new[] { Array.Empty<byte>(), "hello"u8.ToArray(), Array.Empty<byte>(), "world"u8.ToArray() };
using StreamPair streams = await CreateConnectedStreamsAsync();
foreach ((Stream writeable, Stream readable) in GetReadWritePairs(streams))
@@ -2915,7 +2915,7 @@ namespace System.IO.Tests
// (a) produce at least two readable bytes, so we can unblock the reader and read a single byte without clearing its buffer; and
// (b) produce no more than 1K of readable bytes, so we can clear the reader buffer below.
// If this isn't the case for some Stream(s), we can modify the data or parameterize it per Stream.
- byte[] data = Encoding.UTF8.GetBytes("hello world");
+ byte[] data = "hello world"u8.ToArray();
using StreamPair innerStreams = ConnectedStreams.CreateBidirectional();
(Stream innerWriteable, Stream innerReadable) = GetReadWritePair(innerStreams);
diff --git a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs
index 2329475728c..fbba51f0209 100644
--- a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs
+++ b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs
@@ -100,7 +100,7 @@ namespace System.Net.Test.Common
// Since those tests are not set up to handle multiple retries, we instead just send back an invalid response here
// so that SocketsHttpHandler will not induce retry.
// The contents of what we send don't really matter, as long as it is interpreted by SocketsHttpHandler as an invalid response.
- await _connectionStream.WriteAsync(Encoding.ASCII.GetBytes("HTTP/2.0 400 Bad Request\r\n\r\n"));
+ await _connectionStream.WriteAsync("HTTP/2.0 400 Bad Request\r\n\r\n"u8.ToArray());
_connectionSocket.Shutdown(SocketShutdown.Send);
// If WinHTTP doesn't support streaming a request without a length then it will fallback
// to HTTP/1.1. Throwing an exception to detect this case in WinHttpHandler tests.
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs
index 4cb7c502702..ebd154b3a0a 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs
@@ -46,6 +46,7 @@ namespace System.Net.Http.Functional.Tests
#pragma warning restore SYSLIB0039
[InlineData(SslProtocols.None, false)]
[InlineData(SslProtocols.None, true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SetDelegate_ConnectionSucceeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol)
{
#pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete
@@ -98,6 +99,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop]
[ConditionalTheory(nameof(ClientSupportsDHECipherSuites))]
[MemberData(nameof(InvalidCertificateServers))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task InvalidCertificateServers_CertificateValidationDisabled_Succeeds(string url)
{
using (HttpClientHandler handler = CreateHttpClientHandler())
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs
index 06bcd8298cf..14c99f34eda 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs
@@ -29,6 +29,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(false, CancellationMode.Token)]
[InlineData(true, CancellationMode.Token)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/36634", TestPlatforms.Browser)] // out of memory
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsync_CancelDuringRequestContentSend_TaskCanceledQuickly(bool chunkedTransfer, CancellationMode mode)
{
if (LoopbackServerFactory.Version >= HttpVersion20.Value && chunkedTransfer)
@@ -87,6 +88,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(OneBoolAndCancellationMode))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_CancelDuringResponseHeadersReceived_TaskCanceledQuickly(bool connectionClose, CancellationMode mode)
{
if (LoopbackServerFactory.Version >= HttpVersion20.Value && connectionClose)
@@ -207,6 +209,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(ThreeBools))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/65429", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_CancelDuringResponseBodyReceived_Unbuffered_TaskCanceledQuickly(bool chunkedTransfer, bool connectionClose, bool readOrCopyToAsync)
{
if (LoopbackServerFactory.Version >= HttpVersion20.Value && (chunkedTransfer || connectionClose))
@@ -290,6 +293,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(CancellationMode.CancelPendingRequests, true)]
[InlineData(CancellationMode.DisposeHttpClient, true)]
[SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't have blocking synchronous Stream.ReadByte and so it waits for whole body")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_CancelPendingRequests_DoesntCancelReadAsyncOnResponseStream(CancellationMode mode, bool copyToAsync)
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs
index 69685b9f40b..e26fce26f79 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs
@@ -81,6 +81,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(1, true)]
[InlineData(2, true)]
[InlineData(3, false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Manual_CertificateOnlySentWhenValid_Success(int certIndex, bool serverExpectsClientCertificate)
{
var options = new LoopbackServer.Options { UseSsl = true };
@@ -129,6 +130,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(6, false)]
[InlineData(3, true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Manual_CertificateSentMatchesCertificateReceived_Success(
int numberOfRequests,
bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage
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 b2f03bfbc93..e0b2e5d338c 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs
@@ -44,6 +44,7 @@ namespace System.Net.Http.Functional.Tests
private static string GetCookieHeaderValue(string cookieName, string cookieValue) => $"{cookieName}={cookieValue}";
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_DefaultCoookieContainer_NoCookieSent()
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -64,6 +65,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(CookieNamesValuesAndUseCookies))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_SetCookieContainer_CookieSent(string cookieName, string cookieValue, bool useCookies)
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -94,6 +96,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_SetCookieContainerMultipleCookies_CookiesSent()
{
var cookies = new Cookie[]
@@ -128,6 +131,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_AddCookieHeader_CookieHeaderSent()
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -149,6 +153,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_AddMultipleCookieHeaders_CookiesSent()
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -218,6 +223,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_SetCookieContainerAndCookieHeader_BothCookiesSent()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
@@ -246,6 +252,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_SetCookieContainerAndMultipleCookieHeaders_BothCookiesSent()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
@@ -286,6 +293,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsyncWithRedirect_SetCookieContainer_CorrectCookiesSent()
{
if (UseVersion == HttpVersion30)
@@ -333,6 +341,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(CookieNamesValuesAndUseCookies))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ReceiveSetCookieHeader_CookieAdded(string cookieName, string cookieValue, bool useCookies)
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
@@ -365,6 +374,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ReceiveMultipleSetCookieHeaders_CookieAdded()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
@@ -405,6 +415,7 @@ namespace System.Net.Http.Functional.Tests
// ConditionalFact: CookieContainer does not follow RFC6265 on .NET Framework, therefore the (WinHttpHandler) test is expected to fail
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetFramework))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_NoPathDefined_CookieAddedWithDefaultPath()
{
await LoopbackServerFactory.CreateServerAsync(async (server, serverUrl) =>
@@ -435,6 +446,7 @@ namespace System.Net.Http.Functional.Tests
// ConditionalFact: CookieContainer does not follow RFC6265 on .NET Framework, therefore the (WinHttpHandler) test is expected to fail
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetFramework))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_CookiePathDoesNotMatchRequestPath_CookieAccepted()
{
await LoopbackServerFactory.CreateServerAsync(async (server, serverUrl) =>
@@ -467,6 +479,7 @@ namespace System.Net.Http.Functional.Tests
// ConditionalFact: CookieContainer does not follow RFC6265 on .NET Framework, therefore the (WinHttpHandler) test is expected to fail
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNetFramework))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_Redirect_CookiesArePreserved()
{
if (UseVersion == HttpVersion30)
@@ -516,6 +529,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ReceiveSetCookieHeader_CookieUpdated()
{
const string newCookieValue = "789";
@@ -544,6 +558,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ReceiveSetCookieHeader_CookieRemoved()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
@@ -568,6 +583,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ReceiveInvalidSetCookieHeader_ValidCookiesAdded()
{
await LoopbackServerFactory.CreateServerAsync(async (server, url) =>
@@ -603,6 +619,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsyncWithRedirect_ReceiveSetCookie_CookieSent()
{
if (UseVersion == HttpVersion30)
@@ -663,6 +680,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsyncWithBasicAuth_ReceiveSetCookie_CookieSent()
{
if (UseVersion == HttpVersion30)
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs
index 42448b2ee1c..201c1d8e54e 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs
@@ -322,6 +322,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ProxyTunnelRequest_GetAsync_Success()
{
if (IsWinHttpHandler)
@@ -358,6 +359,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ProxyTunnelRequest_MaxConnectionsSetButDoesNotApplyToProxyConnect_Success()
{
if (IsWinHttpHandler)
@@ -415,6 +417,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ProxyTunnelRequest_OriginServerSendsProxyAuthChallenge_NoProxyAuthPerformed()
{
if (IsWinHttpHandler)
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 c90753dd402..be1f072c1b7 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs
@@ -282,6 +282,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses external servers")]
[Theory]
[MemberData(nameof(CertificateValidationServersAndExpectedPolicies))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task UseCallback_BadCertificate_ExpectedPolicyErrors(string url, SslPolicyErrors expectedErrors)
{
const int SEC_E_BUFFER_TOO_SMALL = unchecked((int)0x80090321);
@@ -305,6 +306,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task UseCallback_SelfSignedCertificate_ExpectedPolicyErrors()
{
using (HttpClientHandler handler = CreateHttpClientHandler())
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs
index 58aaee300d3..238794dbe23 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs
@@ -101,6 +101,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(GetAsync_AllowedSSLVersion_Succeeds_MemberData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_AllowedSSLVersion_Succeeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol)
{
int count = 0;
@@ -242,6 +243,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_NoSpecifiedProtocol_DefaultsToTls12()
{
using (HttpClientHandler handler = CreateHttpClientHandler())
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs
index 5385879c864..87fac367760 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs
@@ -153,6 +153,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "ServerCertificateCustomValidationCallback not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_IPv6LinkLocalAddressUri_Success()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -187,6 +188,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(GetAsync_IPBasedUri_Success_MemberData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_IPBasedUri_Success(IPAddress address)
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -278,6 +280,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(SecureAndNonSecure_IPBasedUri_MemberData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_SecureAndNonSecureIPBasedUri_CorrectlyFormatted(IPAddress address, bool useSsl)
{
if (LoopbackServerFactory.Version >= HttpVersion20.Value)
@@ -324,6 +327,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData("WWW-Authenticate", "CustomAuth")]
[InlineData("", "")] // RFC7235 requires servers to send this header with 401 but some servers don't.
[SkipOnPlatform(TestPlatforms.Browser, "Credentials is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ServerNeedsNonStandardAuthAndSetCredential_StatusCodeUnauthorized(string authHeadrName, string authHeaderValue)
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -407,6 +411,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsync_ManyDifferentRequestHeaders_SentCorrectly()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -986,6 +991,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(false, false)]
[InlineData(null, false)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/65429", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(bool? chunked, bool enableWasmStreaming)
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1198,6 +1204,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ReadAsStreamAsync_EmptyResponseBody_HandlerProducesWellBehavedResponseStream()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1293,6 +1300,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/58812", TestPlatforms.Browser)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Dispose_DisposingHandlerCancelsActiveOperationsWithoutResponses()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1413,6 +1421,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "ExpectContinue not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ExpectContinueTrue_NoContent_StillSendsHeader()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1465,6 +1474,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(Interim1xxStatusCode))]
[SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_1xxResponsesWithHeaders_InterimResponsesHeadersIgnored(HttpStatusCode responseStatusCode)
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1540,6 +1550,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(Interim1xxStatusCode))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_Unexpected1xxResponses_DropAllInterimResponses(HttpStatusCode responseStatusCode)
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1591,6 +1602,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "ExpectContinue not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_MultipleExpected100Responses_ReceivesCorrectResponse()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1641,6 +1653,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_Expect100Continue_RequestBodyFails_ThrowsContentException()
{
if (IsWinHttpHandler)
@@ -1690,6 +1703,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "ExpectContinue not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_No100ContinueReceived_RequestBodySentEventually()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1922,6 +1936,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_RequestVersion20_HttpNotHttps_NoUpgradeRequest()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
@@ -1957,6 +1972,7 @@ namespace System.Net.Http.Functional.Tests
#region Uri wire transmission encoding tests
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendRequest_UriPathHasReservedChars_ServerReceivedExpectedPath()
{
if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value)
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyFileTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyFileTests.cs
index afae8f8c7a0..980a8a9194c 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyFileTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyFileTests.cs
@@ -182,7 +182,7 @@ QT4YuclwLvQmTewyjLtDGiDF/mC+4kpyBePeO9kfkRUDHiwSNk/efN4ug1xQgwhu
qE3Db1UI4anCCnyEj/jDA8R6hZTFDjxu6bG0Z66g7I2GBDEYaaB+8x0vtiyu5LXo
6UZ53SX6S+jfIqJoF5YME9zVMoO2kwS/EGvc64+epCGcee1Nx4SGgUcr5HJYz1P4
CU+l4wPQR0rRmYHIJJIvFh5OXk84pV0crsOrekw7tHeNU6DMzw==",
- Encoding.UTF8.GetBytes("Password > cipher"),
+ "Password > cipher"u8.ToArray(),
new PbeParameters(
PbeEncryptionAlgorithm.Aes192Cbc,
HashAlgorithmName.SHA256,
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyPemTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyPemTests.cs
index d27137f9708..a00c34b0e4f 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyPemTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSAKeyPemTests.cs
@@ -287,7 +287,7 @@ ho0YNYGUDSgOs6RxBpw1rJUCnAlHNU09peCjEP+aZSrhsxlejN/GpVS4e0JTmMeo
xTL6VO9mx52x6h5WDAQAisMVeMkBoxQUWLANXiw1zSfVbsmB7mDknsRcvD3tcgMs
7YLD7LQMiPAIjDlOP8XP/w==
-----END ENCRYPTED PRIVATE KEY-----";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
+ byte[] passwordBytes = "test"u8.ToArray();
dsa.ImportFromEncryptedPem(pem, passwordBytes);
DSAParameters dsaParameters = dsa.ExportParameters(true);
@@ -319,9 +319,8 @@ MGHbpaaShD6iJfoGMRX0frr0mMCtuOOZkkjBF9pSpkhaH0TDSq1PrVLxcM0/S4Vs
dVYwfovccu8ktEAwk5XAOo0r+5CCw2lDDw/hbDeO87BToC5Cc5nu3F5LxAUj8Flc
v8pi3w==
-----END ENCRYPTED PRIVATE KEY-----";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
- dsa.ImportFromEncryptedPem(pem, passwordBytes));
+ dsa.ImportFromEncryptedPem(pem, "test"u8));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
@@ -332,9 +331,8 @@ v8pi3w==
using (DSA dsa = DSAFactory.Create())
{
string pem = "";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
- dsa.ImportFromEncryptedPem(pem, passwordBytes));
+ dsa.ImportFromEncryptedPem(pem, "test"u8));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSATestData.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSATestData.cs
index 93871baa3f2..7d6bfe30720 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSATestData.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSATestData.cs
@@ -171,7 +171,7 @@ namespace System.Security.Cryptography.Dsa.Tests
"41e2345f1f56df2458f426d155b4ba2db6dcd8c8"
).HexToByteArray();
- data = Encoding.ASCII.GetBytes("abc");
+ data = "abc"u8.ToArray();
}
}
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.LimitedPrivate.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.LimitedPrivate.cs
index ca0f9967c13..ac74a4900d5 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.LimitedPrivate.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.LimitedPrivate.cs
@@ -83,7 +83,7 @@ PFzVQfJ396S+yx4IIC4=";
ReadWriteBase64EncryptedPkcs8(
base64,
- Encoding.UTF8.GetBytes("qwerty"),
+ "qwerty"u8.ToArray(),
new PbeParameters(
PbeEncryptionAlgorithm.Aes256Cbc,
HashAlgorithmName.SHA1,
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs
index d867f1545a9..492c9d45132 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyFileTests.cs
@@ -195,7 +195,7 @@ qtlbnispri1a/EghiaPQ0po=";
ReadWriteBase64EncryptedPkcs8(
base64,
- Encoding.UTF8.GetBytes("qwerty"),
+ "qwerty"u8.ToArray(),
new PbeParameters(
PbeEncryptionAlgorithm.Aes256Cbc,
HashAlgorithmName.SHA1,
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyPemTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyPemTests.cs
index 3c367a4557b..52458f12c56 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyPemTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/ECKeyPemTests.cs
@@ -342,8 +342,7 @@ iE/+pIb/4quf+Y524bXUKTGYXzdSUE8Dp1qdZFcwDiCYCTtpL+065fGhmf1KZS2c
/OMt/tWvtMSj17+dJvShsu/NYJXF5fsfpSJbd3e50Y3AisW0Ob7mmF54KBfg6Y+4
aATwwQdUIKVzUZsQctsHPjbriQKKn7GKSyUOikBUNQ+TozojX8/g7JAsl+T9jGM=
-----END ENCRYPTED PRIVATE KEY-----";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
- key.ImportFromEncryptedPem(pem, passwordBytes);
+ key.ImportFromEncryptedPem(pem, "test"u8);
ECParameters ecParameters = key.ExportParameters(true);
ECParameters expected = EccTestData.GetNistP256ReferenceKey();
EccTestBase.AssertEqual(expected, ecParameters);
@@ -370,10 +369,9 @@ Evt9yfvEjiP/6yITq59drw1Kcgp6buOCVCY7LZ06aD6WpogiqGDYMuzfvqg5hNFp
opSAJ/pvHONL5kyAJLeNyG9c/mR2qyrP2L9gL0Z5fB9NyPejKTLi0PXMGQWdDTH8
Qh0fqdrNovgFLubbJFMQN/MwwIAfIuf0Mn0WFYYeQiBJ3kg=
-----END ENCRYPTED PRIVATE KEY-----";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
- key.ImportFromEncryptedPem(pem, passwordBytes));
+ key.ImportFromEncryptedPem(pem, "test"u8));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs
index 187c76ad351..d2b0c1a5ea4 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs
@@ -274,8 +274,6 @@ namespace System.Security.Cryptography.EcDsa.Tests
[MemberData(nameof(InteroperableSignatureConfigurations))]
public void SignVerify_InteroperableSameKeys_RoundTripsUnlessTampered(ECDsa ecdsa, HashAlgorithmName hashAlgorithm)
{
- byte[] data = Encoding.UTF8.GetBytes("something to repeat and sign");
-
// large enough to make hashing work though multiple iterations and not a multiple of 4KB it uses.
byte[] dataArray = new byte[33333];
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyFileTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyFileTests.cs
index a9c021ac129..daa175dda47 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyFileTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyFileTests.cs
@@ -781,7 +781,7 @@ RdMKfFP3he4C+CFyGGslffbxCaJhKebeuOil5xxlvP8aBPVNDtQfSS1HXHd1/Ikq
ReadBase64EncryptedPkcs8(
base64,
- Encoding.UTF8.GetBytes("rc2"),
+ "rc2"u8.ToArray(),
new PbeParameters(
PbeEncryptionAlgorithm.Aes192Cbc,
HashAlgorithmName.SHA256,
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyPemTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyPemTests.cs
index 013ec21c8a6..27438e93d36 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyPemTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAKeyPemTests.cs
@@ -425,7 +425,7 @@ E+nr7hyinl51raM1RSHojJB22oOW+GwV7GgWYIjUgIEMDOhN10FcGNfTeC65PCXx
5QSEe7EKVF0aHXBYB5SzMGVuxR/BqydDa26jlhVzO3LNvy9FYuqLKUslCrBCmPrt
raZNyk8KAsLs+FJq9T2tda0=
-----END ENCRYPTED PRIVATE KEY-----";
- rsa.ImportFromEncryptedPem(pem, Encoding.UTF8.GetBytes("test"));
+ rsa.ImportFromEncryptedPem(pem, "test"u8);
RSAParameters rsaParameters = rsa.ExportParameters(true);
ImportExport.AssertKeyEquals(TestData.DiminishedDPParameters, rsaParameters);
@@ -462,9 +462,8 @@ AWvBUt33Sozc+dF0l7NGLAWL2tqkkpyDQuKn6UgYz/vxkFeQAVfSuaJVR+fUlHg0
N4lD7/hJq7b+yYPhlN3Fvvt8M9MtRg1TLAve67CA2v4TITHB06M/ELe3y42bZuLW
CA7ffFk=
-----END ENCRYPTED PRIVATE KEY-----";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
- rsa.ImportFromEncryptedPem(pem, passwordBytes));
+ rsa.ImportFromEncryptedPem(pem, "test"u8));
Assert.Contains(AmbiguousExceptionMarker, ae.Message);
}
}
@@ -475,9 +474,8 @@ CA7ffFk=
using (RSA rsa = RSAFactory.Create())
{
string pem = "these aren't the PEMs we're looking for.";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
- rsa.ImportFromEncryptedPem(pem, passwordBytes));
+ rsa.ImportFromEncryptedPem(pem, "test"u8));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
@@ -498,9 +496,8 @@ Ya8CHwiO/cUU9RIt8A2B84gf2ZfuV2nPMaSuZpTPFC/K5UsCIQCsJMzx1JuilQAN
acPiMCuFTnRSFYAhozpmsqoLyTREqwIhAMLJlZTGjEB2N+sEazH5ToEczQzKqp7t
9juGNbOPhoEL
-----END PRIVATE KEY-----";
- byte[] passwordBytes = Encoding.UTF8.GetBytes("test");
ArgumentException ae = AssertExtensions.Throws<ArgumentException>("input", () =>
- rsa.ImportFromEncryptedPem(pem, passwordBytes));
+ rsa.ImportFromEncryptedPem(pem, "test"u8));
Assert.Contains(NoPemExceptionMarker, ae.Message);
}
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs b/src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs
index abdbabb14b8..172e09ec63a 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/SignatureSupport.cs
@@ -7,6 +7,10 @@ namespace System.Security.Cryptography.Tests
{
internal static bool CanProduceSha1Signature(AsymmetricAlgorithm algorithm)
{
+#if NETFRAMEWORK
+ algorithm.Dispose();
+ return true;
+#else
// We expect all non-Linux platforms to support SHA1 signatures, currently.
if (!OperatingSystem.IsLinux())
{
@@ -46,6 +50,7 @@ namespace System.Security.Cryptography.Tests
default:
throw new NotSupportedException($"Algorithm type {algorithm.GetType()} is not supported.");
}
+#endif
}
}
}
diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs
index 0d6281922dd..7d2558a9593 100644
--- a/src/libraries/Common/tests/Tests/System/StringTests.cs
+++ b/src/libraries/Common/tests/Tests/System/StringTests.cs
@@ -13,6 +13,7 @@ using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
using Microsoft.DotNet.XUnitExtensions;
using Xunit;
+using static System.Text.Tests.StringBuilderTests;
#pragma warning disable xUnit2009 // these are the tests for String and so should be using the explicit methods on String
@@ -2623,15 +2624,116 @@ namespace System.Tests
AssertExtensions.Throws<ArgumentException>("comparisonType", () => "a".Equals("b", comparisonType));
}
- [Fact]
- public static void Format()
+ public static IEnumerable<object[]> Format_Valid_TestData()
+ {
+ yield return new object[] { null, "", new object[0], "" };
+ yield return new object[] { null, ", ", new object[0], ", " };
+
+ yield return new object[] { null, ", Foo {0 }", new object[] { "Bar" }, ", Foo Bar" }; // Ignores whitespace
+
+ yield return new object[] { null, "Foo {0}", new object[] { "Bar" }, "Foo Bar" };
+ yield return new object[] { null, "Foo {0} Baz {1}", new object[] { "Bar", "Foo" }, "Foo Bar Baz Foo" };
+ yield return new object[] { null, "Foo {0} Baz {1} Bar {2}", new object[] { "Bar", "Foo", "Baz" }, "Foo Bar Baz Foo Bar Baz" };
+ yield return new object[] { null, "Foo {0} Baz {1} Bar {2} Foo {3}", new object[] { "Bar", "Foo", "Baz", "Bar" }, "Foo Bar Baz Foo Bar Baz Foo Bar" };
+
+ // Length is positive
+ yield return new object[] { null, "Foo {0,2}", new object[] { "Bar" }, "Foo Bar" }; // MiValue's length > minimum length (so don't prepend whitespace)
+ yield return new object[] { null, "Foo {0,3}", new object[] { "B" }, "Foo B" }; // Value's length < minimum length (so prepend whitespace)
+ yield return new object[] { null, "Foo {0, 3}", new object[] { "B" }, "Foo B" }; // Same as above, but verify AppendFormat ignores whitespace
+ yield return new object[] { null, "Foo {0,0}", new object[] { "Bar" }, "Foo Bar" }; // Minimum length is 0
+ yield return new object[] { null, "Foo {0, 2 }", new object[] { "Bar" }, "Foo Bar" }; // whitespace before and after length
+
+ // Length is negative
+ yield return new object[] { null, "Foo {0,-2}", new object[] { "Bar" }, "Foo Bar" }; // Value's length > |minimum length| (so don't prepend whitespace)
+ yield return new object[] { null, "Foo {0,-3}", new object[] { "B" }, "Foo B " }; // Value's length < |minimum length| (so append whitespace)
+ yield return new object[] { null, "Foo {0, -3}", new object[] { "B" }, "Foo B " }; // Same as above, but verify AppendFormat ignores whitespace
+ yield return new object[] { null, "Foo {0,0}", new object[] { "Bar" }, "Foo Bar" }; // Minimum length is 0
+ yield return new object[] { null, "Foo {0, -2 }", new object[] { "Bar" }, "Foo Bar" }; // whitespace before and after length
+
+ yield return new object[] { null, "Foo {0:D6}", new object[] { 1 }, "Foo 000001" }; // Custom format
+ yield return new object[] { null, "Foo {0 :D6}", new object[] { 1 }, "Foo 000001" }; // Custom format with ignored whitespace
+ yield return new object[] { null, "Foo {0:}", new object[] { 1 }, "Foo 1" }; // Missing custom format
+
+ yield return new object[] { null, "Foo {0,9:D6}", new object[] { 1 }, "Foo 000001" }; // Positive minimum length and custom format
+ yield return new object[] { null, "Foo {0,-9:D6}", new object[] { 1 }, "Foo 000001 " }; // Negative length and custom format
+
+ yield return new object[] { null, "Foo {{{0}", new object[] { 1 }, "Foo {1" }; // Escaped open curly braces
+ yield return new object[] { null, "Foo }}{0}", new object[] { 1 }, "Foo }1" }; // Escaped closed curly braces
+ yield return new object[] { null, "Foo {0} {{0}}", new object[] { 1 }, "Foo 1 {0}" }; // Escaped placeholder
+
+
+ yield return new object[] { null, "Foo {0}", new object[] { null }, "Foo " }; // Values has null only
+ yield return new object[] { null, "Foo {0} {1} {2}", new object[] { "Bar", null, "Baz" }, "Foo Bar Baz" }; // Values has null
+
+ yield return new object[] { CultureInfo.InvariantCulture, "Foo {0,9:D6}", new object[] { 1 }, "Foo 000001" }; // Positive minimum length, custom format and custom format provider
+
+ yield return new object[] { new CustomFormatter(), "{0}", new object[] { 1.2 }, "abc" }; // Custom format provider
+ yield return new object[] { new CustomFormatter(), "{0:0}", new object[] { 1.2 }, "abc" }; // Custom format provider
+
+ // Longer inputs
+ yield return new object[] { null, "0 = {0} 1 = {1} 2 = {2} 3 = {3} 4 = {4}", new object[] { "zero", "one", "two", "three", "four" }, "0 = zero 1 = one 2 = two 3 = three 4 = four" };
+ yield return new object[] { new TestFormatter(), "0 = {0} 1 = {1} 2 = {2} 3 = {3} 4 = {4}", new object[] { "zero", "one", "two", "three", "four" }, "0 = Test: : zero 1 = Test: : one 2 = Test: : two 3 = Test: : three 4 = Test: : four" };
+
+ // ISpanFormattable inputs: simple validation of known types that implement the interface
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (byte)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { 'A' }, "A" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0:r}", new object[] { DateTime.ParseExact("2021-03-15T14:52:51.5058563Z", "o", null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal) }, "Mon, 15 Mar 2021 14:52:51 GMT" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0:r}", new object[] { DateTimeOffset.ParseExact("2021-03-15T14:52:51.5058563Z", "o", null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal) }, "Mon, 15 Mar 2021 14:52:51 GMT" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (decimal)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (double)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { Guid.Parse("68d9cfaf-feab-4d5b-96d8-a3fd889ae89f") }, "68d9cfaf-feab-4d5b-96d8-a3fd889ae89f" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (Half)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (short)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (int)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (long)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (IntPtr)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { new Rune('A') }, "A" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (sbyte)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (float)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { TimeSpan.FromSeconds(42) }, "00:00:42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (ushort)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (uint)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (ulong)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { (UIntPtr)42 }, "42" };
+ yield return new object[] { CultureInfo.InvariantCulture, "{0}", new object[] { new Version(1, 2, 3, 4) }, "1.2.3.4" };
+ }
+
+ [Theory]
+ [MemberData(nameof(Format_Valid_TestData))]
+ public static void Format_Valid(IFormatProvider provider, string format, object[] values, string expected)
{
- string s = string.Format(null, "0 = {0} 1 = {1} 2 = {2} 3 = {3} 4 = {4}", "zero", "one", "two", "three", "four");
- Assert.Equal("0 = zero 1 = one 2 = two 3 = three 4 = four", s);
+ Assert.Equal(expected, string.Format(provider, format, values));
+ if (provider is null)
+ {
+ Assert.Equal(expected, string.Format(format, values));
+ }
+
+ switch (values.Length)
+ {
+ case 1:
+ Assert.Equal(expected, string.Format(provider, format, values[0]));
+ if (provider is null)
+ {
+ Assert.Equal(expected, string.Format(format, values[0]));
+ }
+ break;
- var testFormatter = new TestFormatter();
- s = string.Format(testFormatter, "0 = {0} 1 = {1} 2 = {2} 3 = {3} 4 = {4}", "zero", "one", "two", "three", "four");
- Assert.Equal("0 = Test: : zero 1 = Test: : one 2 = Test: : two 3 = Test: : three 4 = Test: : four", s);
+ case 2:
+ Assert.Equal(expected, string.Format(provider, format, values[0], values[1]));
+ if (provider is null)
+ {
+ Assert.Equal(expected, string.Format(format, values[0], values[1]));
+ }
+ break;
+
+ case 3:
+ Assert.Equal(expected, string.Format(provider, format, values[0], values[1], values[2]));
+ if (provider is null)
+ {
+ Assert.Equal(expected, string.Format(format, values[0], values[1], values[2]));
+ }
+ break;
+ }
}
[Fact]
@@ -2661,26 +2763,54 @@ namespace System.Tests
AssertExtensions.Throws<ArgumentNullException>("format", () => string.Format(null, (object[])null));
AssertExtensions.Throws<ArgumentNullException>("format", () => string.Format(formatter, null, null));
- // Format has value < 0
- Assert.Throws<FormatException>(() => string.Format("{-1}", obj1));
- Assert.Throws<FormatException>(() => string.Format("{-1}", obj1, obj2));
- Assert.Throws<FormatException>(() => string.Format("{-1}", obj1, obj2, obj3));
- Assert.Throws<FormatException>(() => string.Format("{-1}", obj1, obj2, obj3, obj4));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1, obj2));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1, obj2, obj3));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1, obj2, obj3, obj4));
-#pragma warning disable IDE0043 // Format string contains invalid placeholder - the purpose of this is to test the functions
- // Format has out of range value
- Assert.Throws<FormatException>(() => string.Format("{1}", obj1));
- Assert.Throws<FormatException>(() => string.Format("{2}", obj1, obj2));
- Assert.Throws<FormatException>(() => string.Format("{3}", obj1, obj2, obj3));
- Assert.Throws<FormatException>(() => string.Format("{4}", obj1, obj2, obj3, obj4));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{1}", obj1));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{2}", obj1, obj2));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{3}", obj1, obj2, obj3));
- Assert.Throws<FormatException>(() => string.Format(formatter, "{4}", obj1, obj2, obj3, obj4));
-#pragma warning restore IDE0043 // Format string contains invalid placeholder
+ Assert.Throws<FormatException>(() => string.Format("{-1}", obj1)); // Format has value < 0
+ Assert.Throws<FormatException>(() => string.Format("{-1}", obj1, obj2)); // Format has value < 0
+ Assert.Throws<FormatException>(() => string.Format("{-1}", obj1, obj2, obj3)); // Format has value < 0
+ Assert.Throws<FormatException>(() => string.Format("{-1}", obj1, obj2, obj3, obj4)); // Format has value < 0
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1)); // Format has value < 0
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1, obj2)); // Format has value < 0
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1, obj2, obj3)); // Format has value < 0
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{-1}", obj1, obj2, obj3, obj4)); // Format has value < 0
+
+ Assert.Throws<FormatException>(() => string.Format("{1}", obj1)); // Format has value >= 1
+ Assert.Throws<FormatException>(() => string.Format("{2}", obj1, obj2)); // Format has value >= 2
+ Assert.Throws<FormatException>(() => string.Format("{3}", obj1, obj2, obj3)); // Format has value >= 3
+ Assert.Throws<FormatException>(() => string.Format("{4}", obj1, obj2, obj3, obj4)); // Format has value >= 4
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{1}", obj1)); // Format has value >= 1
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{2}", obj1, obj2)); // Format has value >= 2
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{3}", obj1, obj2, obj3)); // Format has value >= 3
+ Assert.Throws<FormatException>(() => string.Format(formatter, "{4}", obj1, obj2, obj3, obj4)); // Format has value >= 4
+
+ Assert.Throws<FormatException>(() => string.Format("{", "")); // Format has unescaped {
+ Assert.Throws<FormatException>(() => string.Format("{a", "")); // Format has unescaped {
+
+ Assert.Throws<FormatException>(() => string.Format("}", "")); // Format has unescaped }
+ Assert.Throws<FormatException>(() => string.Format("}a", "")); // Format has unescaped }
+ Assert.Throws<FormatException>(() => string.Format("{0:}}", "")); // Format has unescaped }
+
+ Assert.Throws<FormatException>(() => string.Format("{\0", "")); // Format has invalid character after {
+ Assert.Throws<FormatException>(() => string.Format("{a", "")); // Format has invalid character after {
+
+ Assert.Throws<FormatException>(() => string.Format("{0 ", "")); // Format with index and spaces is not closed
+
+ Assert.Throws<FormatException>(() => string.Format("{1000000", new string[10])); // Format index is too long
+ Assert.Throws<FormatException>(() => string.Format("{10000000}", new string[10])); // Format index is too long
+
+ Assert.Throws<FormatException>(() => string.Format("{0,", "")); // Format with comma is not closed
+ Assert.Throws<FormatException>(() => string.Format("{0, ", "")); // Format with comma and spaces is not closed
+ Assert.Throws<FormatException>(() => string.Format("{0,-", "")); // Format with comma and minus sign is not closed
+
+ Assert.Throws<FormatException>(() => string.Format("{0,-\0", "")); // Format has invalid character after minus sign
+ Assert.Throws<FormatException>(() => string.Format("{0,-a", "")); // Format has invalid character after minus sign
+
+ Assert.Throws<FormatException>(() => string.Format("{0,1000000", new string[10])); // Format length is too long
+ Assert.Throws<FormatException>(() => string.Format("{0,10000000}", new string[10])); // Format length is too long
+
+ Assert.Throws<FormatException>(() => string.Format("{0:", new string[10])); // Format with colon is not closed
+ Assert.Throws<FormatException>(() => string.Format("{0: ", new string[10])); // Format with colon and spaces is not closed
+
+ Assert.Throws<FormatException>(() => string.Format("{0:{", new string[10])); // Format with custom format contains unescaped {
+ Assert.Throws<FormatException>(() => string.Format("{0:{}", new string[10])); // Format with custom format contains unescaped {
}
[ConditionalTheory]
@@ -7288,8 +7418,7 @@ namespace System.Tests
[Fact]
public static void CreateStringFromEncoding_0Length_EmptyStringReturned() // basic test for code coverage; more tests in encodings tests
{
- byte[] bytes = Encoding.ASCII.GetBytes("hello");
- Assert.Same(string.Empty, new AsciiEncodingWithZeroReturningGetCharCount().GetString(bytes, 0, 0));
+ Assert.Same(string.Empty, new AsciiEncodingWithZeroReturningGetCharCount().GetString("hello"u8.ToArray(), 0, 0));
}
private sealed class AsciiEncodingWithZeroReturningGetCharCount : ASCIIEncoding
diff --git a/src/libraries/Microsoft.Extensions.HostFactoryResolver/Microsoft.Extensions.HostFactoryResolver.sln b/src/libraries/Microsoft.Extensions.HostFactoryResolver/Microsoft.Extensions.HostFactoryResolver.sln
index 1a33e7448af..cd1c71dfc11 100644
--- a/src/libraries/Microsoft.Extensions.HostFactoryResolver/Microsoft.Extensions.HostFactoryResolver.sln
+++ b/src/libraries/Microsoft.Extensions.HostFactoryResolver/Microsoft.Extensions.HostFactoryResolver.sln
@@ -5,6 +5,12 @@ VisualStudioVersion = 17.2.32516.85
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HostFactoryResolver.Sources", "src\Microsoft.Extensions.HostFactoryResolver.Sources.csproj", "{317C456F-8F26-4441-93F7-9042B0DC7119}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{549715BC-A4E3-49F5-A8AC-84D2F65FAC0F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{41A601F5-19D8-45A9-AE63-33F040315BA6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HostFactoryResolver.Tests", "tests\Microsoft.Extensions.HostFactoryResolver.Tests.csproj", "{16B58903-715A-467B-B1E4-284CF285394D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,10 +21,18 @@ Global
{317C456F-8F26-4441-93F7-9042B0DC7119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{317C456F-8F26-4441-93F7-9042B0DC7119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{317C456F-8F26-4441-93F7-9042B0DC7119}.Release|Any CPU.Build.0 = Release|Any CPU
+ {16B58903-715A-467B-B1E4-284CF285394D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {16B58903-715A-467B-B1E4-284CF285394D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {16B58903-715A-467B-B1E4-284CF285394D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {16B58903-715A-467B-B1E4-284CF285394D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {317C456F-8F26-4441-93F7-9042B0DC7119} = {549715BC-A4E3-49F5-A8AC-84D2F65FAC0F}
+ {16B58903-715A-467B-B1E4-284CF285394D} = {41A601F5-19D8-45A9-AE63-33F040315BA6}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {80C3C947-5A43-4A55-9E1C-D62738588863}
EndGlobalSection
diff --git a/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs b/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs
index 11dd6ec5449..abef13086da 100644
--- a/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs
+++ b/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs
@@ -247,7 +247,7 @@ namespace Microsoft.Extensions.Hosting
// build to throw
_hostTcs.TrySetException(new InvalidOperationException("The entry point exited without ever building an IHost."));
}
- catch (TargetInvocationException tie) when (tie.InnerException is HostAbortedException)
+ catch (TargetInvocationException tie) when (tie.InnerException?.GetType().Name == "HostAbortedException")
{
// The host was stopped by our own logic
}
@@ -341,10 +341,30 @@ namespace Microsoft.Extensions.Hosting
if (_stopApplication)
{
// Stop the host from running further
- throw new HostAbortedException();
+ ThrowHostAborted();
}
}
}
+
+ // HostFactoryResolver is used by tools that explicitly don't want to reference Microsoft.Extensions.Hosting assemblies.
+ // So don't depend on the public HostAbortedException directly. Instead, load the exception type dynamically if it can
+ // be found. If it can't (possibly because the app is using an older version), throw a private exception with the same name.
+ private void ThrowHostAborted()
+ {
+ Type? publicHostAbortedExceptionType = Type.GetType("Microsoft.Extensions.Hosting.HostAbortedException, Microsoft.Extensions.Hosting.Abstractions", throwOnError: false);
+ if (publicHostAbortedExceptionType != null)
+ {
+ throw (Exception)Activator.CreateInstance(publicHostAbortedExceptionType)!;
+ }
+ else
+ {
+ throw new HostAbortedException();
+ }
+ }
+
+ private sealed class HostAbortedException : Exception
+ {
+ }
}
}
}
diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs
index 269c4a14528..87e7149cead 100644
--- a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs
+++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs
@@ -36,6 +36,12 @@ namespace Microsoft.Extensions.Hosting
public static readonly string Production;
public static readonly string Staging;
}
+ public sealed partial class HostAbortedException : System.Exception
+ {
+ public HostAbortedException() { }
+ public HostAbortedException(string? message) { }
+ public HostAbortedException(string? message, System.Exception? innerException) { }
+ }
public partial class HostBuilderContext
{
public HostBuilderContext(System.Collections.Generic.IDictionary<object, object> properties) { }
diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/HostAbortedException.cs b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostAbortedException.cs
index c8b88f3218c..c8b88f3218c 100644
--- a/src/libraries/Microsoft.Extensions.Hosting/src/HostAbortedException.cs
+++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostAbortedException.cs
diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Resources/Strings.resx
new file mode 100644
index 00000000000..260653ce44e
--- /dev/null
+++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Resources/Strings.resx
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="HostAbortedExceptionMessage" xml:space="preserve">
+ <value>The host was aborted.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/libraries/Microsoft.Extensions.Hosting/ref/Microsoft.Extensions.Hosting.cs b/src/libraries/Microsoft.Extensions.Hosting/ref/Microsoft.Extensions.Hosting.cs
index 824774d9ea8..22e8f9b805a 100644
--- a/src/libraries/Microsoft.Extensions.Hosting/ref/Microsoft.Extensions.Hosting.cs
+++ b/src/libraries/Microsoft.Extensions.Hosting/ref/Microsoft.Extensions.Hosting.cs
@@ -30,12 +30,6 @@ namespace Microsoft.Extensions.Hosting
public static Microsoft.Extensions.Hosting.IHostBuilder CreateDefaultBuilder() { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder CreateDefaultBuilder(string[]? args) { throw null; }
}
- public sealed partial class HostAbortedException : System.Exception
- {
- public HostAbortedException() { }
- public HostAbortedException(string? message) { }
- public HostAbortedException(string? message, System.Exception? innerException) { }
- }
public sealed partial class HostApplicationBuilder
{
public HostApplicationBuilder() { }
@@ -80,25 +74,25 @@ namespace Microsoft.Extensions.Hosting
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureLogging(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Hosting.HostBuilderContext, Microsoft.Extensions.Logging.ILoggingBuilder> configureLogging) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureLogging(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Logging.ILoggingBuilder> configureLogging) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureServices(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection> configureDelegate) { throw null; }
- [System.Runtime.Versioning.UnsupportedOSPlatform("android")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static System.Threading.Tasks.Task RunConsoleAsync(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Hosting.ConsoleLifetimeOptions> configureOptions, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
- [System.Runtime.Versioning.UnsupportedOSPlatform("android")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static System.Threading.Tasks.Task RunConsoleAsync(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
- [System.Runtime.Versioning.UnsupportedOSPlatform("android")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static Microsoft.Extensions.Hosting.IHostBuilder UseConsoleLifetime(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder) { throw null; }
- [System.Runtime.Versioning.UnsupportedOSPlatform("android")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static Microsoft.Extensions.Hosting.IHostBuilder UseConsoleLifetime(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Hosting.ConsoleLifetimeOptions> configureOptions) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder UseContentRoot(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, string contentRoot) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder UseDefaultServiceProvider(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.DependencyInjection.ServiceProviderOptions> configure) { throw null; }
@@ -124,10 +118,10 @@ namespace Microsoft.Extensions.Hosting.Internal
public void NotifyStopped() { }
public void StopApplication() { }
}
- [System.Runtime.Versioning.UnsupportedOSPlatform("android")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
- [System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
+ [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public partial class ConsoleLifetime : Microsoft.Extensions.Hosting.IHostLifetime, System.IDisposable
{
public ConsoleLifetime(Microsoft.Extensions.Options.IOptions<Microsoft.Extensions.Hosting.ConsoleLifetimeOptions> options, Microsoft.Extensions.Hosting.IHostEnvironment environment, Microsoft.Extensions.Hosting.IHostApplicationLifetime applicationLifetime, Microsoft.Extensions.Options.IOptions<Microsoft.Extensions.Hosting.HostOptions> hostOptions) { }
diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Hosting/src/Resources/Strings.resx
index a244ea06969..293c071e97a 100644
--- a/src/libraries/Microsoft.Extensions.Hosting/src/Resources/Strings.resx
+++ b/src/libraries/Microsoft.Extensions.Hosting/src/Resources/Strings.resx
@@ -135,9 +135,6 @@
<data name="EnvironmentNameChangeNotSupoprted" xml:space="preserve">
<value>The environment name changed from "{0}" to "{1}". Changing host configuration is not supported.</value>
</data>
- <data name="HostAbortedExceptionMessage" xml:space="preserve">
- <value>The host was aborted.</value>
- </data>
<data name="IHostApplicationLifetimeReplacementNotSupported" xml:space="preserve">
<value>Replacing IHostApplicationLifetime is not supported.</value>
</data>
diff --git a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/AssociatedMetadataTypeTypeDescriptor.cs b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/AssociatedMetadataTypeTypeDescriptor.cs
index 252674bd53a..619c47dc14d 100644
--- a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/AssociatedMetadataTypeTypeDescriptor.cs
+++ b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/AssociatedMetadataTypeTypeDescriptor.cs
@@ -113,21 +113,10 @@ namespace System.ComponentModel.DataAnnotations
}
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063:UnrecognizedReflectionPattern",
- Justification = "The cache is a dictionary which is hard to annotate. All values in the cache" +
- "have annotation All (since we only ever add attribute.MetadataClassType which has All)." +
- "But the call to TryGetValue doesn't carry the annotation so this warns when trying" +
- "to return value.")]
- // Better "fix" for the missing annotation would be a local funcion
- // `bool TryGetAssociatedMetadataTypeFromCache(Type type, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] out Type? associatedMetadataType)`
- // With the suppression on it - since that would be much more localized.
- // Unfortunately this currently doesn't work due to an issue in the trimmer
- // https://github.com/dotnet/linker/issues/2632
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public static Type? GetAssociatedMetadataType(Type type)
{
- Type? associatedMetadataType;
- if (s_metadataTypeCache.TryGetValue(type, out associatedMetadataType))
+ if (TryGetAssociatedMetadataTypeFromCache(type, out Type? associatedMetadataType))
{
return associatedMetadataType;
}
@@ -140,6 +129,16 @@ namespace System.ComponentModel.DataAnnotations
}
s_metadataTypeCache.TryAdd(type, associatedMetadataType);
return associatedMetadataType;
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:ParameterDoesntMeetParameterRequirements",
+ Justification = "The cache is a dictionary which is hard to annotate. All values in the cache" +
+ "have annotation All (since we only ever add attribute.MetadataClassType which has All)." +
+ "But the call to TryGetValue doesn't carry the annotation so this warns when trying" +
+ "to assign to the out parameter.")]
+ static bool TryGetAssociatedMetadataTypeFromCache(Type type, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] out Type? associatedMetadataType)
+ {
+ return s_metadataTypeCache.TryGetValue(type, out associatedMetadataType);
+ }
}
private static void CheckAssociatedMetadataType(
diff --git a/src/libraries/System.Data.Common/ref/System.Data.Common.cs b/src/libraries/System.Data.Common/ref/System.Data.Common.cs
index fc4963afd6a..7f8e500b823 100644
--- a/src/libraries/System.Data.Common/ref/System.Data.Common.cs
+++ b/src/libraries/System.Data.Common/ref/System.Data.Common.cs
@@ -2405,6 +2405,24 @@ namespace System.Data.Common
System.ComponentModel.PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties(System.Attribute[]? attributes) { throw null; }
object System.ComponentModel.ICustomTypeDescriptor.GetPropertyOwner(System.ComponentModel.PropertyDescriptor? pd) { throw null; }
}
+ public abstract class DbDataSource : IDisposable, IAsyncDisposable
+ {
+ public abstract string ConnectionString { get; }
+ protected abstract System.Data.Common.DbConnection CreateDbConnection();
+ protected virtual System.Data.Common.DbConnection OpenDbConnection() { throw null; }
+ protected virtual System.Threading.Tasks.ValueTask<System.Data.Common.DbConnection> OpenDbConnectionAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
+ protected virtual System.Data.Common.DbCommand CreateDbCommand(string? commandText = null) { throw null; }
+ protected virtual System.Data.Common.DbBatch CreateDbBatch() { throw null; }
+ public System.Data.Common.DbConnection CreateConnection() { throw null; }
+ public System.Data.Common.DbConnection OpenConnection() { throw null; }
+ public System.Threading.Tasks.ValueTask<System.Data.Common.DbConnection> OpenConnectionAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }
+ public System.Data.Common.DbCommand CreateCommand(string? commandText = null) { throw null; }
+ public System.Data.Common.DbBatch CreateBatch() { throw null; }
+ public void Dispose() { throw null; }
+ public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }
+ protected virtual void Dispose(bool disposing) { throw null; }
+ protected virtual System.Threading.Tasks.ValueTask DisposeAsyncCore() { throw null; }
+ }
public abstract partial class DbDataSourceEnumerator
{
protected DbDataSourceEnumerator() { }
@@ -2606,6 +2624,7 @@ namespace System.Data.Common
public virtual System.Data.Common.DbDataAdapter? CreateDataAdapter() { throw null; }
public virtual System.Data.Common.DbDataSourceEnumerator? CreateDataSourceEnumerator() { throw null; }
public virtual System.Data.Common.DbParameter? CreateParameter() { throw null; }
+ public virtual System.Data.Common.DbDataSource CreateDataSource(string connectionString) { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed partial class DbProviderSpecificTypePropertyAttribute : System.Attribute
diff --git a/src/libraries/System.Data.Common/src/Resources/Strings.resx b/src/libraries/System.Data.Common/src/Resources/Strings.resx
index c1a4dee0c36..5199442caa4 100644
--- a/src/libraries/System.Data.Common/src/Resources/Strings.resx
+++ b/src/libraries/System.Data.Common/src/Resources/Strings.resx
@@ -156,6 +156,8 @@
<data name="Expr_InvalidTimeZoneRange" xml:space="preserve"><value>Provided range for time one exceeds total of 14 hours.</value></data>
<data name="Expr_MismatchKindandTimeSpan" xml:space="preserve"><value>Kind property of provided DateTime argument, does not match 'hours' and 'minutes' arguments.</value></data>
<data name="Expr_UnsupportedType" xml:space="preserve"><value>A DataColumn of type '{0}' does not support expression.</value></data>
+ <data name="Batch_NotSupportedOnDataSourceBatch" xml:space="preserve"><value>Connection and transaction access is not supported on batches created from DbDataSource.</value></data>
+ <data name="Command_NotSupportedOnDataSourceCommand" xml:space="preserve"><value>Connection and transaction access is not supported on commands created from DbDataSource.</value></data>
<data name="Data_EnforceConstraints" xml:space="preserve"><value>Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.</value></data>
<data name="Data_CannotModifyCollection" xml:space="preserve"><value>Collection itself is not modifiable.</value></data>
<data name="Data_CaseInsensitiveNameConflict" xml:space="preserve"><value>The given name '{0}' matches at least two names in the collection object with different cases, but does not match either of them with the same case.</value></data>
diff --git a/src/libraries/System.Data.Common/src/System.Data.Common.csproj b/src/libraries/System.Data.Common/src/System.Data.Common.csproj
index c4ac48cf19e..8c1413c2612 100644
--- a/src/libraries/System.Data.Common/src/System.Data.Common.csproj
+++ b/src/libraries/System.Data.Common/src/System.Data.Common.csproj
@@ -210,6 +210,7 @@
<Compile Include="System\Data\Common\DbDataReader.cs" />
<Compile Include="System\Data\Common\DbDataReaderExtensions.cs" />
<Compile Include="System\Data\Common\DbDataRecord.cs" />
+ <Compile Include="System\Data\Common\DbDataSource.cs" />
<Compile Include="System\Data\Common\DbDataSourceEnumerator.cs" />
<Compile Include="System\Data\Common\DbEnumerator.cs" />
<Compile Include="System\Data\Common\DbException.cs" />
@@ -224,6 +225,7 @@
<Compile Include="System\Data\Common\DBSchemaTable.cs" />
<Compile Include="System\Data\Common\DbTransaction.cs" />
<Compile Include="System\Data\Common\DecimalStorage.cs" />
+ <Compile Include="System\Data\Common\DefaultDataSource.cs" />
<Compile Include="System\Data\Common\DoubleStorage.cs" />
<Compile Include="System\Data\Common\FieldNameLookup.cs" />
<Compile Include="System\Data\Common\Groupbybehavior.cs" />
diff --git a/src/libraries/System.Data.Common/src/System/Data/Common/DbDataSource.cs b/src/libraries/System.Data.Common/src/System/Data/Common/DbDataSource.cs
new file mode 100644
index 00000000000..c51c7f59507
--- /dev/null
+++ b/src/libraries/System.Data.Common/src/System/Data/Common/DbDataSource.cs
@@ -0,0 +1,584 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Threading;
+using System.Threading.Tasks;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
+namespace System.Data.Common
+{
+ public abstract class DbDataSource : IDisposable, IAsyncDisposable
+ {
+ public abstract string ConnectionString { get; }
+
+ protected abstract DbConnection CreateDbConnection();
+
+ protected virtual DbConnection OpenDbConnection()
+ {
+ var connection = CreateDbConnection();
+
+ try
+ {
+ connection.Open();
+ return connection;
+ }
+ catch
+ {
+ connection.Dispose();
+ throw;
+ }
+ }
+
+ protected virtual async ValueTask<DbConnection> OpenDbConnectionAsync(CancellationToken cancellationToken = default)
+ {
+ var connection = CreateDbConnection();
+
+ try
+ {
+ await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
+ return connection;
+ }
+ catch
+ {
+ await connection.DisposeAsync().ConfigureAwait(false);
+ throw;
+ }
+ }
+
+ protected virtual DbCommand CreateDbCommand(string? commandText = null)
+ {
+ var command = CreateDbConnection().CreateCommand();
+ command.CommandText = commandText;
+
+ return new DbCommandWrapper(command);
+ }
+
+ protected virtual DbBatch CreateDbBatch()
+ => new DbBatchWrapper(CreateDbConnection().CreateBatch());
+
+ public DbConnection CreateConnection()
+ => CreateDbConnection();
+
+ public DbConnection OpenConnection()
+ => OpenDbConnection();
+
+ public ValueTask<DbConnection> OpenConnectionAsync(CancellationToken cancellationToken = default)
+ => OpenDbConnectionAsync(cancellationToken);
+
+ public DbCommand CreateCommand(string? commandText = null)
+ => CreateDbCommand(commandText);
+
+ public DbBatch CreateBatch()
+ => CreateDbBatch();
+
+ public void Dispose()
+ {
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ await DisposeAsyncCore().ConfigureAwait(false);
+
+ Dispose(disposing: false);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ }
+
+ protected virtual ValueTask DisposeAsyncCore()
+ => default;
+
+ private sealed class DbCommandWrapper : DbCommand
+ {
+ private readonly DbCommand _wrappedCommand;
+ private readonly DbConnection _connection;
+
+ internal DbCommandWrapper(DbCommand wrappedCommand)
+ {
+ Debug.Assert(wrappedCommand.Connection is not null);
+
+ _wrappedCommand = wrappedCommand;
+ _connection = wrappedCommand.Connection;
+ }
+
+ public override int ExecuteNonQuery()
+ {
+ _connection.Open();
+
+ try
+ {
+ return _wrappedCommand.ExecuteNonQuery();
+ }
+ finally
+ {
+ try
+ {
+ _connection.Close();
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up.
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
+ {
+ await _connection.OpenAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ return await _wrappedCommand.ExecuteNonQueryAsync(cancellationToken)
+ .ConfigureAwait(false);
+ }
+ finally
+ {
+ try
+ {
+ await _connection.CloseAsync().ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ public override object? ExecuteScalar()
+ {
+ _connection.Open();
+
+ try
+ {
+ return _wrappedCommand.ExecuteScalar();
+ }
+ finally
+ {
+ try
+ {
+ _connection.Close();
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ public override async Task<object?> ExecuteScalarAsync(CancellationToken cancellationToken)
+ {
+ await _connection.OpenAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ return await _wrappedCommand.ExecuteScalarAsync(cancellationToken)
+ .ConfigureAwait(false);
+ }
+ finally
+ {
+ try
+ {
+ await _connection.CloseAsync().ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
+ {
+ _connection.Open();
+
+ try
+ {
+ return _wrappedCommand.ExecuteReader(behavior | CommandBehavior.CloseConnection);
+ }
+ catch
+ {
+ try
+ {
+ _connection.Close();
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ }
+
+ throw;
+ }
+ }
+
+ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(
+ CommandBehavior behavior,
+ CancellationToken cancellationToken)
+ {
+ await _connection.OpenAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ return await _wrappedCommand.ExecuteReaderAsync(
+ behavior | CommandBehavior.CloseConnection,
+ cancellationToken)
+ .ConfigureAwait(false);
+ }
+ catch
+ {
+ try
+ {
+ await _connection.CloseAsync().ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ }
+
+ throw;
+ }
+ }
+
+ protected override DbParameter CreateDbParameter()
+ => _wrappedCommand.CreateParameter();
+
+ public override void Cancel()
+ => _wrappedCommand.Cancel();
+
+ [AllowNull]
+ public override string CommandText
+ {
+ get => _wrappedCommand.CommandText;
+ set => _wrappedCommand.CommandText = value;
+ }
+
+ public override int CommandTimeout
+ {
+ get => _wrappedCommand.CommandTimeout;
+ set => _wrappedCommand.CommandTimeout = value;
+ }
+
+ public override CommandType CommandType
+ {
+ get => _wrappedCommand.CommandType;
+ set => _wrappedCommand.CommandType = value;
+ }
+
+ protected override DbParameterCollection DbParameterCollection
+ => _wrappedCommand.Parameters;
+
+ public override bool DesignTimeVisible
+ {
+ get => _wrappedCommand.DesignTimeVisible;
+ set => _wrappedCommand.DesignTimeVisible = value;
+ }
+
+ public override UpdateRowSource UpdatedRowSource
+ {
+ get => _wrappedCommand.UpdatedRowSource;
+ set => _wrappedCommand.UpdatedRowSource = value;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ var connection = _wrappedCommand.Connection;
+
+ _wrappedCommand.Dispose();
+ connection!.Dispose();
+ }
+ }
+
+ public override async ValueTask DisposeAsync()
+ {
+ var connection = _wrappedCommand.Connection;
+
+ await _wrappedCommand.DisposeAsync().ConfigureAwait(false);
+ await connection!.DisposeAsync().ConfigureAwait(false);
+ }
+
+ // In most case, preparation doesn't make sense on a connectionless command since prepared statements are
+ // usually bound to specific physical connections.
+ // When prepared statements are global (not bound to a specific connection), providers would need to
+ // provide their own connection-less implementation anyway (i.e. interacting with the originating
+ // DbDataSource), so they'd have to override this in any case.
+ public override void Prepare()
+ => throw ExceptionBuilder.NotSupportedOnDataSourceCommand();
+
+ public override Task PrepareAsync(CancellationToken cancellationToken = default)
+ => Task.FromException(ExceptionBuilder.NotSupportedOnDataSourceCommand());
+
+ // The below are incompatible with commands executed directly against DbDataSource, since no DbConnection
+ // is involved at the user API level and the DbCommandWrapper owns the DbConnection.
+ protected override DbConnection? DbConnection
+ {
+ get => throw ExceptionBuilder.NotSupportedOnDataSourceCommand();
+ set => throw ExceptionBuilder.NotSupportedOnDataSourceCommand();
+ }
+
+ protected override DbTransaction? DbTransaction
+ {
+ get => throw ExceptionBuilder.NotSupportedOnDataSourceCommand();
+ set => throw ExceptionBuilder.NotSupportedOnDataSourceCommand();
+ }
+ }
+
+ private sealed class DbBatchWrapper : DbBatch
+ {
+ private readonly DbBatch _wrappedBatch;
+ private readonly DbConnection _connection;
+
+ internal DbBatchWrapper(DbBatch wrappedBatch)
+ {
+ Debug.Assert(wrappedBatch.Connection is not null);
+
+ _wrappedBatch = wrappedBatch;
+ _connection = wrappedBatch.Connection;
+ }
+
+ public override int ExecuteNonQuery()
+ {
+ _connection.Open();
+
+ try
+ {
+ return _wrappedBatch.ExecuteNonQuery();
+ }
+ finally
+ {
+ try
+ {
+ _connection.Close();
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
+ {
+ await _connection.OpenAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ return await _wrappedBatch.ExecuteNonQueryAsync(cancellationToken)
+ .ConfigureAwait(false);
+ }
+ finally
+ {
+ try
+ {
+ await _connection.CloseAsync().ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ public override object? ExecuteScalar()
+ {
+ _connection.Open();
+
+ try
+ {
+ return _wrappedBatch.ExecuteScalar();
+ }
+ finally
+ {
+ try
+ {
+ _connection.Close();
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ public override async Task<object?> ExecuteScalarAsync(CancellationToken cancellationToken)
+ {
+ await _connection.OpenAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ return await _wrappedBatch.ExecuteScalarAsync(cancellationToken)
+ .ConfigureAwait(false);
+ }
+ finally
+ {
+ try
+ {
+ await _connection.CloseAsync().ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ // Also, refrain from bubbling up the close exception even if there's no original exception,
+ // since it's not relevant to the user - execution did complete successfully, and the connection
+ // close is just an internal detail that shouldn't cause user code to fail.
+ }
+ }
+ }
+
+ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
+ {
+ _connection.Open();
+
+ try
+ {
+ return _wrappedBatch.ExecuteReader(behavior | CommandBehavior.CloseConnection);
+ }
+ catch
+ {
+ try
+ {
+ _connection.Close();
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ }
+
+ throw;
+ }
+ }
+
+ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(
+ CommandBehavior behavior,
+ CancellationToken cancellationToken)
+ {
+ await _connection.OpenAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ return await _wrappedBatch.ExecuteReaderAsync(
+ behavior | CommandBehavior.CloseConnection,
+ cancellationToken)
+ .ConfigureAwait(false);
+ }
+ catch
+ {
+ try
+ {
+ await _connection.CloseAsync().ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ ExceptionBuilder.TraceExceptionWithoutRethrow(e);
+
+ // Swallow to allow the original exception to bubble up
+ }
+
+ throw;
+ }
+ }
+
+ protected override DbBatchCommand CreateDbBatchCommand() => throw new NotImplementedException();
+
+ public override void Cancel()
+ => _wrappedBatch.Cancel();
+
+ protected override DbBatchCommandCollection DbBatchCommands => _wrappedBatch.BatchCommands;
+
+ public override int Timeout
+ {
+ get => _wrappedBatch.Timeout;
+ set => _wrappedBatch.Timeout = value;
+ }
+
+ public override void Dispose()
+ {
+ var connection = _wrappedBatch.Connection;
+
+ _wrappedBatch.Dispose();
+ connection!.Dispose();
+ }
+
+ public override async ValueTask DisposeAsync()
+ {
+ var connection = _wrappedBatch.Connection;
+
+ await _wrappedBatch.DisposeAsync().ConfigureAwait(false);
+ await connection!.DisposeAsync().ConfigureAwait(false);
+ }
+
+ // In most case, preparation doesn't make sense on a connectionless command since prepared statements are
+ // usually bound to specific physical connections.
+ // When prepared statements are global (not bound to a specific connection), providers would need to
+ // provide their own connection-less implementation anyway (i.e. interacting with the originating
+ // DbDataSource), so they'd have to override this in any case.
+ public override void Prepare()
+ => throw ExceptionBuilder.NotSupportedOnDataSourceCommand();
+
+ public override Task PrepareAsync(CancellationToken cancellationToken = default)
+ => Task.FromException(ExceptionBuilder.NotSupportedOnDataSourceCommand());
+
+ // The below are incompatible with batches executed directly against DbDataSource, since no DbConnection
+ // is involved at the user API level and the DbBatchWrapper owns the DbConnection.
+ protected override DbConnection? DbConnection
+ {
+ get => throw ExceptionBuilder.NotSupportedOnDataSourceBatch();
+ set => throw ExceptionBuilder.NotSupportedOnDataSourceBatch();
+ }
+
+ protected override DbTransaction? DbTransaction
+ {
+ get => throw ExceptionBuilder.NotSupportedOnDataSourceBatch();
+ set => throw ExceptionBuilder.NotSupportedOnDataSourceBatch();
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Data.Common/src/System/Data/Common/DbProviderFactory.cs b/src/libraries/System.Data.Common/src/System/Data/Common/DbProviderFactory.cs
index 7282338b540..f133e5a0cdd 100644
--- a/src/libraries/System.Data.Common/src/System/Data/Common/DbProviderFactory.cs
+++ b/src/libraries/System.Data.Common/src/System/Data/Common/DbProviderFactory.cs
@@ -66,5 +66,8 @@ namespace System.Data.Common
public virtual DbParameter? CreateParameter() => null;
public virtual DbDataSourceEnumerator? CreateDataSourceEnumerator() => null;
+
+ public virtual DbDataSource CreateDataSource(string connectionString)
+ => new DefaultDataSource(this, connectionString);
}
}
diff --git a/src/libraries/System.Data.Common/src/System/Data/Common/DefaultDataSource.cs b/src/libraries/System.Data.Common/src/System/Data/Common/DefaultDataSource.cs
new file mode 100644
index 00000000000..2829fb1b5aa
--- /dev/null
+++ b/src/libraries/System.Data.Common/src/System/Data/Common/DefaultDataSource.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Data.Common
+{
+ internal sealed class DefaultDataSource : DbDataSource
+ {
+ private readonly DbProviderFactory _dbProviderFactory;
+ private readonly string _connectionString;
+
+ internal DefaultDataSource(DbProviderFactory dbProviderFactory, string connectionString)
+ {
+ _dbProviderFactory = dbProviderFactory;
+ _connectionString = connectionString;
+ }
+
+ public override string ConnectionString => _connectionString;
+
+ protected override DbConnection CreateDbConnection()
+ {
+ var connection = _dbProviderFactory.CreateConnection();
+ if (connection is null)
+ {
+ throw new InvalidOperationException("DbProviderFactory returned a null connection");
+ }
+
+ connection.ConnectionString = _connectionString;
+
+ return connection;
+ }
+ }
+}
diff --git a/src/libraries/System.Data.Common/src/System/Data/DataException.cs b/src/libraries/System.Data.Common/src/System/Data/DataException.cs
index 7696f42c3db..ffc9b5c9682 100644
--- a/src/libraries/System.Data.Common/src/System/Data/DataException.cs
+++ b/src/libraries/System.Data.Common/src/System/Data/DataException.cs
@@ -352,6 +352,17 @@ namespace System.Data
public static Exception ArgumentContainsNull(string paramName) => _Argument(paramName, SR.Format(SR.Data_ArgumentContainsNull, paramName));
public static Exception TypeNotAllowed(Type type) => _InvalidOperation(SR.Format(SR.Data_TypeNotAllowed, type.AssemblyQualifiedName));
+ //
+ // Batch
+ //
+
+ public static Exception NotSupportedOnDataSourceBatch() => Common.ADP.NotSupported(SR.Batch_NotSupportedOnDataSourceBatch);
+
+ //
+ // Command
+ //
+
+ public static Exception NotSupportedOnDataSourceCommand() => Common.ADP.NotSupported(SR.Command_NotSupportedOnDataSourceCommand);
//
// Collections
diff --git a/src/libraries/System.Diagnostics.Process/tests/RemotelyInvokable.cs b/src/libraries/System.Diagnostics.Process/tests/RemotelyInvokable.cs
index 7d7fa6657c0..a61596b687e 100644
--- a/src/libraries/System.Diagnostics.Process/tests/RemotelyInvokable.cs
+++ b/src/libraries/System.Diagnostics.Process/tests/RemotelyInvokable.cs
@@ -99,7 +99,7 @@ namespace System.Diagnostics.Tests
public static int WriteSlowlyByByte()
{
var stdout = Console.OpenStandardOutput();
- var bytes = new byte[] { 97, 0 }; //Encoding.Unicode.GetBytes("a");
+ var bytes = new byte[] { 97, 0 }; // Encoding.Unicode.GetBytes("a");
for (int i = 0; i != bytes.Length; ++i)
{
diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs
index 39f7c9b1605..229b6117da1 100644
--- a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs
+++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs
@@ -479,18 +479,18 @@ namespace System.DirectoryServices.Protocols.Tests
public static IEnumerable<object[]> TestCompareRequestTheory_TestData()
{
yield return new object[] { "input", "input", ResultCode.CompareTrue };
- yield return new object[] { "input", Encoding.UTF8.GetBytes("input"), ResultCode.CompareTrue };
+ yield return new object[] { "input", "input"u8.ToArray(), ResultCode.CompareTrue };
yield return new object[] { "input", "false", ResultCode.CompareFalse };
yield return new object[] { "input", new byte[] { 1, 2, 3, 4, 5 }, ResultCode.CompareFalse };
yield return new object[] { "http://example.com/", "http://example.com/", ResultCode.CompareTrue };
yield return new object[] { "http://example.com/", new Uri("http://example.com/"), ResultCode.CompareTrue };
- yield return new object[] { "http://example.com/", Encoding.UTF8.GetBytes("http://example.com/"), ResultCode.CompareTrue };
+ yield return new object[] { "http://example.com/", "http://example.com/"u8.ToArray(), ResultCode.CompareTrue };
yield return new object[] { "http://example.com/", "http://false/", ResultCode.CompareFalse };
yield return new object[] { "http://example.com/", new Uri("http://false/"), ResultCode.CompareFalse };
- yield return new object[] { "http://example.com/", Encoding.UTF8.GetBytes("http://false/"), ResultCode.CompareFalse };
+ yield return new object[] { "http://example.com/", "http://false/"u8.ToArray(), ResultCode.CompareFalse };
}
[ConditionalTheory(nameof(IsLdapConfigurationExist))]
diff --git a/src/libraries/System.Drawing.Common/tests/ImageTests.cs b/src/libraries/System.Drawing.Common/tests/ImageTests.cs
index cfd315a96cd..e1b8512835f 100644
--- a/src/libraries/System.Drawing.Common/tests/ImageTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/ImageTests.cs
@@ -238,7 +238,7 @@ namespace System.Drawing.Tests
// Change data.
PropertyItem item = source.GetPropertyItem(PropertyTagExifUserComment);
- item.Value = Encoding.ASCII.GetBytes("Hello World\0");
+ item.Value = "Hello World\0"u8.ToArray();
item.Len = item.Value.Length;
bitmap.SetPropertyItem(item);
@@ -253,7 +253,7 @@ namespace System.Drawing.Tests
// New data.
item.Id = propid;
- item.Value = Encoding.ASCII.GetBytes("New Value\0");
+ item.Value = "New Value\0"u8.ToArray();
item.Len = item.Value.Length;
bitmap.SetPropertyItem(item);
@@ -296,7 +296,7 @@ namespace System.Drawing.Tests
// Change data.
PropertyItem item = bitmap.GetPropertyItem(PropertyTagExifUserComment);
- item.Value = Encoding.ASCII.GetBytes("Hello World\0");
+ item.Value = "Hello World\0"u8.ToArray();
item.Len = item.Value.Length;
bitmap.SetPropertyItem(item);
@@ -339,7 +339,7 @@ namespace System.Drawing.Tests
// New data.
item.Id = propid;
- item.Value = Encoding.ASCII.GetBytes("New Value\0");
+ item.Value = "New Value\0"u8.ToArray();
item.Len = item.Value.Length;
bitmap.SetPropertyItem(item);
@@ -439,7 +439,7 @@ namespace System.Drawing.Tests
// Change data.
PropertyItem item = source.GetPropertyItem(PropertyTagExifUserComment);
- item.Value = Encoding.ASCII.GetBytes("Hello World\0");
+ item.Value = "Hello World\0"u8.ToArray();
item.Len = item.Value.Length;
bitmap.SetPropertyItem(item);
@@ -454,7 +454,7 @@ namespace System.Drawing.Tests
// New data.
item.Id = propid;
- item.Value = Encoding.ASCII.GetBytes("New Value\0");
+ item.Value = "New Value\0"u8.ToArray();
item.Len = item.Value.Length;
bitmap.SetPropertyItem(item);
diff --git a/src/libraries/System.Formats.Asn1/tests/Reader/ReadGeneralizedTime.cs b/src/libraries/System.Formats.Asn1/tests/Reader/ReadGeneralizedTime.cs
index 6583a7d3936..cdd3437a007 100644
--- a/src/libraries/System.Formats.Asn1/tests/Reader/ReadGeneralizedTime.cs
+++ b/src/libraries/System.Formats.Asn1/tests/Reader/ReadGeneralizedTime.cs
@@ -229,7 +229,7 @@ namespace System.Formats.Asn1.Tests.Reader
[Fact]
public static void ExcessivelyPreciseFraction()
{
- byte[] inputData = Text.Encoding.ASCII.GetBytes("\u0018\u002A2017092118.012345678901234567890123456789Z");
+ byte[] inputData = "\u0018\u002A2017092118.012345678901234567890123456789Z"u8.ToArray();
AsnReader berReader = new AsnReader(inputData, AsnEncodingRules.BER);
DateTimeOffset value = berReader.ReadGeneralizedTime();
@@ -244,7 +244,7 @@ namespace System.Formats.Asn1.Tests.Reader
[Fact]
public static void ExcessivelyPreciseFraction_OneTenthPlusEpsilon()
{
- byte[] inputData = Text.Encoding.ASCII.GetBytes("\u0018\u002A20170921180044.10000000000000000000000001Z");
+ byte[] inputData = "\u0018\u002A20170921180044.10000000000000000000000001Z"u8.ToArray();
AsnReader derReader = new AsnReader(inputData, AsnEncodingRules.DER);
DateTimeOffset value = derReader.ReadGeneralizedTime();
@@ -287,7 +287,7 @@ namespace System.Formats.Asn1.Tests.Reader
[Fact]
public static void ExcessivelyPreciseFraction_OneTenthPlusEpsilonAndZero()
{
- byte[] inputData = Text.Encoding.ASCII.GetBytes("\u0018\u002A20170921180044.10000000000000000000000010Z");
+ byte[] inputData = "\u0018\u002A20170921180044.10000000000000000000000010Z"u8.ToArray();
AsnReader berReader = new AsnReader(inputData, AsnEncodingRules.BER);
DateTimeOffset value = berReader.ReadGeneralizedTime();
@@ -305,7 +305,7 @@ namespace System.Formats.Asn1.Tests.Reader
[Fact]
public static void ExcessivelyPreciseNonFraction()
{
- byte[] inputData = Text.Encoding.ASCII.GetBytes("\u0018\u002A2017092118.012345678901234567890123Q56789Z");
+ byte[] inputData = "\u0018\u002A2017092118.012345678901234567890123Q56789Z"u8.ToArray();
AsnReader berReader = new AsnReader(inputData, AsnEncodingRules.BER);
Assert.Throws<AsnContentException>(() => berReader.ReadGeneralizedTime());
diff --git a/src/libraries/System.Formats.Tar/ref/System.Formats.Tar.cs b/src/libraries/System.Formats.Tar/ref/System.Formats.Tar.cs
index 642433227b1..702b5ee604d 100644
--- a/src/libraries/System.Formats.Tar/ref/System.Formats.Tar.cs
+++ b/src/libraries/System.Formats.Tar/ref/System.Formats.Tar.cs
@@ -42,6 +42,14 @@ namespace System.Formats.Tar
public void ExtractToFile(string destinationFileName, bool overwrite) { }
public override string ToString() { throw null; }
}
+ public enum TarEntryFormat
+ {
+ Unknown = 0,
+ V7 = 1,
+ Ustar = 2,
+ Pax = 3,
+ Gnu = 4,
+ }
public enum TarEntryType : byte
{
V7RegularFile = (byte)0,
@@ -87,18 +95,10 @@ namespace System.Formats.Tar
GroupSpecial = 1024,
UserSpecial = 2048,
}
- public enum TarFormat
- {
- Unknown = 0,
- V7 = 1,
- Ustar = 2,
- Pax = 3,
- Gnu = 4,
- }
public sealed partial class TarReader : System.IDisposable
{
public TarReader(System.IO.Stream archiveStream, bool leaveOpen = false) { }
- public System.Formats.Tar.TarFormat Format { get { throw null; } }
+ public System.Formats.Tar.TarEntryFormat Format { get { throw null; } }
public System.Collections.Generic.IReadOnlyDictionary<string, string>? GlobalExtendedAttributes { get { throw null; } }
public void Dispose() { }
public System.Formats.Tar.TarEntry? GetNextEntry(bool copyData = false) { throw null; }
@@ -106,8 +106,8 @@ namespace System.Formats.Tar
public sealed partial class TarWriter : System.IDisposable
{
public TarWriter(System.IO.Stream archiveStream, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>>? globalExtendedAttributes = null, bool leaveOpen = false) { }
- public TarWriter(System.IO.Stream archiveStream, System.Formats.Tar.TarFormat archiveFormat, bool leaveOpen = false) { }
- public System.Formats.Tar.TarFormat Format { get { throw null; } }
+ public TarWriter(System.IO.Stream archiveStream, System.Formats.Tar.TarEntryFormat archiveFormat, bool leaveOpen = false) { }
+ public System.Formats.Tar.TarEntryFormat Format { get { throw null; } }
public void Dispose() { }
public void WriteEntry(System.Formats.Tar.TarEntry entry) { }
public void WriteEntry(string fileName, string? entryName) { }
diff --git a/src/libraries/System.Formats.Tar/src/System.Formats.Tar.csproj b/src/libraries/System.Formats.Tar/src/System.Formats.Tar.csproj
index d866dc3e3f9..65aa346b490 100644
--- a/src/libraries/System.Formats.Tar/src/System.Formats.Tar.csproj
+++ b/src/libraries/System.Formats.Tar/src/System.Formats.Tar.csproj
@@ -21,12 +21,12 @@
<Compile Include="System\Formats\Tar\TarHeader.Write.cs" />
<Compile Include="System\Formats\Tar\TarHelpers.cs" />
<Compile Include="System\Formats\Tar\TarEntry.cs" />
+ <Compile Include="System\Formats\Tar\TarEntryFormat.cs" />
<Compile Include="System\Formats\Tar\UstarTarEntry.cs" />
<Compile Include="System\Formats\Tar\GnuTarEntry.cs" />
<Compile Include="System\Formats\Tar\PaxTarEntry.cs" />
<Compile Include="System\Formats\Tar\TarEntryType.cs" />
<Compile Include="System\Formats\Tar\TarFile.cs" />
- <Compile Include="System\Formats\Tar\TarFormat.cs" />
<Compile Include="System\Formats\Tar\TarReader.cs" />
<Compile Include="System\Formats\Tar\TarWriter.cs" />
<Compile Include="System\Formats\Tar\SubReadStream.cs" />
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/GnuTarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/GnuTarEntry.cs
index 252a95fe378..af01516d88a 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/GnuTarEntry.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/GnuTarEntry.cs
@@ -6,7 +6,7 @@ namespace System.Formats.Tar
/// <summary>
/// Represents a tar entry from an archive of the GNU format.
/// </summary>
- /// <remarks>Even though the <see cref="TarFormat.Gnu"/> format is not POSIX compatible, it implements and supports the Unix-specific fields that were defined in the POSIX IEEE P1003.1 standard from 1988: <c>devmajor</c>, <c>devminor</c>, <c>gname</c> and <c>uname</c>.</remarks>
+ /// <remarks>Even though the <see cref="TarEntryFormat.Gnu"/> format is not POSIX compatible, it implements and supports the Unix-specific fields that were defined in the POSIX IEEE P1003.1 standard from 1988: <c>devmajor</c>, <c>devminor</c>, <c>gname</c> and <c>uname</c>.</remarks>
public sealed class GnuTarEntry : PosixTarEntry
{
// Constructor used when reading an existing archive.
@@ -29,7 +29,7 @@ namespace System.Formats.Tar
/// </list>
/// </remarks>
public GnuTarEntry(TarEntryType entryType, string entryName)
- : base(entryType, entryName, TarFormat.Gnu)
+ : base(entryType, entryName, TarEntryFormat.Gnu)
{
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PaxTarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PaxTarEntry.cs
index 54b44f71a55..fc5b9c3dbee 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PaxTarEntry.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PaxTarEntry.cs
@@ -50,7 +50,7 @@ namespace System.Formats.Tar
/// </list>
/// </remarks>
public PaxTarEntry(TarEntryType entryType, string entryName)
- : base(entryType, entryName, TarFormat.Pax)
+ : base(entryType, entryName, TarEntryFormat.Pax)
{
}
@@ -84,7 +84,7 @@ namespace System.Formats.Tar
/// </list>
/// </remarks>
public PaxTarEntry(TarEntryType entryType, string entryName, IEnumerable<KeyValuePair<string, string>> extendedAttributes)
- : base(entryType, entryName, TarFormat.Pax)
+ : base(entryType, entryName, TarEntryFormat.Pax)
{
ArgumentNullException.ThrowIfNull(extendedAttributes);
_header.ReplaceNormalAttributesWithExtended(extendedAttributes);
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PosixTarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PosixTarEntry.cs
index 0b682454f38..c3d8394ea8f 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PosixTarEntry.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/PosixTarEntry.cs
@@ -4,10 +4,10 @@
namespace System.Formats.Tar
{
/// <summary>
- /// Abstract class that represents a tar entry from an archive of a format that is based on the POSIX IEEE P1003.1 standard from 1988. This includes the formats <see cref="TarFormat.Ustar"/> (represented by the <see cref="UstarTarEntry"/> class), <see cref="TarFormat.Pax"/> (represented by the <see cref="PaxTarEntry"/> class) and <see cref="TarFormat.Gnu"/> (represented by the <see cref="GnuTarEntry"/> class).
+ /// Abstract class that represents a tar entry from an archive of a format that is based on the POSIX IEEE P1003.1 standard from 1988. This includes the formats <see cref="TarEntryFormat.Ustar"/> (represented by the <see cref="UstarTarEntry"/> class), <see cref="TarEntryFormat.Pax"/> (represented by the <see cref="PaxTarEntry"/> class) and <see cref="TarEntryFormat.Gnu"/> (represented by the <see cref="GnuTarEntry"/> class).
/// </summary>
/// <remarks>Formats that implement the POSIX IEEE P1003.1 standard from 1988, support the following header fields: <c>devmajor</c>, <c>devminor</c>, <c>gname</c> and <c>uname</c>.
- /// Even though the <see cref="TarFormat.Gnu"/> format is not POSIX compatible, it implements and supports the Unix-specific fields that were defined in that POSIX standard.</remarks>
+ /// Even though the <see cref="TarEntryFormat.Gnu"/> format is not POSIX compatible, it implements and supports the Unix-specific fields that were defined in that POSIX standard.</remarks>
public abstract partial class PosixTarEntry : TarEntry
{
// Constructor used when reading an existing archive.
@@ -17,7 +17,7 @@ namespace System.Formats.Tar
}
// Constructor called when creating a new 'TarEntry*' instance that can be passed to a TarWriter.
- internal PosixTarEntry(TarEntryType entryType, string entryName, TarFormat format)
+ internal PosixTarEntry(TarEntryType entryType, string entryName, TarEntryFormat format)
: base(entryType, entryName, format)
{
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs
index ce5e076cfc3..a2328ea9691 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs
@@ -11,7 +11,7 @@ namespace System.Formats.Tar
/// <summary>
/// Abstract class that represents a tar entry from an archive.
/// </summary>
- /// <remarks>All the properties exposed by this class are supported by the <see cref="TarFormat.V7"/>, <see cref="TarFormat.Ustar"/>, <see cref="TarFormat.Pax"/> and <see cref="TarFormat.Gnu"/> formats.</remarks>
+ /// <remarks>All the properties exposed by this class are supported by the <see cref="TarEntryFormat.V7"/>, <see cref="TarEntryFormat.Ustar"/>, <see cref="TarEntryFormat.Pax"/> and <see cref="TarEntryFormat.Gnu"/> formats.</remarks>
public abstract partial class TarEntry
{
internal TarHeader _header;
@@ -26,7 +26,7 @@ namespace System.Formats.Tar
}
// Constructor called when creating a new 'TarEntry*' instance that can be passed to a TarWriter.
- internal TarEntry(TarEntryType entryType, string entryName, TarFormat format)
+ internal TarEntry(TarEntryType entryType, string entryName, TarEntryFormat format)
{
ArgumentException.ThrowIfNullOrEmpty(entryName);
@@ -93,7 +93,7 @@ namespace System.Formats.Tar
/// <summary>
/// When the <see cref="EntryType"/> indicates an entry that can contain data, this property returns the length in bytes of such data.
/// </summary>
- /// <remarks>The entry type that commonly contains data is <see cref="TarEntryType.RegularFile"/> (or <see cref="TarEntryType.V7RegularFile"/> in the <see cref="TarFormat.V7"/> format). Other uncommon entry types that can also contain data are: <see cref="TarEntryType.ContiguousFile"/>, <see cref="TarEntryType.DirectoryList"/>, <see cref="TarEntryType.MultiVolume"/> and <see cref="TarEntryType.SparseFile"/>.</remarks>
+ /// <remarks>The entry type that commonly contains data is <see cref="TarEntryType.RegularFile"/> (or <see cref="TarEntryType.V7RegularFile"/> in the <see cref="TarEntryFormat.V7"/> format). Other uncommon entry types that can also contain data are: <see cref="TarEntryType.ContiguousFile"/>, <see cref="TarEntryType.DirectoryList"/>, <see cref="TarEntryType.MultiVolume"/> and <see cref="TarEntryType.SparseFile"/>.</remarks>
public long Length => _header._dataStream != null ? _header._dataStream.Length : _header._size;
/// <summary>
@@ -211,7 +211,7 @@ namespace System.Formats.Tar
/// <value><para>Gets a stream that represents the data section of this entry.</para>
/// <para>Sets a new stream that represents the data section, if it makes sense for the <see cref="EntryType"/> to contain data; if a stream already existed, the old stream gets disposed before substituting it with the new stream. Setting a <see langword="null"/> stream is allowed.</para></value>
/// <remarks>If you write data to this data stream, make sure to rewind it to the desired start position before writing this entry into an archive using <see cref="TarWriter.WriteEntry(TarEntry)"/>.</remarks>
- /// <exception cref="InvalidOperationException">Setting a data section is not supported because the <see cref="EntryType"/> is not <see cref="TarEntryType.RegularFile"/> (or <see cref="TarEntryType.V7RegularFile"/> for an archive of <see cref="TarFormat.V7"/> format).</exception>
+ /// <exception cref="InvalidOperationException">Setting a data section is not supported because the <see cref="EntryType"/> is not <see cref="TarEntryType.RegularFile"/> (or <see cref="TarEntryType.V7RegularFile"/> for an archive of <see cref="TarEntryFormat.V7"/> format).</exception>
/// <exception cref="IOException"><para>Cannot set an unreadable stream.</para>
/// <para>-or-</para>
/// <para>An I/O problem occurred.</para></exception>
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFormat.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryFormat.cs
index 1f4bd40327f..e215dcbff31 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFormat.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryFormat.cs
@@ -4,28 +4,28 @@
namespace System.Formats.Tar
{
/// <summary>
- /// Specifies the supported Tar formats.
+ /// Specifies the supported formats that tar entries can use.
/// </summary>
- public enum TarFormat
+ public enum TarEntryFormat
{
/// <summary>
- /// Tar format undetermined.
+ /// Tar entry format undetermined.
/// </summary>
Unknown,
/// <summary>
- /// 1979 Version 7 AT&amp;T Unix Tar Command Format (v7).
+ /// 1979 Version 7 AT&amp;T Unix tar entry format.
/// </summary>
V7,
/// <summary>
- /// POSIX IEEE 1003.1-1988 Unix Standard Tar Format (ustar).
+ /// POSIX IEEE 1003.1-1988 Unix Standard tar entry format.
/// </summary>
Ustar,
/// <summary>
- /// POSIX IEEE 1003.1-2001 ("POSIX.1") Pax Interchange Tar Format (pax).
+ /// POSIX IEEE 1003.1-2001 ("POSIX.1") Pax Interchange tar entry format.
/// </summary>
Pax,
/// <summary>
- /// GNU Tar Format (gnu).
+ /// GNU tar entry format (gnu).
/// </summary>
Gnu,
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryType.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryType.cs
index 3f3e61556eb..b297f178fad 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryType.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntryType.cs
@@ -11,7 +11,7 @@ namespace System.Formats.Tar
{
/// <summary>
/// <para>Regular file.</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.Ustar"/>, <see cref="TarFormat.Pax"/> and <see cref="TarFormat.Gnu"/> formats.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.Ustar"/>, <see cref="TarEntryFormat.Pax"/> and <see cref="TarEntryFormat.Gnu"/> formats.</para>
/// </summary>
RegularFile = (byte)'0',
/// <summary>
@@ -43,7 +43,7 @@ namespace System.Formats.Tar
Fifo = (byte)'6',
/// <summary>
/// <para>GNU contiguous file</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.Gnu"/> format, and is treated as a <see cref="RegularFile"/> entry type.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.Gnu"/> format, and is treated as a <see cref="RegularFile"/> entry type.</para>
/// </summary>
// According to the GNU spec, it's extremely rare to encounter a contiguous entry.
ContiguousFile = (byte)'7',
@@ -59,7 +59,7 @@ namespace System.Formats.Tar
GlobalExtendedAttributes = (byte)'g',
/// <summary>
/// <para>GNU directory with a list of entries.</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.Gnu"/> format, and is treated as a <see cref="Directory"/> entry type that contains a data section.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.Gnu"/> format, and is treated as a <see cref="Directory"/> entry type that contains a data section.</para>
/// </summary>
DirectoryList = (byte)'D',
/// <summary>
@@ -74,27 +74,27 @@ namespace System.Formats.Tar
LongPath = (byte)'L',
/// <summary>
/// <para>GNU multi-volume file.</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.Gnu"/> format and is not supported for writing.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.Gnu"/> format and is not supported for writing.</para>
/// </summary>
MultiVolume = (byte)'M',
/// <summary>
/// <para>V7 Regular file.</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.V7"/> format.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.V7"/> format.</para>
/// </summary>
V7RegularFile = (byte)'\0',
/// <summary>
/// <para>GNU file to be renamed/symlinked.</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.Gnu"/> format. It is considered unsafe and is ignored by other tools.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.Gnu"/> format. It is considered unsafe and is ignored by other tools.</para>
/// </summary>
RenamedOrSymlinked = (byte)'N',
/// <summary>
/// <para>GNU sparse file.</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.Gnu"/> format and is not supported for writing.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.Gnu"/> format and is not supported for writing.</para>
/// </summary>
SparseFile = (byte)'S',
/// <summary>
/// <para>GNU tape volume.</para>
- /// <para>This entry type is specific to the <see cref="TarFormat.Gnu"/> format and is not supported for writing.</para>
+ /// <para>This entry type is specific to the <see cref="TarEntryFormat.Gnu"/> format and is not supported for writing.</para>
/// </summary>
TapeVolume = (byte)'V',
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFile.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFile.cs
index ba56ac87441..66e87920fe2 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFile.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarFile.cs
@@ -196,7 +196,7 @@ namespace System.Formats.Tar
Debug.Assert(Path.IsPathFullyQualified(sourceDirectoryName));
Debug.Assert(destination.CanWrite);
- using (TarWriter writer = new TarWriter(destination, TarFormat.Pax, leaveOpen))
+ using (TarWriter writer = new TarWriter(destination, TarEntryFormat.Pax, leaveOpen))
{
bool baseDirectoryIsEmpty = true;
DirectoryInfo di = new(sourceDirectoryName);
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Read.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Read.cs
index 1e46719c839..2e92a7429e8 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Read.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Read.cs
@@ -39,7 +39,7 @@ namespace System.Formats.Tar
// Confirms if gnu, or tentatively selects ustar
ReadMagicAttribute(buffer);
- if (_format != TarFormat.V7)
+ if (_format != TarEntryFormat.V7)
{
// Confirms if gnu
ReadVersionAttribute(buffer);
@@ -47,12 +47,12 @@ namespace System.Formats.Tar
// Fields that ustar, pax and gnu share identically
ReadPosixAndGnuSharedAttributes(buffer);
- Debug.Assert(_format is TarFormat.Ustar or TarFormat.Pax or TarFormat.Gnu);
- if (_format == TarFormat.Ustar)
+ Debug.Assert(_format is TarEntryFormat.Ustar or TarEntryFormat.Pax or TarEntryFormat.Gnu);
+ if (_format == TarEntryFormat.Ustar)
{
ReadUstarAttributes(buffer);
}
- else if (_format == TarFormat.Gnu)
+ else if (_format == TarEntryFormat.Gnu)
{
ReadGnuAttributes(buffer);
}
@@ -334,12 +334,12 @@ namespace System.Formats.Tar
_typeFlag = (TarEntryType)buffer[FieldLocations.TypeFlag];
_linkName = TarHelpers.GetTrimmedUtf8String(buffer.Slice(FieldLocations.LinkName, FieldLengths.LinkName));
- if (_format == TarFormat.Unknown)
+ if (_format == TarEntryFormat.Unknown)
{
_format = _typeFlag switch
{
TarEntryType.ExtendedAttributes or
- TarEntryType.GlobalExtendedAttributes => TarFormat.Pax,
+ TarEntryType.GlobalExtendedAttributes => TarEntryFormat.Pax,
TarEntryType.DirectoryList or
TarEntryType.LongLink or
@@ -347,14 +347,14 @@ namespace System.Formats.Tar
TarEntryType.MultiVolume or
TarEntryType.RenamedOrSymlinked or
TarEntryType.SparseFile or
- TarEntryType.TapeVolume => TarFormat.Gnu,
+ TarEntryType.TapeVolume => TarEntryFormat.Gnu,
// V7 is the only one that uses 'V7RegularFile'.
- TarEntryType.V7RegularFile => TarFormat.V7,
+ TarEntryType.V7RegularFile => TarEntryFormat.V7,
// We can quickly determine the *minimum* possible format if the entry type
// is the POSIX 'RegularFile', although later we could upgrade it to PAX or GNU
- _ => (_typeFlag == TarEntryType.RegularFile) ? TarFormat.Ustar : TarFormat.V7
+ _ => (_typeFlag == TarEntryType.RegularFile) ? TarEntryFormat.Ustar : TarEntryFormat.V7
};
}
@@ -370,7 +370,7 @@ namespace System.Formats.Tar
// If at this point the magic value is all nulls, we definitely have a V7
if (TarHelpers.IsAllNullBytes(magic))
{
- _format = TarFormat.V7;
+ _format = TarEntryFormat.V7;
return;
}
@@ -379,12 +379,12 @@ namespace System.Formats.Tar
if (_magic == GnuMagic)
{
- _format = TarFormat.Gnu;
+ _format = TarEntryFormat.Gnu;
}
- else if (_format == TarFormat.V7 && _magic == UstarMagic)
+ else if (_format == TarEntryFormat.V7 && _magic == UstarMagic)
{
// Important: Only change to ustar if we had not changed the format to pax already
- _format = TarFormat.Ustar;
+ _format = TarEntryFormat.Ustar;
}
}
@@ -392,7 +392,7 @@ namespace System.Formats.Tar
// Throws if converting the bytes to string fails or if an unexpected version string is found.
private void ReadVersionAttribute(Span<byte> buffer)
{
- if (_format == TarFormat.V7)
+ if (_format == TarEntryFormat.V7)
{
return;
}
@@ -402,13 +402,13 @@ namespace System.Formats.Tar
_version = Encoding.ASCII.GetString(version);
// The POSIX formats have a 6 byte Magic "ustar\0", followed by a 2 byte Version "00"
- if ((_format is TarFormat.Ustar or TarFormat.Pax) && _version != UstarVersion)
+ if ((_format is TarEntryFormat.Ustar or TarEntryFormat.Pax) && _version != UstarVersion)
{
throw new FormatException(string.Format(SR.TarPosixFormatExpected, _name));
}
// The GNU format has a Magic+Version 8 byte string "ustar \0"
- if (_format == TarFormat.Gnu && _version != GnuVersion)
+ if (_format == TarEntryFormat.Gnu && _version != GnuVersion)
{
throw new FormatException(string.Format(SR.TarGnuFormatExpected, _name));
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs
index 0c2cf88c9c7..099544778c3 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs
@@ -12,11 +12,11 @@ namespace System.Formats.Tar
// Writes header attributes of a tar archive entry.
internal partial struct TarHeader
{
- private static ReadOnlySpan<byte> PaxMagicBytes => new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x0 }; // "ustar\0"
- private static ReadOnlySpan<byte> PaxVersionBytes => new byte[] { TarHelpers.ZeroChar, TarHelpers.ZeroChar }; // "00"
+ private static ReadOnlySpan<byte> PaxMagicBytes => "ustar\0"u8;
+ private static ReadOnlySpan<byte> PaxVersionBytes => "00"u8;
- private static ReadOnlySpan<byte> GnuMagicBytes => new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, TarHelpers.SpaceChar }; // "ustar "
- private static ReadOnlySpan<byte> GnuVersionBytes => new byte[] { TarHelpers.SpaceChar, 0x0 }; // " \0"
+ private static ReadOnlySpan<byte> GnuMagicBytes => "ustar "u8;
+ private static ReadOnlySpan<byte> GnuVersionBytes => " \0"u8;
// Extended Attribute entries have a special format in the Name field:
// "{dirName}/PaxHeaders.{processId}/{fileName}{trailingSeparator}"
@@ -48,7 +48,7 @@ namespace System.Formats.Tar
internal void WriteAsV7(Stream archiveStream, Span<byte> buffer)
{
long actualLength = GetTotalDataBytesToWrite();
- TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarFormat.V7);
+ TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarEntryFormat.V7);
int checksum = WriteName(buffer, out _);
checksum += WriteCommonFields(buffer, actualLength, actualEntryType);
@@ -66,7 +66,7 @@ namespace System.Formats.Tar
internal void WriteAsUstar(Stream archiveStream, Span<byte> buffer)
{
long actualLength = GetTotalDataBytesToWrite();
- TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarFormat.Ustar);
+ TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarEntryFormat.Ustar);
int checksum = WritePosixName(buffer);
checksum += WriteCommonFields(buffer, actualLength, actualEntryType);
@@ -153,7 +153,7 @@ namespace System.Formats.Tar
_gnuUnusedBytes ??= new byte[FieldLengths.AllGnuUnused];
long actualLength = GetTotalDataBytesToWrite();
- TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarFormat.Gnu);
+ TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarEntryFormat.Gnu);
int checksum = WriteName(buffer, out _);
checksum += WriteCommonFields(buffer, actualLength, actualEntryType);
@@ -194,7 +194,7 @@ namespace System.Formats.Tar
private void WriteAsPaxInternal(Stream archiveStream, Span<byte> buffer)
{
long actualLength = GetTotalDataBytesToWrite();
- TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarFormat.Pax);
+ TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarEntryFormat.Pax);
int checksum = WritePosixName(buffer);
checksum += WriteCommonFields(buffer, actualLength, actualEntryType);
@@ -275,9 +275,9 @@ namespace System.Formats.Tar
// When writing an entry that came from an archive of a different format, if its entry type happens to
// be an incompatible regular file entry type, convert it to the compatible one.
// No change for all other entry types.
- private TarEntryType GetCorrectTypeFlagForFormat(TarFormat format)
+ private TarEntryType GetCorrectTypeFlagForFormat(TarEntryFormat format)
{
- if (format is TarFormat.V7)
+ if (format is TarEntryFormat.V7)
{
if (_typeFlag is TarEntryType.RegularFile)
{
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs
index aa0bab5aae0..217b16efb21 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs
@@ -43,7 +43,7 @@ namespace System.Formats.Tar
// Position in the stream where the data ends in this header.
internal long _endOfHeaderAndDataAndBlockAlignment;
- internal TarFormat _format;
+ internal TarEntryFormat _format;
// Common attributes
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs
index db80de8ef02..dc0b16d77d5 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs
@@ -179,11 +179,11 @@ namespace System.Formats.Tar
// Throws if the specified entry type is not supported for the specified format.
// If 'forWriting' is true, an incompatible 'Regular File' entry type is allowed. It will be converted to the compatible version before writing.
- internal static void VerifyEntryTypeIsSupported(TarEntryType entryType, TarFormat archiveFormat, bool forWriting)
+ internal static void VerifyEntryTypeIsSupported(TarEntryType entryType, TarEntryFormat archiveFormat, bool forWriting)
{
switch (archiveFormat)
{
- case TarFormat.V7:
+ case TarEntryFormat.V7:
if (entryType is
TarEntryType.Directory or
TarEntryType.HardLink or
@@ -198,7 +198,7 @@ namespace System.Formats.Tar
}
break;
- case TarFormat.Ustar:
+ case TarEntryFormat.Ustar:
if (entryType is
TarEntryType.BlockDevice or
TarEntryType.CharacterDevice or
@@ -216,7 +216,7 @@ namespace System.Formats.Tar
}
break;
- case TarFormat.Pax:
+ case TarEntryFormat.Pax:
if (entryType is
TarEntryType.BlockDevice or
TarEntryType.CharacterDevice or
@@ -237,7 +237,7 @@ namespace System.Formats.Tar
}
break;
- case TarFormat.Gnu:
+ case TarEntryFormat.Gnu:
if (entryType is
TarEntryType.BlockDevice or
TarEntryType.CharacterDevice or
@@ -266,7 +266,7 @@ namespace System.Formats.Tar
}
break;
- case TarFormat.Unknown:
+ case TarEntryFormat.Unknown:
default:
throw new FormatException(string.Format(SR.TarInvalidFormat, archiveFormat));
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarReader.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarReader.cs
index 2aa5b3875d8..3c651c63da1 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarReader.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarReader.cs
@@ -41,19 +41,19 @@ namespace System.Formats.Tar
_previouslyReadEntry = null;
GlobalExtendedAttributes = null;
- Format = TarFormat.Unknown;
+ Format = TarEntryFormat.Unknown;
_isDisposed = false;
_readFirstEntry = false;
_reachedEndMarkers = false;
}
/// <summary>
- /// The format of the archive. It is initially <see cref="TarFormat.Unknown"/>. The archive format is detected after the first call to <see cref="GetNextEntry(bool)"/>.
+ /// The format of the archive. It is initially <see cref="TarEntryFormat.Unknown"/>. The archive format is detected after the first call to <see cref="GetNextEntry(bool)"/>.
/// </summary>
- public TarFormat Format { get; private set; }
+ public TarEntryFormat Format { get; private set; }
/// <summary>
- /// <para>If the archive format is <see cref="TarFormat.Pax"/>, returns a read-only dictionary containing the string key-value pairs of the Global Extended Attributes in the first entry of the archive.</para>
+ /// <para>If the archive format is <see cref="TarEntryFormat.Pax"/>, returns a read-only dictionary containing the string key-value pairs of the Global Extended Attributes in the first entry of the archive.</para>
/// <para>If there is no Global Extended Attributes entry at the beginning of the archive, this returns an empty read-only dictionary.</para>
/// <para>If the first entry has not been read by calling <see cref="GetNextEntry(bool)"/>, this returns <see langword="null"/>.</para>
/// </summary>
@@ -89,9 +89,9 @@ namespace System.Formats.Tar
/// <para>-or-</para>
/// <para>The archive contains entries in different formats.</para>
/// <para>-or-</para>
- /// <para>More than one Global Extended Attributes Entry was found in the current <see cref="TarFormat.Pax"/> archive.</para>
+ /// <para>More than one Global Extended Attributes Entry was found in the current <see cref="TarEntryFormat.Pax"/> archive.</para>
/// <para>-or-</para>
- /// <para>Two or more Extended Attributes entries were found consecutively in the current <see cref="TarFormat.Pax"/> archive.</para></exception>
+ /// <para>Two or more Extended Attributes entries were found consecutively in the current <see cref="TarEntryFormat.Pax"/> archive.</para></exception>
/// <exception cref="IOException">An I/O problem occurred.</exception>
public TarEntry? GetNextEntry(bool copyData = false)
{
@@ -115,7 +115,7 @@ namespace System.Formats.Tar
{
if (!_readFirstEntry)
{
- Debug.Assert(Format == TarFormat.Unknown);
+ Debug.Assert(Format == TarEntryFormat.Unknown);
Format = header._format;
_readFirstEntry = true;
}
@@ -126,10 +126,10 @@ namespace System.Formats.Tar
TarEntry entry = Format switch
{
- TarFormat.Pax => new PaxTarEntry(header, this),
- TarFormat.Gnu => new GnuTarEntry(header, this),
- TarFormat.Ustar => new UstarTarEntry(header, this),
- TarFormat.V7 or TarFormat.Unknown or _ => new V7TarEntry(header, this),
+ TarEntryFormat.Pax => new PaxTarEntry(header, this),
+ TarEntryFormat.Gnu => new GnuTarEntry(header, this),
+ TarEntryFormat.Ustar => new UstarTarEntry(header, this),
+ TarEntryFormat.V7 or TarEntryFormat.Unknown or _ => new V7TarEntry(header, this),
};
_previouslyReadEntry = entry;
@@ -250,7 +250,7 @@ namespace System.Formats.Tar
GlobalExtendedAttributes = header._extendedAttributes?.AsReadOnly();
header = default;
- header._format = TarFormat.Pax;
+ header._format = TarEntryFormat.Pax;
try
{
if (!header.TryGetNextHeader(_archiveStream, copyData))
@@ -261,7 +261,7 @@ namespace System.Formats.Tar
catch (EndOfStreamException)
{
// Edge case: The only entry in the archive was a Global Extended Attributes entry
- Format = TarFormat.Pax;
+ Format = TarEntryFormat.Pax;
return false;
}
if (header._typeFlag == TarEntryType.GlobalExtendedAttributes)
@@ -308,7 +308,7 @@ namespace System.Formats.Tar
private bool TryProcessExtendedAttributesHeader(TarHeader firstHeader, bool copyData, out TarHeader secondHeader)
{
secondHeader = default;
- secondHeader._format = TarFormat.Pax;
+ secondHeader._format = TarEntryFormat.Pax;
// Now get the actual entry
if (!secondHeader.TryGetNextHeader(_archiveStream, copyData))
@@ -346,7 +346,7 @@ namespace System.Formats.Tar
finalHeader = default;
TarHeader secondHeader = default;
- secondHeader._format = TarFormat.Gnu;
+ secondHeader._format = TarEntryFormat.Gnu;
// Get the second entry, which is the actual entry
if (!secondHeader.TryGetNextHeader(_archiveStream, copyData))
@@ -365,7 +365,7 @@ namespace System.Formats.Tar
(header._typeFlag is TarEntryType.LongPath && secondHeader._typeFlag is TarEntryType.LongLink))
{
TarHeader thirdHeader = default;
- thirdHeader._format = TarFormat.Gnu;
+ thirdHeader._format = TarEntryFormat.Gnu;
// Get the third entry, which is the actual entry
if (!thirdHeader.TryGetNextHeader(_archiveStream, copyData))
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs
index 7fa73a3cf13..8296910d386 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Unix.cs
@@ -29,7 +29,7 @@ namespace System.Formats.Tar
Interop.Sys.FileTypes.S_IFCHR => TarEntryType.CharacterDevice,
Interop.Sys.FileTypes.S_IFIFO => TarEntryType.Fifo,
Interop.Sys.FileTypes.S_IFLNK => TarEntryType.SymbolicLink,
- Interop.Sys.FileTypes.S_IFREG => Format is TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile,
+ Interop.Sys.FileTypes.S_IFREG => Format is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile,
Interop.Sys.FileTypes.S_IFDIR => TarEntryType.Directory,
_ => throw new IOException(string.Format(SR.TarUnsupportedFile, fullPath)),
};
@@ -38,10 +38,10 @@ namespace System.Formats.Tar
TarEntry entry = Format switch
{
- TarFormat.V7 => new V7TarEntry(entryType, entryName),
- TarFormat.Ustar => new UstarTarEntry(entryType, entryName),
- TarFormat.Pax => new PaxTarEntry(entryType, entryName),
- TarFormat.Gnu => new GnuTarEntry(entryType, entryName),
+ TarEntryFormat.V7 => new V7TarEntry(entryType, entryName),
+ TarEntryFormat.Ustar => new UstarTarEntry(entryType, entryName),
+ TarEntryFormat.Pax => new PaxTarEntry(entryType, entryName),
+ TarEntryFormat.Gnu => new GnuTarEntry(entryType, entryName),
_ => throw new FormatException(string.Format(SR.TarInvalidFormat, Format)),
};
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Windows.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Windows.cs
index 5fdd3b97d85..bee4ac9b7c3 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Windows.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.Windows.cs
@@ -28,7 +28,7 @@ namespace System.Formats.Tar
}
else if (attributes.HasFlag(FileAttributes.Normal) || attributes.HasFlag(FileAttributes.Archive))
{
- entryType = Format is TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
+ entryType = Format is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
}
else
{
@@ -37,10 +37,10 @@ namespace System.Formats.Tar
TarEntry entry = Format switch
{
- TarFormat.V7 => new V7TarEntry(entryType, entryName),
- TarFormat.Ustar => new UstarTarEntry(entryType, entryName),
- TarFormat.Pax => new PaxTarEntry(entryType, entryName),
- TarFormat.Gnu => new GnuTarEntry(entryType, entryName),
+ TarEntryFormat.V7 => new V7TarEntry(entryType, entryName),
+ TarEntryFormat.Ustar => new UstarTarEntry(entryType, entryName),
+ TarEntryFormat.Pax => new PaxTarEntry(entryType, entryName),
+ TarEntryFormat.Gnu => new GnuTarEntry(entryType, entryName),
_ => throw new FormatException(string.Format(SR.TarInvalidFormat, Format)),
};
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.cs
index 4d715cdd6b3..ece218d02e9 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarWriter.cs
@@ -21,13 +21,13 @@ namespace System.Formats.Tar
private readonly IEnumerable<KeyValuePair<string, string>>? _globalExtendedAttributes;
/// <summary>
- /// Initializes a <see cref="TarWriter"/> instance that can write tar entries to the specified stream, optionally leave the stream open upon disposal of this instance, and can optionally add a Global Extended Attributes entry at the beginning of the archive. When using this constructor, the format of the resulting archive is <see cref="TarFormat.Pax"/>.
+ /// Initializes a <see cref="TarWriter"/> instance that can write tar entries to the specified stream, optionally leave the stream open upon disposal of this instance, and can optionally add a Global Extended Attributes entry at the beginning of the archive. When using this constructor, the format of the resulting archive is <see cref="TarEntryFormat.Pax"/>.
/// </summary>
/// <param name="archiveStream">The stream to write to.</param>
/// <param name="globalExtendedAttributes">An optional enumeration of string key-value pairs that represent Global Extended Attributes metadata that should apply to all subsquent entries. If <see langword="null"/>, then no Global Extended Attributes entry is written. If an empty instance is passed, a Global Extended Attributes entry is written with default values.</param>
/// <param name="leaveOpen"><see langword="false"/> to dispose the <paramref name="archiveStream"/> when this instance is disposed; <see langword="true"/> to leave the stream open.</param>
public TarWriter(Stream archiveStream, IEnumerable<KeyValuePair<string, string>>? globalExtendedAttributes = null, bool leaveOpen = false)
- : this(archiveStream, TarFormat.Pax, leaveOpen)
+ : this(archiveStream, TarEntryFormat.Pax, leaveOpen)
{
_globalExtendedAttributes = globalExtendedAttributes;
}
@@ -38,12 +38,12 @@ namespace System.Formats.Tar
/// <param name="archiveStream">The stream to write to.</param>
/// <param name="archiveFormat">The format of the archive.</param>
/// <param name="leaveOpen"><see langword="false"/> to dispose the <paramref name="archiveStream"/> when this instance is disposed; <see langword="true"/> to leave the stream open.</param>
- /// <remarks><para>If the selected <paramref name="archiveFormat"/> is <see cref="TarFormat.Pax"/>, no Global Extended Attributes entry is written. To write a PAX archive with a Global Extended Attributes entry inserted at the beginning of the archive, use the <see cref="TarWriter(Stream, IEnumerable{KeyValuePair{string, string}}?, bool)"/> constructor instead.</para>
- /// <para>The recommended format is <see cref="TarFormat.Pax"/> for its flexibility.</para></remarks>
+ /// <remarks><para>If the selected <paramref name="archiveFormat"/> is <see cref="TarEntryFormat.Pax"/>, no Global Extended Attributes entry is written. To write a PAX archive with a Global Extended Attributes entry inserted at the beginning of the archive, use the <see cref="TarWriter(Stream, IEnumerable{KeyValuePair{string, string}}?, bool)"/> constructor instead.</para>
+ /// <para>The recommended format is <see cref="TarEntryFormat.Pax"/> for its flexibility.</para></remarks>
/// <exception cref="ArgumentNullException"><paramref name="archiveStream"/> is <see langword="null"/>.</exception>
/// <exception cref="IOException"><paramref name="archiveStream"/> is unwritable.</exception>
- /// <exception cref="ArgumentOutOfRangeException"><paramref name="archiveFormat"/> is either <see cref="TarFormat.Unknown"/>, or not one of the other enum values.</exception>
- public TarWriter(Stream archiveStream, TarFormat archiveFormat, bool leaveOpen = false)
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="archiveFormat"/> is either <see cref="TarEntryFormat.Unknown"/>, or not one of the other enum values.</exception>
+ public TarWriter(Stream archiveStream, TarEntryFormat archiveFormat, bool leaveOpen = false)
{
ArgumentNullException.ThrowIfNull(archiveStream);
@@ -52,7 +52,7 @@ namespace System.Formats.Tar
throw new IOException(SR.IO_NotSupported_UnwritableStream);
}
- if (archiveFormat is not TarFormat.V7 and not TarFormat.Ustar and not TarFormat.Pax and not TarFormat.Gnu)
+ if (archiveFormat is not TarEntryFormat.V7 and not TarEntryFormat.Ustar and not TarEntryFormat.Pax and not TarEntryFormat.Gnu)
{
throw new ArgumentOutOfRangeException(nameof(archiveFormat));
}
@@ -69,7 +69,7 @@ namespace System.Formats.Tar
/// <summary>
/// The format of the archive.
/// </summary>
- public TarFormat Format { get; private set; }
+ public TarEntryFormat Format { get; private set; }
/// <summary>
/// Disposes the current <see cref="TarWriter"/> instance, and closes the archive stream if the <c>leaveOpen</c> argument was set to <see langword="false"/> in the constructor.
@@ -109,7 +109,7 @@ namespace System.Formats.Tar
entryName = Path.GetFileName(fileName);
}
- if (Format is TarFormat.Pax)
+ if (Format is TarEntryFormat.Pax)
{
WriteGlobalExtendedAttributesEntryIfNeeded();
}
@@ -136,7 +136,7 @@ namespace System.Formats.Tar
/// <para>These are the entry types supported for writing on each format:</para>
/// <list type="bullet">
/// <item>
- /// <para><see cref="TarFormat.V7"/></para>
+ /// <para><see cref="TarEntryFormat.V7"/></para>
/// <list type="bullet">
/// <item><see cref="TarEntryType.Directory"/></item>
/// <item><see cref="TarEntryType.HardLink"/></item>
@@ -145,7 +145,7 @@ namespace System.Formats.Tar
/// </list>
/// </item>
/// <item>
- /// <para><see cref="TarFormat.Ustar"/>, <see cref="TarFormat.Pax"/> and <see cref="TarFormat.Gnu"/></para>
+ /// <para><see cref="TarEntryFormat.Ustar"/>, <see cref="TarEntryFormat.Pax"/> and <see cref="TarEntryFormat.Gnu"/></para>
/// <list type="bullet">
/// <item><see cref="TarEntryType.BlockDevice"/></item>
/// <item><see cref="TarEntryType.CharacterDevice"/></item>
@@ -176,19 +176,19 @@ namespace System.Formats.Tar
{
switch (Format)
{
- case TarFormat.V7:
+ case TarEntryFormat.V7:
entry._header.WriteAsV7(_archiveStream, buffer);
break;
- case TarFormat.Ustar:
+ case TarEntryFormat.Ustar:
entry._header.WriteAsUstar(_archiveStream, buffer);
break;
- case TarFormat.Pax:
+ case TarEntryFormat.Pax:
entry._header.WriteAsPax(_archiveStream, buffer);
break;
- case TarFormat.Gnu:
+ case TarEntryFormat.Gnu:
entry._header.WriteAsGnu(_archiveStream, buffer);
break;
- case TarFormat.Unknown:
+ case TarEntryFormat.Unknown:
default:
throw new FormatException(string.Format(SR.TarInvalidFormat, Format));
}
@@ -210,7 +210,7 @@ namespace System.Formats.Tar
// /// <para>These are the entry types supported for writing on each format:</para>
// /// <list type="bullet">
// /// <item>
- // /// <para><see cref="TarFormat.V7"/></para>
+ // /// <para><see cref="TarEntryFormat.V7"/></para>
// /// <list type="bullet">
// /// <item><see cref="TarEntryType.Directory"/></item>
// /// <item><see cref="TarEntryType.HardLink"/></item>
@@ -219,7 +219,7 @@ namespace System.Formats.Tar
// /// </list>
// /// </item>
// /// <item>
- // /// <para><see cref="TarFormat.Ustar"/>, <see cref="TarFormat.Pax"/> and <see cref="TarFormat.Gnu"/></para>
+ // /// <para><see cref="TarEntryFormat.Ustar"/>, <see cref="TarEntryFormat.Pax"/> and <see cref="TarEntryFormat.Gnu"/></para>
// /// <list type="bullet">
// /// <item><see cref="TarEntryType.BlockDevice"/></item>
// /// <item><see cref="TarEntryType.CharacterDevice"/></item>
@@ -279,7 +279,7 @@ namespace System.Formats.Tar
{
Debug.Assert(!_isDisposed);
- if (_wroteGEA || Format != TarFormat.Pax)
+ if (_wroteGEA || Format != TarEntryFormat.Pax)
{
return;
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/UstarTarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/UstarTarEntry.cs
index 13e1d9c358a..b1cbaef8b16 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/UstarTarEntry.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/UstarTarEntry.cs
@@ -28,7 +28,7 @@ namespace System.Formats.Tar
/// </list>
/// </remarks>
public UstarTarEntry(TarEntryType entryType, string entryName)
- : base(entryType, entryName, TarFormat.Ustar)
+ : base(entryType, entryName, TarEntryFormat.Ustar)
{
}
diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/V7TarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/V7TarEntry.cs
index 84389365c73..6972daf20dc 100644
--- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/V7TarEntry.cs
+++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/V7TarEntry.cs
@@ -23,7 +23,7 @@ namespace System.Formats.Tar
/// <exception cref="InvalidOperationException">The entry type is not supported for creating an entry.</exception>
/// <remarks>When creating an instance using the <see cref="V7TarEntry(TarEntryType, string)"/> constructor, only the following entry types are supported: <see cref="TarEntryType.Directory"/>, <see cref="TarEntryType.HardLink"/>, <see cref="TarEntryType.SymbolicLink"/> and <see cref="TarEntryType.V7RegularFile"/>.</remarks>
public V7TarEntry(TarEntryType entryType, string entryName)
- : base(entryType, entryName, TarFormat.V7)
+ : base(entryType, entryName, TarEntryFormat.V7)
{
}
diff --git a/src/libraries/System.Formats.Tar/tests/CompressedTar.Tests.cs b/src/libraries/System.Formats.Tar/tests/CompressedTar.Tests.cs
index a056bc0eed9..d13bf469d73 100644
--- a/src/libraries/System.Formats.Tar/tests/CompressedTar.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/CompressedTar.Tests.cs
@@ -37,7 +37,7 @@ namespace System.Formats.Tar.Tests
using GZipStream decompressorStream = new GZipStream(streamToDecompress, CompressionMode.Decompress);
using TarReader reader = new TarReader(decompressorStream);
TarEntry entry = reader.GetNextEntry();
- Assert.Equal(TarFormat.Pax, reader.Format);
+ Assert.Equal(TarEntryFormat.Pax, reader.Format);
Assert.Equal(fileName, entry.Name);
Assert.Null(reader.GetNextEntry());
}
@@ -77,4 +77,4 @@ namespace System.Formats.Tar.Tests
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs
index 5bb0d9b2c3e..8b9af8b3bc3 100644
--- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs
@@ -52,7 +52,7 @@ namespace System.Formats.Tar.Tests
string fileWithTwoSegments = Path.Join(secondSegment, "c.txt");
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
// No preceding directory entries for the segments
UstarTarEntry entry = new UstarTarEntry(TarEntryType.RegularFile, fileWithTwoSegments);
@@ -78,7 +78,7 @@ namespace System.Formats.Tar.Tests
public void Extract_LinkEntry_TargetOutsideDirectory(TarEntryType entryType)
{
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry entry = new UstarTarEntry(entryType, "link");
entry.LinkName = PlatformDetection.IsWindows ? @"C:\Windows\System32\notepad.exe" : "/usr/bin/nano";
@@ -112,7 +112,7 @@ namespace System.Formats.Tar.Tests
File.Create(targetPath).Dispose();
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry entry = new UstarTarEntry(entryType, linkName);
entry.LinkName = targetPath;
diff --git a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs
index ef619edb472..02758eba6a4 100644
--- a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs
@@ -12,13 +12,13 @@ namespace System.Formats.Tar.Tests
public class TarReader_File_Tests : TarTestsBase
{
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_File(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_File(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "file";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -32,7 +32,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry file = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -50,13 +50,13 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_File_HardLink(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_File_HardLink(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "file_hardlink";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -69,7 +69,7 @@ namespace System.Formats.Tar.Tests
Assert.Null(reader.GlobalExtendedAttributes);
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry file = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -91,13 +91,13 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_File_SymbolicLink(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_File_SymbolicLink(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "file_symlink";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -111,7 +111,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry file = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -133,13 +133,13 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_Folder_File(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_Folder_File(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "folder_file";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -153,7 +153,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry directory = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -174,13 +174,13 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_Folder_File_Utf8(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_Folder_File_Utf8(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "folder_file_utf8";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -193,7 +193,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry directory = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -214,13 +214,13 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_Folder_Subfolder_File(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_Folder_Subfolder_File(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "folder_subfolder_file";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -233,7 +233,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry parent = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -257,13 +257,13 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_FolderSymbolicLink_Folder_Subfolder_File(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_FolderSymbolicLink_Folder_Subfolder_File(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "foldersymlink_folder_subfolder_file";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -276,7 +276,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry childlink = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -303,13 +303,13 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, TestTarFormat.v7)]
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_Many_Small_Files(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.V7, TestTarFormat.v7)]
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_Many_Small_Files(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "many_small_files";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -322,7 +322,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
List<TarEntry> entries = new List<TarEntry>();
TarEntry entry;
@@ -348,7 +348,7 @@ namespace System.Formats.Tar.Tests
int directoriesCount = entries.Count(e => e.EntryType == TarEntryType.Directory);
Assert.Equal(10, directoriesCount);
- TarEntryType regularFileEntryType = format == TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
+ TarEntryType regularFileEntryType = format == TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
for (int i = 0; i < 10; i++)
{
int filesCount = entries.Count(e => e.EntryType == regularFileEntryType && e.Name.StartsWith($"{i}/"));
@@ -358,12 +358,12 @@ namespace System.Formats.Tar.Tests
[Theory]
// V7 does not support longer filenames
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_LongPath_Splitable_Under255(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_LongPath_Splitable_Under255(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "longpath_splitable_under255";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -376,7 +376,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry directory = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -398,12 +398,12 @@ namespace System.Formats.Tar.Tests
[Theory]
// V7 does not support block devices, character devices or fifos
- [InlineData(TarFormat.Ustar, TestTarFormat.ustar)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_SpecialFiles(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.Ustar, TestTarFormat.ustar)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_SpecialFiles(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "specialfiles";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -416,7 +416,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
PosixTarEntry blockDevice = reader.GetNextEntry() as PosixTarEntry;
Assert.Equal(format, reader.Format);
@@ -441,11 +441,11 @@ namespace System.Formats.Tar.Tests
[Theory]
// Neither V7 not Ustar can handle links with long target filenames
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_File_LongSymbolicLink(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_File_LongSymbolicLink(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "file_longsymlink";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -458,7 +458,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry directory = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -483,11 +483,11 @@ namespace System.Formats.Tar.Tests
[Theory]
// Neither V7 not Ustar can handle a path that does not have separators that can be split under 100 bytes
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_LongFileName_Over100_Under255(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_LongFileName_Over100_Under255(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "longfilename_over100_under255";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -500,7 +500,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry file = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -519,11 +519,11 @@ namespace System.Formats.Tar.Tests
[Theory]
// Neither V7 not Ustar can handle path lenghts waaaay beyond name+prefix length
- [InlineData(TarFormat.Pax, TestTarFormat.pax)]
- [InlineData(TarFormat.Pax, TestTarFormat.pax_gea)]
- [InlineData(TarFormat.Gnu, TestTarFormat.gnu)]
- [InlineData(TarFormat.Gnu, TestTarFormat.oldgnu)]
- public void Read_Archive_LongPath_Over255(TarFormat format, TestTarFormat testFormat)
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax)]
+ [InlineData(TarEntryFormat.Pax, TestTarFormat.pax_gea)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.gnu)]
+ [InlineData(TarEntryFormat.Gnu, TestTarFormat.oldgnu)]
+ public void Read_Archive_LongPath_Over255(TarEntryFormat format, TestTarFormat testFormat)
{
string testCaseName = "longpath_over255";
using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);
@@ -536,7 +536,7 @@ namespace System.Formats.Tar.Tests
}
// Format is determined after reading the first entry, not on the constructor
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry directory = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -556,7 +556,7 @@ namespace System.Formats.Tar.Tests
Assert.Null(reader.GetNextEntry());
}
- private void Verify_Archive_RegularFile(TarEntry file, TarFormat format, IReadOnlyDictionary<string, string> gea, string expectedFileName, string expectedContents)
+ private void Verify_Archive_RegularFile(TarEntry file, TarEntryFormat format, IReadOnlyDictionary<string, string> gea, string expectedFileName, string expectedContents)
{
Assert.NotNull(file);
@@ -572,7 +572,7 @@ namespace System.Formats.Tar.Tests
Assert.Equal(expectedContents, contents);
}
- TarEntryType expectedEntryType = format == TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
+ TarEntryType expectedEntryType = format == TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
Assert.Equal(expectedEntryType, file.EntryType);
Assert.Equal(AssetGid, file.Gid);
diff --git a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs
index a9eccc625c0..bad9bf8fa17 100644
--- a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs
@@ -48,7 +48,7 @@ namespace System.Formats.Tar.Tests
{
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry entry = new UstarTarEntry(TarEntryType.Directory, "dir");
writer.WriteEntry(entry);
@@ -72,7 +72,7 @@ namespace System.Formats.Tar.Tests
{
string expectedText = "Hello world!";
MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt");
entry1.DataStream = new MemoryStream();
@@ -118,7 +118,7 @@ namespace System.Formats.Tar.Tests
{
string expectedText = "Hello world!";
MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt");
entry1.DataStream = new MemoryStream();
@@ -165,7 +165,7 @@ namespace System.Formats.Tar.Tests
public void GetNextEntry_CopyDataFalse_UnseekableArchive_Exceptions()
{
MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt");
entry1.DataStream = new MemoryStream();
@@ -208,7 +208,7 @@ namespace System.Formats.Tar.Tests
public void GetNextEntry_UnseekableArchive_ReplaceDataStream_ExcludeFromDisposing(bool copyData)
{
MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt");
entry1.DataStream = new MemoryStream();
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.Tests.cs
index 855d52d9bca..aab1bb1395d 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.Tests.cs
@@ -13,7 +13,7 @@ namespace System.Formats.Tar.Tests
public void Constructors_NullStream()
{
Assert.Throws<ArgumentNullException>(() => new TarWriter(archiveStream: null));
- Assert.Throws<ArgumentNullException>(() => new TarWriter(archiveStream: null, TarFormat.V7));
+ Assert.Throws<ArgumentNullException>(() => new TarWriter(archiveStream: null, TarEntryFormat.V7));
}
[Fact]
@@ -36,29 +36,29 @@ namespace System.Formats.Tar.Tests
using MemoryStream archiveStream = new MemoryStream();
using TarWriter writerDefault = new TarWriter(archiveStream, leaveOpen: true);
- Assert.Equal(TarFormat.Pax, writerDefault.Format);
+ Assert.Equal(TarEntryFormat.Pax, writerDefault.Format);
- using TarWriter writerV7 = new TarWriter(archiveStream, TarFormat.V7, leaveOpen: true);
- Assert.Equal(TarFormat.V7, writerV7.Format);
+ using TarWriter writerV7 = new TarWriter(archiveStream, TarEntryFormat.V7, leaveOpen: true);
+ Assert.Equal(TarEntryFormat.V7, writerV7.Format);
- using TarWriter writerUstar = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true);
- Assert.Equal(TarFormat.Ustar, writerUstar.Format);
+ using TarWriter writerUstar = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true);
+ Assert.Equal(TarEntryFormat.Ustar, writerUstar.Format);
- using TarWriter writerPax = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true);
- Assert.Equal(TarFormat.Pax, writerPax.Format);
+ using TarWriter writerPax = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true);
+ Assert.Equal(TarEntryFormat.Pax, writerPax.Format);
- using TarWriter writerGnu = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true);
- Assert.Equal(TarFormat.Gnu, writerGnu.Format);
+ using TarWriter writerGnu = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true);
+ Assert.Equal(TarEntryFormat.Gnu, writerGnu.Format);
using TarWriter writerNullGeaDefaultPax = new TarWriter(archiveStream, leaveOpen: true, globalExtendedAttributes: null);
- Assert.Equal(TarFormat.Pax, writerNullGeaDefaultPax.Format);
+ Assert.Equal(TarEntryFormat.Pax, writerNullGeaDefaultPax.Format);
using TarWriter writerValidGeaDefaultPax = new TarWriter(archiveStream, leaveOpen: true, globalExtendedAttributes: new Dictionary<string, string>());
- Assert.Equal(TarFormat.Pax, writerValidGeaDefaultPax.Format);
+ Assert.Equal(TarEntryFormat.Pax, writerValidGeaDefaultPax.Format);
- Assert.Throws<ArgumentOutOfRangeException>(() => new TarWriter(archiveStream, TarFormat.Unknown));
- Assert.Throws<ArgumentOutOfRangeException>(() => new TarWriter(archiveStream, (TarFormat)int.MinValue));
- Assert.Throws<ArgumentOutOfRangeException>(() => new TarWriter(archiveStream, (TarFormat)int.MaxValue));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new TarWriter(archiveStream, TarEntryFormat.Unknown));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new TarWriter(archiveStream, (TarEntryFormat)int.MinValue));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new TarWriter(archiveStream, (TarEntryFormat)int.MaxValue));
}
[Fact]
@@ -67,7 +67,7 @@ namespace System.Formats.Tar.Tests
using MemoryStream archiveStream = new MemoryStream();
using WrappedStream wrappedStream = new WrappedStream(archiveStream, canRead: true, canWrite: false, canSeek: false);
Assert.Throws<IOException>(() => new TarWriter(wrappedStream));
- Assert.Throws<IOException>(() => new TarWriter(wrappedStream, TarFormat.V7));
+ Assert.Throws<IOException>(() => new TarWriter(wrappedStream, TarEntryFormat.V7));
}
[Fact]
@@ -96,7 +96,7 @@ namespace System.Formats.Tar.Tests
using (TarReader reader = new TarReader(wrapped))
{
TarEntry entry = reader.GetNextEntry();
- Assert.Equal(TarFormat.Pax, reader.Format);
+ Assert.Equal(TarEntryFormat.Pax, reader.Format);
Assert.Equal(TarEntryType.RegularFile, entry.EntryType);
Assert.Null(reader.GetNextEntry());
}
@@ -106,7 +106,7 @@ namespace System.Formats.Tar.Tests
public void VerifyChecksumV7()
{
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, TarFormat.V7, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, TarEntryFormat.V7, leaveOpen: true))
{
V7TarEntry entry = new V7TarEntry(
// '\0' = 0
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Gnu.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Gnu.Tests.cs
index da5cc1117f1..5e7dbdc3164 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Gnu.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Gnu.Tests.cs
@@ -13,7 +13,7 @@ namespace System.Formats.Tar.Tests
public void Write_V7RegularFileEntry_As_RegularFileEntry()
{
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, archiveFormat: TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, archiveFormat: TarEntryFormat.Gnu, leaveOpen: true))
{
V7TarEntry entry = new V7TarEntry(TarEntryType.V7RegularFile, InitialEntryName);
@@ -36,7 +36,7 @@ namespace System.Formats.Tar.Tests
public void WriteRegularFile()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry regularFile = new GnuTarEntry(TarEntryType.RegularFile, InitialEntryName);
SetRegularFile(regularFile);
@@ -56,7 +56,7 @@ namespace System.Formats.Tar.Tests
public void WriteHardLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry hardLink = new GnuTarEntry(TarEntryType.HardLink, InitialEntryName);
SetHardLink(hardLink);
@@ -76,7 +76,7 @@ namespace System.Formats.Tar.Tests
public void WriteSymbolicLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry symbolicLink = new GnuTarEntry(TarEntryType.SymbolicLink, InitialEntryName);
SetSymbolicLink(symbolicLink);
@@ -96,7 +96,7 @@ namespace System.Formats.Tar.Tests
public void WriteDirectory()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry directory = new GnuTarEntry(TarEntryType.Directory, InitialEntryName);
SetDirectory(directory);
@@ -116,7 +116,7 @@ namespace System.Formats.Tar.Tests
public void WriteCharacterDevice()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry charDevice = new GnuTarEntry(TarEntryType.CharacterDevice, InitialEntryName);
SetCharacterDevice(charDevice);
@@ -136,7 +136,7 @@ namespace System.Formats.Tar.Tests
public void WriteBlockDevice()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry blockDevice = new GnuTarEntry(TarEntryType.BlockDevice, InitialEntryName);
SetBlockDevice(blockDevice);
@@ -156,7 +156,7 @@ namespace System.Formats.Tar.Tests
public void WriteFifo()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry fifo = new GnuTarEntry(TarEntryType.Fifo, InitialEntryName);
SetFifo(fifo);
@@ -183,7 +183,7 @@ namespace System.Formats.Tar.Tests
string longName = new string('a', 101);
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry entry = new GnuTarEntry(entryType, longName);
writer.WriteEntry(entry);
@@ -207,7 +207,7 @@ namespace System.Formats.Tar.Tests
string longLinkName = new string('a', 101);
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry entry = new GnuTarEntry(entryType, "file.txt");
entry.LinkName = longLinkName;
@@ -234,7 +234,7 @@ namespace System.Formats.Tar.Tests
string longLinkName = new string('a', 101);
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Gnu, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
{
GnuTarEntry entry = new GnuTarEntry(entryType, longName);
entry.LinkName = longLinkName;
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Pax.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Pax.Tests.cs
index a746c609d23..d04a40cab1c 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Pax.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Pax.Tests.cs
@@ -15,7 +15,7 @@ namespace System.Formats.Tar.Tests
public void Write_V7RegularFileEntry_As_RegularFileEntry()
{
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, archiveFormat: TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, archiveFormat: TarEntryFormat.Pax, leaveOpen: true))
{
V7TarEntry entry = new V7TarEntry(TarEntryType.V7RegularFile, InitialEntryName);
@@ -38,7 +38,7 @@ namespace System.Formats.Tar.Tests
public void WriteRegularFile()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry regularFile = new PaxTarEntry(TarEntryType.RegularFile, InitialEntryName);
SetRegularFile(regularFile);
@@ -58,7 +58,7 @@ namespace System.Formats.Tar.Tests
public void WriteHardLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry hardLink = new PaxTarEntry(TarEntryType.HardLink, InitialEntryName);
SetHardLink(hardLink);
@@ -78,7 +78,7 @@ namespace System.Formats.Tar.Tests
public void WriteSymbolicLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry symbolicLink = new PaxTarEntry(TarEntryType.SymbolicLink, InitialEntryName);
SetSymbolicLink(symbolicLink);
@@ -98,7 +98,7 @@ namespace System.Formats.Tar.Tests
public void WriteDirectory()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry directory = new PaxTarEntry(TarEntryType.Directory, InitialEntryName);
SetDirectory(directory);
@@ -118,7 +118,7 @@ namespace System.Formats.Tar.Tests
public void WriteCharacterDevice()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry charDevice = new PaxTarEntry(TarEntryType.CharacterDevice, InitialEntryName);
SetCharacterDevice(charDevice);
@@ -138,7 +138,7 @@ namespace System.Formats.Tar.Tests
public void WriteBlockDevice()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry blockDevice = new PaxTarEntry(TarEntryType.BlockDevice, InitialEntryName);
SetBlockDevice(blockDevice);
@@ -158,7 +158,7 @@ namespace System.Formats.Tar.Tests
public void WriteFifo()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry fifo = new PaxTarEntry(TarEntryType.Fifo, InitialEntryName);
SetFifo(fifo);
@@ -184,7 +184,7 @@ namespace System.Formats.Tar.Tests
extendedAttributes.Add(expectedKey, expectedValue);
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry regularFile = new PaxTarEntry(TarEntryType.RegularFile, InitialEntryName, extendedAttributes);
SetRegularFile(regularFile);
@@ -221,7 +221,7 @@ namespace System.Formats.Tar.Tests
extendedAttributes.Add("ctime", ConvertDateTimeOffsetToDouble(TestChangeTime).ToString("F6", CultureInfo.InvariantCulture));
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry regularFile = new PaxTarEntry(TarEntryType.RegularFile, InitialEntryName, extendedAttributes);
SetRegularFile(regularFile);
@@ -252,7 +252,7 @@ namespace System.Formats.Tar.Tests
string groupName = "IAmAGroupNameWhoseLengthIsWayBeyondTheThirtyTwoByteLimit";
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Pax, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Pax, leaveOpen: true))
{
PaxTarEntry regularFile = new PaxTarEntry(TarEntryType.RegularFile, InitialEntryName);
SetRegularFile(regularFile);
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Ustar.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Ustar.Tests.cs
index a130ae87edc..39613ca123a 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Ustar.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.Ustar.Tests.cs
@@ -13,7 +13,7 @@ namespace System.Formats.Tar.Tests
public void Write_V7RegularFileEntry_As_RegularFileEntry()
{
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, archiveFormat: TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, archiveFormat: TarEntryFormat.Ustar, leaveOpen: true))
{
V7TarEntry entry = new V7TarEntry(TarEntryType.V7RegularFile, InitialEntryName);
@@ -36,7 +36,7 @@ namespace System.Formats.Tar.Tests
public void WriteRegularFile()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry regularFile = new UstarTarEntry(TarEntryType.RegularFile, InitialEntryName);
SetRegularFile(regularFile);
@@ -56,7 +56,7 @@ namespace System.Formats.Tar.Tests
public void WriteHardLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry hardLink = new UstarTarEntry(TarEntryType.HardLink, InitialEntryName);
SetHardLink(hardLink);
@@ -76,7 +76,7 @@ namespace System.Formats.Tar.Tests
public void WriteSymbolicLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry symbolicLink = new UstarTarEntry(TarEntryType.SymbolicLink, InitialEntryName);
SetSymbolicLink(symbolicLink);
@@ -96,7 +96,7 @@ namespace System.Formats.Tar.Tests
public void WriteDirectory()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry directory = new UstarTarEntry(TarEntryType.Directory, InitialEntryName);
SetDirectory(directory);
@@ -116,7 +116,7 @@ namespace System.Formats.Tar.Tests
public void WriteCharacterDevice()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry charDevice = new UstarTarEntry(TarEntryType.CharacterDevice, InitialEntryName);
SetCharacterDevice(charDevice);
@@ -136,7 +136,7 @@ namespace System.Formats.Tar.Tests
public void WriteBlockDevice()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry blockDevice = new UstarTarEntry(TarEntryType.BlockDevice, InitialEntryName);
SetBlockDevice(blockDevice);
@@ -156,7 +156,7 @@ namespace System.Formats.Tar.Tests
public void WriteFifo()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true))
{
UstarTarEntry fifo = new UstarTarEntry(TarEntryType.Fifo, InitialEntryName);
SetFifo(fifo);
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.V7.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.V7.Tests.cs
index 7b74d769fa1..1b0a325d089 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.V7.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Entry.V7.Tests.cs
@@ -14,7 +14,7 @@ namespace System.Formats.Tar.Tests
{
// Verify that entry types that can be manually constructed in other types, cannot be inserted in a v7 writer
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, archiveFormat: TarFormat.V7, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, archiveFormat: TarEntryFormat.V7, leaveOpen: true))
{
// Entry types supported in ustar but not in v7
Assert.Throws<InvalidOperationException>(() => writer.WriteEntry(new UstarTarEntry(TarEntryType.BlockDevice, InitialEntryName)));
@@ -36,19 +36,19 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.Ustar)]
- [InlineData(TarFormat.Pax)]
- [InlineData(TarFormat.Gnu)]
- public void Write_RegularFileEntry_As_V7RegularFileEntry(TarFormat entryFormat)
+ [InlineData(TarEntryFormat.Ustar)]
+ [InlineData(TarEntryFormat.Pax)]
+ [InlineData(TarEntryFormat.Gnu)]
+ public void Write_RegularFileEntry_As_V7RegularFileEntry(TarEntryFormat entryFormat)
{
using MemoryStream archive = new MemoryStream();
- using (TarWriter writer = new TarWriter(archive, archiveFormat: TarFormat.V7, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archive, archiveFormat: TarEntryFormat.V7, leaveOpen: true))
{
TarEntry entry = entryFormat switch
{
- TarFormat.Ustar => new UstarTarEntry(TarEntryType.RegularFile, InitialEntryName),
- TarFormat.Pax => new PaxTarEntry(TarEntryType.RegularFile, InitialEntryName),
- TarFormat.Gnu => new GnuTarEntry(TarEntryType.RegularFile, InitialEntryName),
+ TarEntryFormat.Ustar => new UstarTarEntry(TarEntryType.RegularFile, InitialEntryName),
+ TarEntryFormat.Pax => new PaxTarEntry(TarEntryType.RegularFile, InitialEntryName),
+ TarEntryFormat.Gnu => new GnuTarEntry(TarEntryType.RegularFile, InitialEntryName),
_ => throw new FormatException()
};
@@ -72,7 +72,7 @@ namespace System.Formats.Tar.Tests
public void WriteRegularFile()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.V7, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.V7, leaveOpen: true))
{
V7TarEntry oldRegularFile = new V7TarEntry(TarEntryType.V7RegularFile, InitialEntryName);
SetRegularFile(oldRegularFile);
@@ -92,7 +92,7 @@ namespace System.Formats.Tar.Tests
public void WriteHardLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.V7, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.V7, leaveOpen: true))
{
V7TarEntry hardLink = new V7TarEntry(TarEntryType.HardLink, InitialEntryName);
SetHardLink(hardLink);
@@ -112,7 +112,7 @@ namespace System.Formats.Tar.Tests
public void WriteSymbolicLink()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.V7, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.V7, leaveOpen: true))
{
V7TarEntry symbolicLink = new V7TarEntry(TarEntryType.SymbolicLink, InitialEntryName);
SetSymbolicLink(symbolicLink);
@@ -132,7 +132,7 @@ namespace System.Formats.Tar.Tests
public void WriteDirectory()
{
using MemoryStream archiveStream = new MemoryStream();
- using (TarWriter writer = new TarWriter(archiveStream, TarFormat.V7, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.V7, leaveOpen: true))
{
V7TarEntry directory = new V7TarEntry(TarEntryType.Directory, InitialEntryName);
SetDirectory(directory);
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs
index 95239178941..095aa19c219 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.Unix.cs
@@ -12,14 +12,14 @@ namespace System.Formats.Tar.Tests
private static bool IsRemoteExecutorSupportedAndOnUnixAndSuperUser => RemoteExecutor.IsSupported && PlatformDetection.IsUnixAndSuperUser;
[ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))]
- [InlineData(TarFormat.Ustar)]
- [InlineData(TarFormat.Pax)]
- [InlineData(TarFormat.Gnu)]
- public void Add_Fifo(TarFormat format)
+ [InlineData(TarEntryFormat.Ustar)]
+ [InlineData(TarEntryFormat.Pax)]
+ [InlineData(TarEntryFormat.Gnu)]
+ public void Add_Fifo(TarEntryFormat format)
{
RemoteExecutor.Invoke((string strFormat) =>
{
- TarFormat expectedFormat = Enum.Parse<TarFormat>(strFormat);
+ TarEntryFormat expectedFormat = Enum.Parse<TarEntryFormat>(strFormat);
using TempDirectory root = new TempDirectory();
string fifoName = "fifofile";
@@ -36,7 +36,7 @@ namespace System.Formats.Tar.Tests
archive.Seek(0, SeekOrigin.Begin);
using (TarReader reader = new TarReader(archive))
{
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
PosixTarEntry entry = reader.GetNextEntry() as PosixTarEntry;
Assert.Equal(expectedFormat, reader.Format);
@@ -55,14 +55,14 @@ namespace System.Formats.Tar.Tests
}
[ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))]
- [InlineData(TarFormat.Ustar)]
- [InlineData(TarFormat.Pax)]
- [InlineData(TarFormat.Gnu)]
- public void Add_BlockDevice(TarFormat format)
+ [InlineData(TarEntryFormat.Ustar)]
+ [InlineData(TarEntryFormat.Pax)]
+ [InlineData(TarEntryFormat.Gnu)]
+ public void Add_BlockDevice(TarEntryFormat format)
{
RemoteExecutor.Invoke((string strFormat) =>
{
- TarFormat expectedFormat = Enum.Parse<TarFormat>(strFormat);
+ TarEntryFormat expectedFormat = Enum.Parse<TarEntryFormat>(strFormat);
using TempDirectory root = new TempDirectory();
string blockDevicePath = Path.Join(root.Path, AssetBlockDeviceFileName);
@@ -79,7 +79,7 @@ namespace System.Formats.Tar.Tests
archive.Seek(0, SeekOrigin.Begin);
using (TarReader reader = new TarReader(archive))
{
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
PosixTarEntry entry = reader.GetNextEntry() as PosixTarEntry;
Assert.Equal(expectedFormat, reader.Format);
@@ -101,14 +101,14 @@ namespace System.Formats.Tar.Tests
}
[ConditionalTheory(nameof(IsRemoteExecutorSupportedAndOnUnixAndSuperUser))]
- [InlineData(TarFormat.Ustar)]
- [InlineData(TarFormat.Pax)]
- [InlineData(TarFormat.Gnu)]
- public void Add_CharacterDevice(TarFormat format)
+ [InlineData(TarEntryFormat.Ustar)]
+ [InlineData(TarEntryFormat.Pax)]
+ [InlineData(TarEntryFormat.Gnu)]
+ public void Add_CharacterDevice(TarEntryFormat format)
{
RemoteExecutor.Invoke((string strFormat) =>
{
- TarFormat expectedFormat = Enum.Parse<TarFormat>(strFormat);
+ TarEntryFormat expectedFormat = Enum.Parse<TarEntryFormat>(strFormat);
using TempDirectory root = new TempDirectory();
string characterDevicePath = Path.Join(root.Path, AssetCharacterDeviceFileName);
@@ -124,7 +124,7 @@ namespace System.Formats.Tar.Tests
archive.Seek(0, SeekOrigin.Begin);
using (TarReader reader = new TarReader(archive))
{
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
PosixTarEntry entry = reader.GetNextEntry() as PosixTarEntry;
Assert.Equal(expectedFormat, reader.Format);
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.cs
index 52d34232c4d..31781e75b9f 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.File.Tests.cs
@@ -67,11 +67,11 @@ namespace System.Formats.Tar.Tests
[ActiveIssue("https://github.com/dotnet/runtime/issues/69474", TestPlatforms.Linux)]
[Theory]
- [InlineData(TarFormat.V7)]
- [InlineData(TarFormat.Ustar)]
- [InlineData(TarFormat.Pax)]
- [InlineData(TarFormat.Gnu)]
- public void Add_File(TarFormat format)
+ [InlineData(TarEntryFormat.V7)]
+ [InlineData(TarEntryFormat.Ustar)]
+ [InlineData(TarEntryFormat.Pax)]
+ [InlineData(TarEntryFormat.Gnu)]
+ public void Add_File(TarEntryFormat format)
{
using TempDirectory root = new TempDirectory();
string fileName = "file.txt";
@@ -92,12 +92,12 @@ namespace System.Formats.Tar.Tests
archive.Seek(0, SeekOrigin.Begin);
using (TarReader reader = new TarReader(archive))
{
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry entry = reader.GetNextEntry();
Assert.NotNull(entry);
Assert.Equal(format, reader.Format);
Assert.Equal(fileName, entry.Name);
- TarEntryType expectedEntryType = format is TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
+ TarEntryType expectedEntryType = format is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
Assert.Equal(expectedEntryType, entry.EntryType);
Assert.True(entry.Length > 0);
Assert.NotNull(entry.DataStream);
@@ -115,15 +115,15 @@ namespace System.Formats.Tar.Tests
}
[Theory]
- [InlineData(TarFormat.V7, false)]
- [InlineData(TarFormat.V7, true)]
- [InlineData(TarFormat.Ustar, false)]
- [InlineData(TarFormat.Ustar, true)]
- [InlineData(TarFormat.Pax, false)]
- [InlineData(TarFormat.Pax, true)]
- [InlineData(TarFormat.Gnu, false)]
- [InlineData(TarFormat.Gnu, true)]
- public void Add_Directory(TarFormat format, bool withContents)
+ [InlineData(TarEntryFormat.V7, false)]
+ [InlineData(TarEntryFormat.V7, true)]
+ [InlineData(TarEntryFormat.Ustar, false)]
+ [InlineData(TarEntryFormat.Ustar, true)]
+ [InlineData(TarEntryFormat.Pax, false)]
+ [InlineData(TarEntryFormat.Pax, true)]
+ [InlineData(TarEntryFormat.Gnu, false)]
+ [InlineData(TarEntryFormat.Gnu, true)]
+ public void Add_Directory(TarEntryFormat format, bool withContents)
{
using TempDirectory root = new TempDirectory();
string dirName = "dir";
@@ -146,7 +146,7 @@ namespace System.Formats.Tar.Tests
archive.Seek(0, SeekOrigin.Begin);
using (TarReader reader = new TarReader(archive))
{
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry entry = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -162,15 +162,15 @@ namespace System.Formats.Tar.Tests
}
[ConditionalTheory(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))]
- [InlineData(TarFormat.V7, false)]
- [InlineData(TarFormat.V7, true)]
- [InlineData(TarFormat.Ustar, false)]
- [InlineData(TarFormat.Ustar, true)]
- [InlineData(TarFormat.Pax, false)]
- [InlineData(TarFormat.Pax, true)]
- [InlineData(TarFormat.Gnu, false)]
- [InlineData(TarFormat.Gnu, true)]
- public void Add_SymbolicLink(TarFormat format, bool createTarget)
+ [InlineData(TarEntryFormat.V7, false)]
+ [InlineData(TarEntryFormat.V7, true)]
+ [InlineData(TarEntryFormat.Ustar, false)]
+ [InlineData(TarEntryFormat.Ustar, true)]
+ [InlineData(TarEntryFormat.Pax, false)]
+ [InlineData(TarEntryFormat.Pax, true)]
+ [InlineData(TarEntryFormat.Gnu, false)]
+ [InlineData(TarEntryFormat.Gnu, true)]
+ public void Add_SymbolicLink(TarEntryFormat format, bool createTarget)
{
using TempDirectory root = new TempDirectory();
string targetName = "file.txt";
@@ -195,7 +195,7 @@ namespace System.Formats.Tar.Tests
archive.Seek(0, SeekOrigin.Begin);
using (TarReader reader = new TarReader(archive))
{
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
TarEntry entry = reader.GetNextEntry();
Assert.Equal(format, reader.Format);
@@ -233,12 +233,12 @@ namespace System.Formats.Tar.Tests
using (TarReader reader = new TarReader(archive))
{
// Unknown until reading first entry
- Assert.Equal(TarFormat.Unknown, reader.Format);
+ Assert.Equal(TarEntryFormat.Unknown, reader.Format);
Assert.Null(reader.GlobalExtendedAttributes);
Assert.Null(reader.GetNextEntry());
- Assert.Equal(TarFormat.Pax, reader.Format);
+ Assert.Equal(TarEntryFormat.Pax, reader.Format);
Assert.NotNull(reader.GlobalExtendedAttributes);
int expectedCount = withAttributes ? 1 : 0;
diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs
index c68690c0a7f..2722095996a 100644
--- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs
@@ -35,7 +35,7 @@ namespace System.Formats.Tar.Tests
Assert.NotNull(entry.DataStream);
entry.DataStream.ReadByte(); // Advance one byte, now the expected string would be "ello file"
- using (TarWriter writer = new TarWriter(destination, TarFormat.Ustar, leaveOpen: true))
+ using (TarWriter writer = new TarWriter(destination, TarEntryFormat.Ustar, leaveOpen: true))
{
writer.WriteEntry(entry);
}
diff --git a/src/libraries/System.IO.Compression.ZipFile/tests/ZipFile.Unix.cs b/src/libraries/System.IO.Compression.ZipFile/tests/ZipFile.Unix.cs
index e13fec3d935..91b6b4baf5e 100644
--- a/src/libraries/System.IO.Compression.ZipFile/tests/ZipFile.Unix.cs
+++ b/src/libraries/System.IO.Compression.ZipFile/tests/ZipFile.Unix.cs
@@ -61,7 +61,6 @@ namespace System.IO.Compression.Tests
{
// '7600' tests that S_ISUID, S_ISGID, and S_ISVTX bits don't get extracted to file permissions
string[] testPermissions = new[] { "777", "755", "644", "754", "7600" };
- byte[] contents = Encoding.UTF8.GetBytes("contents");
string archivePath = GetTestFilePath();
using (FileStream fileStream = new FileStream(archivePath, FileMode.CreateNew))
@@ -72,7 +71,7 @@ namespace System.IO.Compression.Tests
ZipArchiveEntry entry = archive.CreateEntry(permission + ".txt");
entry.ExternalAttributes = Convert.ToInt32(permission, 8) << 16;
using Stream stream = entry.Open();
- stream.Write(contents);
+ stream.Write("contents"u8);
stream.Flush();
}
}
diff --git a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs
index 637d04500d7..93adafa337f 100644
--- a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs
+++ b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_UpdateTests.cs
@@ -169,14 +169,14 @@ namespace System.IO.Compression.Tests
{
s.Seek(0, SeekOrigin.End);
- byte[] data = Encoding.ASCII.GetBytes("\r\n\r\nThe answer my friend, is blowin' in the wind.");
+ byte[] data = "\r\n\r\nThe answer my friend, is blowin' in the wind."u8.ToArray();
if (writeWithSpans)
{
- s.Write(data, 0, data.Length);
+ s.Write(new ReadOnlySpan<byte>(data));
}
else
{
- s.Write(new ReadOnlySpan<byte>(data));
+ s.Write(data, 0, data.Length);
}
}
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
index 69c2c7208f4..bcb3de4825c 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
@@ -97,11 +97,11 @@ namespace System.IO.Tests
// Operation succeeds when being run by the Unix superuser
if (PlatformDetection.IsSuperUser)
{
- File.WriteAllBytes(path, Encoding.UTF8.GetBytes("text"));
- Assert.Equal(Encoding.UTF8.GetBytes("text"), File.ReadAllBytes(path));
+ File.WriteAllBytes(path, "text"u8.ToArray());
+ Assert.Equal("text"u8.ToArray(), File.ReadAllBytes(path));
}
else
- Assert.Throws<UnauthorizedAccessException>(() => File.WriteAllBytes(path, Encoding.UTF8.GetBytes("text")));
+ Assert.Throws<UnauthorizedAccessException>(() => File.WriteAllBytes(path, "text"u8.ToArray()));
}
finally
{
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
index 3ab0df37004..2c6df24b702 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
@@ -108,11 +108,11 @@ namespace System.IO.Tests
// Operation succeeds when being run by the Unix superuser
if (PlatformDetection.IsSuperUser)
{
- await File.WriteAllBytesAsync(path, Encoding.UTF8.GetBytes("text"));
- Assert.Equal(Encoding.UTF8.GetBytes("text"), await File.ReadAllBytesAsync(path));
+ await File.WriteAllBytesAsync(path, "text"u8.ToArray());
+ Assert.Equal("text"u8.ToArray(), await File.ReadAllBytesAsync(path));
}
else
- await Assert.ThrowsAsync<UnauthorizedAccessException>(async () => await File.WriteAllBytesAsync(path, Encoding.UTF8.GetBytes("text")));
+ await Assert.ThrowsAsync<UnauthorizedAccessException>(async () => await File.WriteAllBytesAsync(path, "text"u8.ToArray()));
}
finally
{
diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs
index 04d04aadaa5..86a4901b344 100644
--- a/src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs
+++ b/src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs
@@ -21,7 +21,7 @@ namespace System.IO.Tests
{
FileStreamOptions options = new() { Options = fileOptions, Access = FileAccess.Write, Share = FileShare.Write };
using FileStream fs = new(devicePath, options);
- fs.Write(Encoding.UTF8.GetBytes("foo"));
+ fs.Write("foo"u8);
}
[Theory]
@@ -30,21 +30,21 @@ namespace System.IO.Tests
{
FileStreamOptions options = new() { Options = fileOptions, Access = FileAccess.Write, Share = FileShare.Write };
using FileStream fs = new(devicePath, options);
- await fs.WriteAsync(Encoding.UTF8.GetBytes("foo"));
+ await fs.WriteAsync("foo"u8.ToArray());
}
[Theory]
[MemberData(nameof(DevicePath_TestData))]
public void CharacterDevice_WriteAllBytes(string devicePath)
{
- File.WriteAllBytes(devicePath, Encoding.UTF8.GetBytes("foo"));
+ File.WriteAllBytes(devicePath, "foo"u8.ToArray());
}
[Theory]
[MemberData(nameof(DevicePath_TestData))]
public async Task CharacterDevice_WriteAllBytesAsync(string devicePath)
{
- await File.WriteAllBytesAsync(devicePath, Encoding.UTF8.GetBytes("foo"));
+ await File.WriteAllBytesAsync(devicePath, "foo"u8.ToArray());
}
[Theory]
diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs
index cd3b18da034..44cafb53a89 100644
--- a/src/libraries/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs
+++ b/src/libraries/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs
@@ -218,12 +218,12 @@ namespace System.IO.Tests
Assert.False(fs.CanRead);
Assert.True(fs.CanWrite);
- fs.Write(Encoding.ASCII.GetBytes("abcde"));
+ fs.Write("abcde"u8);
Assert.Equal(5, fs.Length);
Assert.Equal(5, fs.Position);
Assert.Equal(1, fs.Seek(1, SeekOrigin.Begin));
- fs.Write(Encoding.ASCII.GetBytes("xyz"));
+ fs.Write("xyz"u8);
Assert.Equal(4, fs.Position);
Assert.Equal(5, fs.Length);
}
@@ -257,12 +257,12 @@ namespace System.IO.Tests
Assert.Throws<IOException>(() => fs.Seek(0, SeekOrigin.Begin));
Assert.Throws<NotSupportedException>(() => fs.ReadByte());
- fs.Write(Encoding.ASCII.GetBytes("abcde"));
+ fs.Write("abcde"u8);
Assert.Equal(position + 5, fs.Position);
Assert.Equal(position, fs.Seek(position, SeekOrigin.Begin));
Assert.Equal(position + 1, fs.Seek(1, SeekOrigin.Current));
- fs.Write(Encoding.ASCII.GetBytes("xyz"));
+ fs.Write("xyz"u8);
}
Assert.Equal(initialContents + "axyze", File.ReadAllText(fileName));
diff --git a/src/libraries/System.IO.Hashing/tests/Crc32Tests.cs b/src/libraries/System.IO.Hashing/tests/Crc32Tests.cs
index 6d2993f1509..0761450fb9a 100644
--- a/src/libraries/System.IO.Hashing/tests/Crc32Tests.cs
+++ b/src/libraries/System.IO.Hashing/tests/Crc32Tests.cs
@@ -51,7 +51,7 @@ namespace System.IO.Hashing.Tests
"FFFFFFFF"),
new TestCase(
"Self-test 123456789",
- Encoding.ASCII.GetBytes("123456789"),
+ "123456789"u8.ToArray(),
"2639F4CB"),
new TestCase(
"Self-test residue",
@@ -63,7 +63,7 @@ namespace System.IO.Hashing.Tests
"FFFFFFFF"),
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"39A34F41"),
};
diff --git a/src/libraries/System.IO.Hashing/tests/Crc64Tests.cs b/src/libraries/System.IO.Hashing/tests/Crc64Tests.cs
index d647e4b9587..52971f0c977 100644
--- a/src/libraries/System.IO.Hashing/tests/Crc64Tests.cs
+++ b/src/libraries/System.IO.Hashing/tests/Crc64Tests.cs
@@ -59,7 +59,7 @@ namespace System.IO.Hashing.Tests
"0000000000000000"),
new TestCase(
"Self-test 123456789",
- Encoding.ASCII.GetBytes("123456789"),
+ "123456789"u8.ToArray(),
"6C40DF5F0B497347"),
new TestCase(
"Self-test residue",
@@ -67,7 +67,7 @@ namespace System.IO.Hashing.Tests
"0000000000000000"),
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"41E05242FFA9883B"),
};
diff --git a/src/libraries/System.IO.Hashing/tests/XxHash32Tests.007.cs b/src/libraries/System.IO.Hashing/tests/XxHash32Tests.007.cs
index 9ec9262dd1c..db17893ccca 100644
--- a/src/libraries/System.IO.Hashing/tests/XxHash32Tests.007.cs
+++ b/src/libraries/System.IO.Hashing/tests/XxHash32Tests.007.cs
@@ -45,19 +45,19 @@ namespace System.IO.Hashing.Tests
// Same inputs as the main XxHash32 tests, but with the seed applied.
new TestCase(
"Nobody inspects the spammish repetition",
- Encoding.ASCII.GetBytes("Nobody inspects the spammish repetition"),
+ "Nobody inspects the spammish repetition"u8.ToArray(),
"21C69E3A"),
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"558D024f"),
new TestCase(
"The quick brown fox jumps over the lazy dog.",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog."),
+ "The quick brown fox jumps over the lazy dog."u8.ToArray(),
"E7D2C0A7"),
new TestCase(
"abc",
- Encoding.ASCII.GetBytes("abc"),
+ "abc"u8.ToArray(),
"D46070BB"),
new TestCase(
"123456",
diff --git a/src/libraries/System.IO.Hashing/tests/XxHash32Tests.cs b/src/libraries/System.IO.Hashing/tests/XxHash32Tests.cs
index abd77d8c22f..9c6bad45f8d 100644
--- a/src/libraries/System.IO.Hashing/tests/XxHash32Tests.cs
+++ b/src/libraries/System.IO.Hashing/tests/XxHash32Tests.cs
@@ -43,17 +43,17 @@ namespace System.IO.Hashing.Tests
//https://asecuritysite.com/encryption/xxHash, Example 1
new TestCase(
"Nobody inspects the spammish repetition",
- Encoding.ASCII.GetBytes("Nobody inspects the spammish repetition"),
+ "Nobody inspects the spammish repetition"u8.ToArray(),
"E2293B2F"),
//https://asecuritysite.com/encryption/xxHash, Example 2
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"E85EA4DE"),
//https://asecuritysite.com/encryption/xxHash, Example 3
new TestCase(
"The quick brown fox jumps over the lazy dog.",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog."),
+ "The quick brown fox jumps over the lazy dog."u8.ToArray(),
"68D039C8"),
// Manual exploration to force boundary conditions in code coverage.
@@ -62,7 +62,7 @@ namespace System.IO.Hashing.Tests
// The "in three pieces" test causes this to build up in the accumulator every time.
new TestCase(
"abc",
- Encoding.ASCII.GetBytes("abc"),
+ "abc"u8.ToArray(),
"32D153FF"),
// Accumulates every time.
new TestCase(
diff --git a/src/libraries/System.IO.Hashing/tests/XxHash32Tests.f00d.cs b/src/libraries/System.IO.Hashing/tests/XxHash32Tests.f00d.cs
index 4a116bc5035..edf94fb5cc4 100644
--- a/src/libraries/System.IO.Hashing/tests/XxHash32Tests.f00d.cs
+++ b/src/libraries/System.IO.Hashing/tests/XxHash32Tests.f00d.cs
@@ -45,19 +45,19 @@ namespace System.IO.Hashing.Tests
// Same inputs as the main XxHash32 tests, but with the seed applied.
new TestCase(
"Nobody inspects the spammish repetition",
- Encoding.ASCII.GetBytes("Nobody inspects the spammish repetition"),
+ "Nobody inspects the spammish repetition"u8.ToArray(),
"E8FF660B"),
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"C2B00BA1"),
new TestCase(
"The quick brown fox jumps over the lazy dog.",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog."),
+ "The quick brown fox jumps over the lazy dog."u8.ToArray(),
"11AC3BD7"),
new TestCase(
"abc",
- Encoding.ASCII.GetBytes("abc"),
+ "abc"u8.ToArray(),
"BC85BB95"),
new TestCase(
"123456",
diff --git a/src/libraries/System.IO.Hashing/tests/XxHash64Tests.007.cs b/src/libraries/System.IO.Hashing/tests/XxHash64Tests.007.cs
index 836b29230f3..6c902b8352d 100644
--- a/src/libraries/System.IO.Hashing/tests/XxHash64Tests.007.cs
+++ b/src/libraries/System.IO.Hashing/tests/XxHash64Tests.007.cs
@@ -47,19 +47,19 @@ namespace System.IO.Hashing.Tests
// Same inputs as the main XxHash64 tests, but with the seed applied.
new TestCase(
"Nobody inspects the spammish repetition",
- Encoding.ASCII.GetBytes("Nobody inspects the spammish repetition"),
+ "Nobody inspects the spammish repetition"u8.ToArray(),
"C86A41E2F34280A0"),
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"BB05857F11B054EB"),
new TestCase(
"The quick brown fox jumps over the lazy dog.",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog."),
+ "The quick brown fox jumps over the lazy dog."u8.ToArray(),
"618682461CB28F83"),
new TestCase(
"abc",
- Encoding.ASCII.GetBytes("abc"),
+ "abc"u8.ToArray(),
"6BF4B26E3CA10C20"),
new TestCase(
"123456",
diff --git a/src/libraries/System.IO.Hashing/tests/XxHash64Tests.cs b/src/libraries/System.IO.Hashing/tests/XxHash64Tests.cs
index 213e6f91c25..10485ba584e 100644
--- a/src/libraries/System.IO.Hashing/tests/XxHash64Tests.cs
+++ b/src/libraries/System.IO.Hashing/tests/XxHash64Tests.cs
@@ -45,17 +45,17 @@ namespace System.IO.Hashing.Tests
//https://asecuritysite.com/encryption/xxHash, Example 1
new TestCase(
"Nobody inspects the spammish repetition",
- Encoding.ASCII.GetBytes("Nobody inspects the spammish repetition"),
+ "Nobody inspects the spammish repetition"u8.ToArray(),
"FBCEA83C8A378BF1"),
//https://asecuritysite.com/encryption/xxHash, Example 2
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"0B242D361FDA71BC"),
//https://asecuritysite.com/encryption/xxHash, Example 3
new TestCase(
"The quick brown fox jumps over the lazy dog.",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog."),
+ "The quick brown fox jumps over the lazy dog."u8.ToArray(),
"44AD33705751AD73"),
// Manual exploration to force boundary conditions in code coverage.
@@ -64,7 +64,7 @@ namespace System.IO.Hashing.Tests
// The "in three pieces" test causes this to build up in the accumulator every time.
new TestCase(
"abc",
- Encoding.ASCII.GetBytes("abc"),
+ "abc"u8.ToArray(),
"44BC2CF5AD770999"),
// Accumulates every time.
new TestCase(
diff --git a/src/libraries/System.IO.Hashing/tests/XxHash64Tests.f00d.cs b/src/libraries/System.IO.Hashing/tests/XxHash64Tests.f00d.cs
index 75fc4f514ac..283f1922d1d 100644
--- a/src/libraries/System.IO.Hashing/tests/XxHash64Tests.f00d.cs
+++ b/src/libraries/System.IO.Hashing/tests/XxHash64Tests.f00d.cs
@@ -47,19 +47,19 @@ namespace System.IO.Hashing.Tests
// Same inputs as the main XxHash64 tests, but with the seed applied.
new TestCase(
"Nobody inspects the spammish repetition",
- Encoding.ASCII.GetBytes("Nobody inspects the spammish repetition"),
+ "Nobody inspects the spammish repetition"u8.ToArray(),
"76E6275980CF4E30"),
new TestCase(
"The quick brown fox jumps over the lazy dog",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"),
+ "The quick brown fox jumps over the lazy dog"u8.ToArray(),
"5CC25b2B8248DF76"),
new TestCase(
"The quick brown fox jumps over the lazy dog.",
- Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog."),
+ "The quick brown fox jumps over the lazy dog."u8.ToArray(),
"10E8D9E4DA841407"),
new TestCase(
"abc",
- Encoding.ASCII.GetBytes("abc"),
+ "abc"u8.ToArray(),
"AE9DA0E407940A85"),
new TestCase(
"123456",
diff --git a/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs b/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs
index adf547a3c45..f6e87e2034f 100644
--- a/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs
@@ -43,9 +43,9 @@ namespace System.IO.Pipelines.Tests
{
var messages = new List<byte[]>()
{
- Encoding.UTF8.GetBytes("Hello World1"),
- Encoding.UTF8.GetBytes("Hello World2"),
- Encoding.UTF8.GetBytes("Hello World3"),
+ "Hello World1"u8.ToArray(),
+ "Hello World2"u8.ToArray(),
+ "Hello World3"u8.ToArray(),
};
var stream = new WriteCheckMemoryStream();
@@ -67,9 +67,9 @@ namespace System.IO.Pipelines.Tests
{
var messages = new List<byte[]>()
{
- Encoding.UTF8.GetBytes("Hello World1"),
- Encoding.UTF8.GetBytes("Hello World2"),
- Encoding.UTF8.GetBytes("Hello World3"),
+ "Hello World1"u8.ToArray(),
+ "Hello World2"u8.ToArray(),
+ "Hello World3"u8.ToArray(),
};
var targetPipe = new Pipe(s_testOptions);
@@ -199,7 +199,7 @@ namespace System.IO.Pipelines.Tests
// This should make the write call pause
var targetPipe = new Pipe(new PipeOptions(pauseWriterThreshold: 1, resumeWriterThreshold: 1));
var cts = new CancellationTokenSource();
- await Pipe.Writer.WriteAsync(Encoding.ASCII.GetBytes("Gello World"));
+ await Pipe.Writer.WriteAsync("Gello World"u8.ToArray());
Task task = PipeReader.CopyToAsync(targetPipe.Writer, cts.Token);
cts.Cancel();
@@ -212,7 +212,7 @@ namespace System.IO.Pipelines.Tests
{
// This should make the write call pause
var targetPipe = new Pipe(new PipeOptions(pauseWriterThreshold: 1, resumeWriterThreshold: 1));
- await Pipe.Writer.WriteAsync(Encoding.ASCII.GetBytes("Gello World"));
+ await Pipe.Writer.WriteAsync("Gello World"u8.ToArray());
Task task = PipeReader.CopyToAsync(targetPipe.Writer);
targetPipe.Writer.CancelPendingFlush();
@@ -290,7 +290,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CopyToAsyncStreamCopiesRemainderAfterReadingSome()
{
- var buffer = Encoding.UTF8.GetBytes("Hello World");
+ byte[] buffer = "Hello World"u8.ToArray();
await Pipe.Writer.WriteAsync(buffer);
Pipe.Writer.Complete();
@@ -308,7 +308,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CopyToAsyncPipeWriterCopiesRemainderAfterReadingSome()
{
- var buffer = Encoding.UTF8.GetBytes("Hello World");
+ byte[] buffer = "Hello World"u8.ToArray();
await Pipe.Writer.WriteAsync(buffer);
Pipe.Writer.Complete();
diff --git a/src/libraries/System.IO.Pipelines/tests/PipeReaderReadAtLeastAsyncTests.cs b/src/libraries/System.IO.Pipelines/tests/PipeReaderReadAtLeastAsyncTests.cs
index 64762de5ec8..9a76f91cb76 100644
--- a/src/libraries/System.IO.Pipelines/tests/PipeReaderReadAtLeastAsyncTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/PipeReaderReadAtLeastAsyncTests.cs
@@ -31,7 +31,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CanWriteAndReadAtLeast()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
await Pipe.Writer.WriteAsync(bytes);
ReadResult result = await PipeReader.ReadAtLeastAsync(11);
@@ -46,7 +46,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task ReadAtLeastShouldNotCompleteIfWriterWroteLessThanMinimum()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
await Pipe.Writer.WriteAsync(bytes.AsMemory(0, 5));
ValueTask<ReadResult> task = PipeReader.ReadAtLeastAsync(11);
@@ -68,7 +68,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CanAlternateReadAtLeastAndRead()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
await Pipe.Writer.WriteAsync(bytes.AsMemory(0, 5));
ReadResult result = await PipeReader.ReadAtLeastAsync(3);
@@ -113,7 +113,7 @@ namespace System.IO.Pipelines.Tests
public async Task CanReadAtLeast(int bufferSize, bool bufferedRead)
{
SetPipeReaderOptions(bufferSize: bufferSize);
- await Pipe.Writer.WriteAsync(Encoding.ASCII.GetBytes("Hello Pipelines World"));
+ await Pipe.Writer.WriteAsync("Hello Pipelines World"u8.ToArray());
if (bufferedRead)
{
@@ -148,7 +148,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task WriteAndCancellingPendingReadBeforeReadAtLeastAsync()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
PipeWriter output = Pipe.Writer;
output.Write(bytes);
await output.FlushAsync();
diff --git a/src/libraries/System.IO.Pipelines/tests/PipeReaderStreamTests.nonnetstandard.cs b/src/libraries/System.IO.Pipelines/tests/PipeReaderStreamTests.nonnetstandard.cs
index 0e8398188c0..803c101da24 100644
--- a/src/libraries/System.IO.Pipelines/tests/PipeReaderStreamTests.nonnetstandard.cs
+++ b/src/libraries/System.IO.Pipelines/tests/PipeReaderStreamTests.nonnetstandard.cs
@@ -55,7 +55,7 @@ namespace System.IO.Pipelines.Tests
[MemberData(nameof(ReadCalls))]
public async Task ReadingFromPipeReaderStreamReadsFromUnderlyingPipeReader(ReadAsyncDelegate readAsync)
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
await pipe.Writer.WriteAsync(helloBytes);
pipe.Writer.Complete();
@@ -73,7 +73,7 @@ namespace System.IO.Pipelines.Tests
[MemberData(nameof(ReadCalls))]
public async Task AsStreamReturnsPipeReaderStream(ReadAsyncDelegate readAsync)
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
await pipe.Writer.WriteAsync(helloBytes);
pipe.Writer.Complete();
@@ -90,7 +90,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task ReadingWithSmallerBufferWorks()
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
await pipe.Writer.WriteAsync(helloBytes);
pipe.Writer.Complete();
diff --git a/src/libraries/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs b/src/libraries/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
index 1a325e466a7..c5cd74d8469 100644
--- a/src/libraries/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
+++ b/src/libraries/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
@@ -34,7 +34,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CanReadAndWrite()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
await _pipe.Writer.WriteAsync(bytes);
ReadResult result = await _pipe.Reader.ReadAsync();
@@ -170,7 +170,7 @@ namespace System.IO.Pipelines.Tests
var blockSize = _pipe.Writer.GetMemory().Length;
byte[] paddingBytes = Enumerable.Repeat((byte)'a', blockSize - 5).ToArray();
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
writeBuffer.Write(paddingBytes);
writeBuffer.Write(bytes);
@@ -338,7 +338,7 @@ namespace System.IO.Pipelines.Tests
await buffer.FlushAsync();
// Write Hello to another pipeline and get the buffer
- byte[] bytes = Encoding.ASCII.GetBytes("Hello");
+ byte[] bytes = "Hello"u8.ToArray();
var c2 = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline));
await c2.Writer.WriteAsync(bytes);
@@ -516,7 +516,7 @@ namespace System.IO.Pipelines.Tests
public async Task SyncReadThenAsyncRead()
{
PipeWriter buffer = _pipe.Writer;
- buffer.Write(Encoding.ASCII.GetBytes("Hello World"));
+ buffer.Write("Hello World"u8.ToArray());
await buffer.FlushAsync();
bool gotData = _pipe.Reader.TryRead(out ReadResult result);
@@ -601,7 +601,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task WritingDataMakesDataReadableViaPipeline()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
await _pipe.Writer.WriteAsync(bytes);
ReadResult result = await _pipe.Reader.ReadAsync();
diff --git a/src/libraries/System.IO.Pipelines/tests/PipeWriterCopyToAsyncTests.cs b/src/libraries/System.IO.Pipelines/tests/PipeWriterCopyToAsyncTests.cs
index 4d9fb17b9ea..9977b6d9349 100644
--- a/src/libraries/System.IO.Pipelines/tests/PipeWriterCopyToAsyncTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/PipeWriterCopyToAsyncTests.cs
@@ -40,7 +40,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CopyToAsyncWorks()
{
- var helloBytes = Encoding.UTF8.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
var stream = new MemoryStream(helloBytes);
@@ -79,7 +79,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task StreamCopyToAsyncWorks()
{
- var helloBytes = Encoding.UTF8.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
var stream = new MemoryStream(helloBytes);
@@ -96,7 +96,7 @@ namespace System.IO.Pipelines.Tests
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public async Task CancelingViaCancelPendingFlushThrows()
{
- var helloBytes = Encoding.UTF8.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: helloBytes.Length - 1, resumeWriterThreshold: 0));
var stream = new MemoryStream(helloBytes);
@@ -115,7 +115,7 @@ namespace System.IO.Pipelines.Tests
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public async Task CancelingViaCancellationTokenThrows()
{
- var helloBytes = Encoding.UTF8.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: helloBytes.Length - 1, resumeWriterThreshold: 0));
var stream = new MemoryStream(helloBytes);
diff --git a/src/libraries/System.IO.Pipelines/tests/PipeWriterStreamTests.nonnetstandard.cs b/src/libraries/System.IO.Pipelines/tests/PipeWriterStreamTests.nonnetstandard.cs
index 57f6f8ee1e2..c7df5657c5d 100644
--- a/src/libraries/System.IO.Pipelines/tests/PipeWriterStreamTests.nonnetstandard.cs
+++ b/src/libraries/System.IO.Pipelines/tests/PipeWriterStreamTests.nonnetstandard.cs
@@ -49,7 +49,7 @@ namespace System.IO.Pipelines.Tests
[MemberData(nameof(WriteCalls))]
public async Task WritingToPipeStreamWritesToUnderlyingPipeWriter(WriteAsyncDelegate writeAsync)
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
var stream = new PipeWriterStream(pipe.Writer, leaveOpen: false);
@@ -65,7 +65,7 @@ namespace System.IO.Pipelines.Tests
[MemberData(nameof(WriteCalls))]
public async Task AsStreamReturnsPipeWriterStream(WriteAsyncDelegate writeAsync)
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
Stream stream = pipe.Writer.AsStream();
@@ -80,7 +80,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task FlushAsyncFlushesBufferedData()
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
Memory<byte> memory = pipe.Writer.GetMemory();
@@ -99,7 +99,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task ReadingFromPipeWriterStreamThrowsNotSupported()
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var pipe = new Pipe();
Stream stream = pipe.Writer.AsStream();
@@ -122,7 +122,7 @@ namespace System.IO.Pipelines.Tests
public async Task CancellingPendingFlushThrowsOperationCancelledException()
{
var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 10, resumeWriterThreshold: 0));
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
Stream stream = pipe.Writer.AsStream();
ValueTask task = stream.WriteAsync(helloBytes);
@@ -139,7 +139,7 @@ namespace System.IO.Pipelines.Tests
public async Task CancellationTokenFlowsToUnderlyingPipeWriter()
{
var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 10, resumeWriterThreshold: 0));
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
Stream stream = pipe.Writer.AsStream();
var cts = new CancellationTokenSource();
diff --git a/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs b/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs
index d7edb408ec3..5dbbeeef1bb 100644
--- a/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs
@@ -185,7 +185,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task WritesUsingGetSpanWorks()
{
- var bytes = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwzyz");
+ byte[] bytes = "abcdefghijklmnopqrstuvwzyz"u8.ToArray();
var pipe = new Pipe(new PipeOptions(pool: new HeapBufferPool(), minimumSegmentSize: 1));
PipeWriter writer = pipe.Writer;
@@ -208,7 +208,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task WritesUsingGetMemoryWorks()
{
- var bytes = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwzyz");
+ byte[] bytes = "abcdefghijklmnopqrstuvwzyz"u8.ToArray();
var pipe = new Pipe(new PipeOptions(pool: new HeapBufferPool(), minimumSegmentSize: 1));
PipeWriter writer = pipe.Writer;
diff --git a/src/libraries/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs b/src/libraries/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs
index 8422de30735..fb17873b6a1 100644
--- a/src/libraries/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs
@@ -32,7 +32,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CancellingBeforeAdvance()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
PipeWriter output = Pipe.Writer;
output.Write(bytes);
await output.FlushAsync();
@@ -65,7 +65,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CancellingPendingAfterReadAsync()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
PipeWriter output = Pipe.Writer;
output.Write(bytes);
@@ -116,7 +116,7 @@ namespace System.IO.Pipelines.Tests
Assert.True(result.IsCanceled);
Assert.True(buffer.IsEmpty);
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
PipeWriter output = Pipe.Writer;
output.Write(bytes);
await output.FlushAsync();
@@ -407,7 +407,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task WriteAndCancellingPendingReadBeforeReadAsync()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
PipeWriter output = Pipe.Writer;
output.Write(bytes);
await output.FlushAsync();
diff --git a/src/libraries/System.IO.Pipelines/tests/SchedulerFacts.cs b/src/libraries/System.IO.Pipelines/tests/SchedulerFacts.cs
index 000c908639f..ba558339b0a 100644
--- a/src/libraries/System.IO.Pipelines/tests/SchedulerFacts.cs
+++ b/src/libraries/System.IO.Pipelines/tests/SchedulerFacts.cs
@@ -68,7 +68,7 @@ namespace System.IO.Pipelines.Tests
Task reading = doRead();
PipeWriter buffer = pipe.Writer;
- buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ buffer.Write("Hello World"u8.ToArray());
// Don't run code on our sync context (we just want to make sure the callbacks)
// are scheduled on the sync context
@@ -112,7 +112,7 @@ namespace System.IO.Pipelines.Tests
Task reading = doRead();
PipeWriter buffer = pipe.Writer;
- buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ buffer.Write("Hello World"u8.ToArray());
// Don't run code on our sync context (we just want to make sure the callbacks)
// are scheduled on the sync context
@@ -160,7 +160,7 @@ namespace System.IO.Pipelines.Tests
Task reading = doRead();
PipeWriter buffer = pipe.Writer;
- buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ buffer.Write("Hello World"u8.ToArray());
// We don't want to run any code on our fake sync context
await buffer.FlushAsync().ConfigureAwait(false);
@@ -201,7 +201,7 @@ namespace System.IO.Pipelines.Tests
Task reading = ExecuteOnNonThreadPoolThread(doRead);
PipeWriter buffer = pipe.Writer;
- buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ buffer.Write("Hello World"u8.ToArray());
await buffer.FlushAsync();
pipe.Writer.Complete();
@@ -480,7 +480,7 @@ namespace System.IO.Pipelines.Tests
Task reading = ExecuteOnNonThreadPoolThread(doRead);
PipeWriter buffer = pipe.Writer;
- buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ buffer.Write("Hello World"u8.ToArray());
await buffer.FlushAsync();
await reading;
@@ -525,7 +525,7 @@ namespace System.IO.Pipelines.Tests
null);
#pragma warning restore CS0618 // Type or member is obsolete
- buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ buffer.Write("Hello World"u8.ToArray());
await buffer.FlushAsync();
await reading;
diff --git a/src/libraries/System.IO.Pipelines/tests/SequencePipeReaderTests.cs b/src/libraries/System.IO.Pipelines/tests/SequencePipeReaderTests.cs
index d12e4f1ec84..3c76c1568f8 100644
--- a/src/libraries/System.IO.Pipelines/tests/SequencePipeReaderTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/SequencePipeReaderTests.cs
@@ -16,7 +16,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CanRead()
{
- var sequence = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes("Hello World"));
+ var sequence = new ReadOnlySequence<byte>("Hello World"u8.ToArray());
var reader = PipeReader.Create(sequence);
ReadResult readResult = await reader.ReadAsync();
@@ -33,7 +33,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task TryReadReturnsTrueIfBufferedBytesAndNotExaminedEverything()
{
- var sequence = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes("Hello World"));
+ var sequence = new ReadOnlySequence<byte>("Hello World"u8.ToArray());
var reader = PipeReader.Create(sequence);
ReadResult readResult = await reader.ReadAsync();
@@ -53,7 +53,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task TryReadReturnsFalseIfBufferedBytesAndEverythingExamined()
{
- var sequence = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes("Hello World"));
+ var sequence = new ReadOnlySequence<byte>("Hello World"u8.ToArray());
var reader = PipeReader.Create(sequence);
ReadResult readResult = await reader.ReadAsync();
@@ -86,7 +86,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task DataCanBeReadMultipleTimes()
{
- var helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var sequence = new ReadOnlySequence<byte>(helloBytes);
PipeReader reader = PipeReader.Create(sequence);
diff --git a/src/libraries/System.IO.Pipelines/tests/StreamPipeReaderTests.cs b/src/libraries/System.IO.Pipelines/tests/StreamPipeReaderTests.cs
index b86151a9617..a59af1d40f2 100644
--- a/src/libraries/System.IO.Pipelines/tests/StreamPipeReaderTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/StreamPipeReaderTests.cs
@@ -17,7 +17,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CanRead()
{
- var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World"));
+ var stream = new MemoryStream("Hello World"u8.ToArray());
var reader = PipeReader.Create(stream);
ReadResult readResult = await reader.ReadAsync();
@@ -34,7 +34,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task TryReadReturnsTrueIfBufferedBytesAndNotExaminedEverything()
{
- var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World"));
+ var stream = new MemoryStream("Hello World"u8.ToArray());
var reader = PipeReader.Create(stream);
ReadResult readResult = await reader.ReadAsync();
@@ -54,7 +54,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task TryReadReturnsFalseIfBufferedBytesAndEverythingExamined()
{
- var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World"));
+ var stream = new MemoryStream("Hello World"u8.ToArray());
var reader = PipeReader.Create(stream);
ReadResult readResult = await reader.ReadAsync();
@@ -168,7 +168,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task BufferingDataPastEndOfStreamCanBeReadAgain()
{
- var helloBytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] helloBytes = "Hello World"u8.ToArray();
var stream = new ThrowAfterZeroByteReadStream(helloBytes);
PipeReader reader = PipeReader.Create(stream);
diff --git a/src/libraries/System.IO.Pipelines/tests/StreamPipeWriterTests.cs b/src/libraries/System.IO.Pipelines/tests/StreamPipeWriterTests.cs
index 4bd99672c49..6b158f8fdb2 100644
--- a/src/libraries/System.IO.Pipelines/tests/StreamPipeWriterTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/StreamPipeWriterTests.cs
@@ -16,7 +16,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void NothingWrittenToStreamUnlessFlushed()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream);
@@ -33,7 +33,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void DataFlushedOnComplete()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true));
@@ -52,7 +52,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task DataFlushedOnCompleteAsync()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true));
@@ -71,7 +71,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void DataNotFlushedOnCompleteWithException()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true));
@@ -88,7 +88,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task DataNotFlushedOnCompleteAsyncWithException()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true));
@@ -105,7 +105,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CompleteAsyncDoesNotThrowObjectDisposedException()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true));
@@ -124,7 +124,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task DataWrittenOnFlushAsync()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream);
@@ -155,7 +155,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task WritesUsingGetSpanWorks()
{
- var bytes = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwzyz");
+ byte[] bytes = "abcdefghijklmnopqrstuvwzyz"u8.ToArray();
var stream = new MemoryStream();
var options = new StreamPipeWriterOptions(new HeapBufferPool(), minimumBufferSize: 1);
PipeWriter writer = PipeWriter.Create(stream, options);
@@ -175,7 +175,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task WritesUsingGetMemoryWorks()
{
- var bytes = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwzyz");
+ byte[] bytes = "abcdefghijklmnopqrstuvwzyz"u8.ToArray();
var stream = new MemoryStream();
var options = new StreamPipeWriterOptions(new HeapBufferPool(), minimumBufferSize: 1);
PipeWriter writer = PipeWriter.Create(stream, options);
@@ -234,10 +234,10 @@ namespace System.IO.Pipelines.Tests
var data = new List<byte[]>
{
- Encoding.ASCII.GetBytes("Hello"),
- Encoding.ASCII.GetBytes("World"),
- Encoding.ASCII.GetBytes("This"),
- Encoding.ASCII.GetBytes("Works"),
+ "Hello"u8.ToArray(),
+ "World"u8.ToArray(),
+ "This"u8.ToArray(),
+ "Works"u8.ToArray(),
}.
ToArray();
@@ -438,7 +438,7 @@ namespace System.IO.Pipelines.Tests
{
using (var pool = new DisposeTrackingBufferPool())
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
var options = new StreamPipeWriterOptions(pool);
PipeWriter writer = PipeWriter.Create(stream, options);
@@ -484,7 +484,7 @@ namespace System.IO.Pipelines.Tests
{
using (var pool = new DisposeTrackingBufferPool())
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
var options = new StreamPipeWriterOptions(pool);
PipeWriter writer = PipeWriter.Create(stream, options);
@@ -628,7 +628,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void UnflushedBytesWorks()
{
- byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] bytes = "Hello World"u8.ToArray();
var stream = new MemoryStream();
PipeWriter writer = PipeWriter.Create(stream);
diff --git a/src/libraries/System.IO.Pipelines/tests/UnflushedBytesTests.cs b/src/libraries/System.IO.Pipelines/tests/UnflushedBytesTests.cs
index 1c2c15e9495..d9a4e7c8fdb 100644
--- a/src/libraries/System.IO.Pipelines/tests/UnflushedBytesTests.cs
+++ b/src/libraries/System.IO.Pipelines/tests/UnflushedBytesTests.cs
@@ -39,7 +39,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void UnflushedBytesWorks()
{
- byte[] bytes = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwzyz");
+ byte[] bytes = "abcdefghijklmnopqrstuvwzyz"u8.ToArray();
Pipe.Writer.Write(bytes);
Assert.True(Pipe.Writer.CanGetUnflushedBytes);
Assert.Equal(bytes.Length,Pipe.Writer.UnflushedBytes);
diff --git a/src/libraries/System.Memory.Data/tests/BinaryDataTests.cs b/src/libraries/System.Memory.Data/tests/BinaryDataTests.cs
index be626539f5e..3ec81641684 100644
--- a/src/libraries/System.Memory.Data/tests/BinaryDataTests.cs
+++ b/src/libraries/System.Memory.Data/tests/BinaryDataTests.cs
@@ -20,7 +20,7 @@ namespace System.Tests
[Fact]
public void CanCreateBinaryDataFromBytes()
{
- byte[] payload = Encoding.UTF8.GetBytes("some data");
+ byte[] payload = "some data"u8.ToArray();
BinaryData data = BinaryData.FromBytes(payload);
Assert.Equal(payload, data.ToArray());
@@ -84,7 +84,7 @@ namespace System.Tests
[Fact]
public async Task CannotWriteToReadOnlyMemoryStream()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
using MemoryStream payload = new MemoryStream(buffer);
BinaryData data = BinaryData.FromStream(payload);
Stream stream = data.ToStream();
@@ -99,7 +99,7 @@ namespace System.Tests
[Fact]
public async Task ToStreamIsMutatedWhenCustomerOwnsBuffer()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
BinaryData data = BinaryData.FromBytes(buffer);
Stream stream = data.ToStream();
buffer[0] = (byte)'z';
@@ -110,7 +110,7 @@ namespace System.Tests
[Fact]
public async Task ToStreamIsNotMutatedWhenBinaryDataOwnsBuffer()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
BinaryData data = BinaryData.FromStream(new MemoryStream(buffer));
Stream stream = data.ToStream();
buffer[0] = (byte)'z';
@@ -121,7 +121,7 @@ namespace System.Tests
[Fact]
public async Task CanCreateBinaryDataFromStream()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
using MemoryStream stream = new MemoryStream(buffer, 0, buffer.Length, true, true);
BinaryData data = BinaryData.FromStream(stream);
Assert.Equal(buffer, data.ToArray());
@@ -147,7 +147,7 @@ namespace System.Tests
[Fact]
public async Task CanCreateBinaryDataFromLongStream()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
using MemoryStream stream = new OverFlowStream(offset: int.MaxValue - 10000, buffer);
BinaryData data = BinaryData.FromStream(stream);
Assert.Equal(buffer, data.ToArray());
@@ -178,7 +178,7 @@ namespace System.Tests
Assert.Empty(data.ToArray());
// stream at end
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
stream.Write(buffer, 0, buffer.Length);
data = BinaryData.FromStream(stream);
Assert.Empty(data.ToArray());
@@ -190,7 +190,7 @@ namespace System.Tests
[Fact]
public async Task CanCreateBinaryDataFromStreamUsingBackingBuffer()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
using MemoryStream stream = new MemoryStream();
stream.Write(buffer, 0, buffer.Length);
stream.Position = 0;
@@ -214,7 +214,7 @@ namespace System.Tests
[Fact]
public async Task CanCreateBinaryDataFromNonSeekableStream()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
using MemoryStream stream = new NonSeekableStream(buffer);
BinaryData data = BinaryData.FromStream(stream);
Assert.Equal(buffer, data.ToArray());
@@ -236,7 +236,7 @@ namespace System.Tests
[Fact]
public async Task CanCreateBinaryDataFromFileStream()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
using FileStream stream = new FileStream(Path.GetTempFileName(), FileMode.Open);
stream.Write(buffer, 0, buffer.Length);
stream.Position = 0;
@@ -265,7 +265,7 @@ namespace System.Tests
public async Task StartPositionOfStreamRespected(int bufferOffset, long streamStart)
{
var input = "some data";
- ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes("some data"), bufferOffset, input.Length - bufferOffset);
+ ArraySegment<byte> buffer = new ArraySegment<byte>("some data"u8.ToArray(), bufferOffset, input.Length - bufferOffset);
MemoryStream stream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count);
var payload = new ReadOnlyMemory<byte>(buffer.Array, buffer.Offset, buffer.Count).Slice((int)streamStart);
@@ -288,7 +288,7 @@ namespace System.Tests
public async Task StartPositionOfStreamRespectedBackingBuffer(int bufferOffset, long streamStart)
{
var input = "some data";
- ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes("some data"), bufferOffset, input.Length - bufferOffset);
+ ArraySegment<byte> buffer = new ArraySegment<byte>("some data"u8.ToArray(), bufferOffset, input.Length - bufferOffset);
MemoryStream stream = new MemoryStream();
stream.Write(buffer.Array, buffer.Offset, buffer.Count);
@@ -411,12 +411,12 @@ namespace System.Tests
[Fact]
public void EqualsRespectsReferenceEquality()
{
- byte[] payload = Encoding.UTF8.GetBytes("some data");
+ byte[] payload = "some data"u8.ToArray();
BinaryData a = BinaryData.FromBytes(payload);
BinaryData b = BinaryData.FromBytes(payload);
Assert.NotEqual(a, b);
- BinaryData c = BinaryData.FromBytes(Encoding.UTF8.GetBytes("some data"));
+ BinaryData c = BinaryData.FromBytes("some data"u8.ToArray());
Assert.NotEqual(a, c);
Assert.False(a.Equals("string data"));
@@ -425,7 +425,7 @@ namespace System.Tests
[Fact]
public void GetHashCodeWorks()
{
- byte[] payload = Encoding.UTF8.GetBytes("some data");
+ byte[] payload = "some data"u8.ToArray();
BinaryData a = BinaryData.FromBytes(payload);
BinaryData b = BinaryData.FromBytes(payload);
HashSet<BinaryData> set = new HashSet<BinaryData>
@@ -435,7 +435,7 @@ namespace System.Tests
// hashcodes of a and b should not match since instances are different.
Assert.DoesNotContain(b, set);
- BinaryData c = BinaryData.FromBytes(Encoding.UTF8.GetBytes("some data"));
+ BinaryData c = BinaryData.FromBytes("some data"u8.ToArray());
// c should have a different hash code
Assert.DoesNotContain(c, set);
set.Add(c);
@@ -445,7 +445,7 @@ namespace System.Tests
[Fact]
public async Task CanRead()
{
- var buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
var stream = new BinaryData(buffer).ToStream();
var read = new byte[buffer.Length];
@@ -465,7 +465,7 @@ namespace System.Tests
[Fact]
public async Task CanReadPartial()
{
- var buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
var stream = new BinaryData(buffer).ToStream();
var length = 4;
var read = new byte[length];
@@ -486,7 +486,7 @@ namespace System.Tests
[Fact]
public void ReadAsyncRespectsCancellation()
{
- var buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
var stream = new BinaryData(buffer).ToStream();
var read = new byte[buffer.Length];
@@ -505,7 +505,7 @@ namespace System.Tests
[Fact]
public async Task CanSeek()
{
- var buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
var stream = new BinaryData(buffer).ToStream();
stream.Seek(5, SeekOrigin.Begin);
@@ -526,7 +526,7 @@ namespace System.Tests
[Fact]
public void ValidatesSeekArguments()
{
- var buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
var stream = new BinaryData(buffer).ToStream();
Assert.Throws<IOException>(() => stream.Seek(-1, SeekOrigin.Begin));
@@ -539,7 +539,7 @@ namespace System.Tests
[Fact]
public async Task ValidatesReadArguments()
{
- var buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
var stream = new BinaryData(buffer).ToStream();
stream.Seek(3, SeekOrigin.Begin);
var read = new byte[buffer.Length - stream.Position];
@@ -556,7 +556,7 @@ namespace System.Tests
[Fact]
public void ValidatesPositionValue()
{
- var buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
var stream = new BinaryData(buffer).ToStream();
Assert.Throws<ArgumentOutOfRangeException>(() => stream.Position = -1);
Assert.Throws<ArgumentOutOfRangeException>(() => stream.Position = (long)int.MaxValue + 1);
@@ -565,7 +565,7 @@ namespace System.Tests
[Fact]
public void CloseStreamValidation()
{
- byte[] buffer = Encoding.UTF8.GetBytes("some data");
+ byte[] buffer = "some data"u8.ToArray();
Stream stream = new BinaryData(buffer).ToStream();
stream.Dispose();
Assert.Throws<ObjectDisposedException>(() => stream.Position = -1);
diff --git a/src/libraries/System.Memory/tests/Base64/Base64DecoderUnitTests.cs b/src/libraries/System.Memory/tests/Base64/Base64DecoderUnitTests.cs
index 92e88fee8e9..1b447f8faa7 100644
--- a/src/libraries/System.Memory/tests/Base64/Base64DecoderUnitTests.cs
+++ b/src/libraries/System.Memory/tests/Base64/Base64DecoderUnitTests.cs
@@ -337,7 +337,7 @@ namespace System.Buffers.Text.Tests
for (int j = 0; j < 8; j++)
{
- Span<byte> source = new byte[8] { 50, 50, 50, 50, 80, 80, 80, 80 }; // valid input - "2222PPPP"
+ Span<byte> source = "2222PPPP"u8.ToArray(); // valid input
Span<byte> decodedBytes = new byte[Base64.GetMaxDecodedFromUtf8Length(source.Length)];
for (int i = 0; i < invalidBytes.Length; i++)
@@ -368,7 +368,7 @@ namespace System.Buffers.Text.Tests
// Input that is not a multiple of 4 is considered invalid, if isFinalBlock = true
if (isFinalBlock)
{
- Span<byte> source = new byte[7] { 50, 50, 50, 50, 80, 80, 80 }; // incomplete input - "2222PPP"
+ Span<byte> source = "2222PPP"u8.ToArray(); // incomplete input
Span<byte> decodedBytes = new byte[Base64.GetMaxDecodedFromUtf8Length(source.Length)];
Assert.Equal(OperationStatus.InvalidData, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int decodedByteCount));
Assert.Equal(4, consumed);
@@ -385,7 +385,7 @@ namespace System.Buffers.Text.Tests
// Only last 2 bytes can be padding, all other occurrence of padding is invalid
for (int j = 0; j < 7; j++)
{
- Span<byte> source = new byte[] { 50, 50, 50, 50, 80, 80, 80, 80 }; // valid input - "2222PPPP"
+ Span<byte> source = "2222PPPP"u8.ToArray(); // valid input
Span<byte> decodedBytes = new byte[Base64.GetMaxDecodedFromUtf8Length(source.Length)];
source[j] = Base64TestHelper.EncodingPad;
Assert.Equal(OperationStatus.InvalidData, Base64.DecodeFromUtf8(source, decodedBytes, out int consumed, out int decodedByteCount, isFinalBlock));
@@ -535,7 +535,7 @@ namespace System.Buffers.Text.Tests
{
for (int i = 0; i < invalidBytes.Length; i++)
{
- Span<byte> buffer = new byte[8] { 50, 50, 50, 50, 80, 80, 80, 80 }; // valid input - "2222PPPP"
+ Span<byte> buffer = "2222PPPP"u8.ToArray(); // valid input
// Don't test padding (byte 61 i.e. '='), which is tested in DecodeInPlaceInvalidBytesPadding
if (invalidBytes[i] == Base64TestHelper.EncodingPad)
@@ -562,7 +562,7 @@ namespace System.Buffers.Text.Tests
// Input that is not a multiple of 4 is considered invalid
{
- Span<byte> buffer = new byte[7] { 50, 50, 50, 50, 80, 80, 80 }; // incomplete input - "2222PPP"
+ Span<byte> buffer = "2222PPP"u8.ToArray(); // incomplete input
Assert.Equal(OperationStatus.InvalidData, Base64.DecodeFromUtf8InPlace(buffer, out int bytesWritten));
Assert.Equal(0, bytesWritten);
}
@@ -574,7 +574,7 @@ namespace System.Buffers.Text.Tests
// Only last 2 bytes can be padding, all other occurrence of padding is invalid
for (int j = 0; j < 7; j++)
{
- Span<byte> buffer = new byte[] { 50, 50, 50, 50, 80, 80, 80, 80 }; // valid input - "2222PPPP"
+ Span<byte> buffer = "2222PPPP"u8.ToArray(); // valid input
buffer[j] = Base64TestHelper.EncodingPad;
string sourceString = Encoding.ASCII.GetString(buffer.Slice(0, 4).ToArray());
diff --git a/src/libraries/System.Memory/tests/BuffersExtensions/BuffersExtensionsTests.cs b/src/libraries/System.Memory/tests/BuffersExtensions/BuffersExtensionsTests.cs
index fc55fbe29fa..d3f180d9230 100644
--- a/src/libraries/System.Memory/tests/BuffersExtensions/BuffersExtensionsTests.cs
+++ b/src/libraries/System.Memory/tests/BuffersExtensions/BuffersExtensionsTests.cs
@@ -13,8 +13,8 @@ namespace System.Buffers.Tests
public void WritingToSingleSegmentBuffer()
{
IBufferWriter<byte> bufferWriter = new TestBufferWriterSingleSegment();
- bufferWriter.Write(Encoding.UTF8.GetBytes("Hello"));
- bufferWriter.Write(Encoding.UTF8.GetBytes(" World!"));
+ bufferWriter.Write("Hello"u8);
+ bufferWriter.Write(" World!"u8);
Assert.Equal("Hello World!", bufferWriter.ToString());
}
@@ -22,8 +22,8 @@ namespace System.Buffers.Tests
public void WritingToMultiSegmentBuffer()
{
var bufferWriter = new TestBufferWriterMultiSegment();
- bufferWriter.Write(Encoding.UTF8.GetBytes("Hello"));
- bufferWriter.Write(Encoding.UTF8.GetBytes(" World!"));
+ bufferWriter.Write("Hello"u8);
+ bufferWriter.Write(" World!"u8);
Assert.Equal(12, bufferWriter.Comitted.Count);
Assert.Equal("Hello World!", bufferWriter.ToString());
}
diff --git a/src/libraries/System.Memory/tests/EncodingExtensions/EncodingExtensionsTests.cs b/src/libraries/System.Memory/tests/EncodingExtensions/EncodingExtensionsTests.cs
index 268b59b909b..b3c8b9e33c9 100644
--- a/src/libraries/System.Memory/tests/EncodingExtensions/EncodingExtensionsTests.cs
+++ b/src/libraries/System.Memory/tests/EncodingExtensions/EncodingExtensionsTests.cs
@@ -74,7 +74,7 @@ namespace System.Text.Tests
// First, a small input with no flushing and no leftover data.
- ReadOnlySpan<byte> inputData = Encoding.UTF8.GetBytes("Hello");
+ ReadOnlySpan<byte> inputData = "Hello"u8;
EncodingExtensions.Convert(decoder, inputData, writer, flush: false, out long charsUsed, out bool completed);
Assert.Equal(5, charsUsed);
Assert.True(completed);
@@ -236,7 +236,7 @@ namespace System.Text.Tests
// Now make sure all of the data was decoded properly.
- Assert.Equal(Encoding.UTF8.GetBytes("\u0020\ud7ff\U00100000\ufffd"), writer.WrittenSpan.ToArray());
+ Assert.Equal("\u0020\ud7ff\U00100000\ufffd"u8.ToArray(), writer.WrittenSpan.ToArray());
}
[Fact]
@@ -252,7 +252,7 @@ namespace System.Text.Tests
// First try the single-segment code path.
ReadOnlySequence<char> sequence = new ReadOnlySequence<char>("Hello!".ToCharArray());
- Assert.Equal(Encoding.UTF8.GetBytes("Hello!"), EncodingExtensions.GetBytes(Encoding.UTF8, sequence));
+ Assert.Equal("Hello!"u8.ToArray(), EncodingExtensions.GetBytes(Encoding.UTF8, sequence));
// Next try the multi-segment code path.
// We've intentionally split multi-char subsequences here to test flushing mechanisms.
@@ -266,7 +266,7 @@ namespace System.Text.Tests
new char[] { '\udfff' }, // (cont.)
new char[] { '\ud800' }); // leftover data (should be replaced)
- Assert.Equal(Encoding.UTF8.GetBytes("\u0020\u0061\u0080\U00010000\U0010FFFF\ufffd"), EncodingExtensions.GetBytes(Encoding.UTF8, sequence));
+ Assert.Equal("\u0020\u0061\u0080\U00010000\U0010FFFF\ufffd"u8.ToArray(), EncodingExtensions.GetBytes(Encoding.UTF8, sequence));
}
[Fact]
@@ -278,7 +278,7 @@ namespace System.Text.Tests
long bytesWritten = EncodingExtensions.GetBytes(Encoding.UTF8, sequence, writer);
Assert.Equal(5, bytesWritten);
- Assert.Equal(Encoding.UTF8.GetBytes("Hello"), writer.WrittenSpan.ToArray());
+ Assert.Equal("Hello"u8.ToArray(), writer.WrittenSpan.ToArray());
}
[Fact]
@@ -320,7 +320,7 @@ namespace System.Text.Tests
ReadOnlySequence<char> sequence = new ReadOnlySequence<char>("Hello!".ToCharArray());
Assert.Equal(
- expected: Encoding.UTF8.GetBytes("Hello!"),
+ expected: "Hello!"u8.ToArray(),
actual: destination.Slice(0, EncodingExtensions.GetBytes(Encoding.UTF8, sequence, destination)).ToArray());
// Next try the multi-segment code path.
@@ -336,7 +336,7 @@ namespace System.Text.Tests
new char[] { '\ud800' }); // leftover data (should be replaced)
Assert.Equal(
- expected: Encoding.UTF8.GetBytes("\u0020\u0061\u0080\U00010000\U0010FFFF\ufffd"),
+ expected: "\u0020\u0061\u0080\U00010000\U0010FFFF\ufffd"u8.ToArray(),
actual: destination.Slice(0, EncodingExtensions.GetBytes(Encoding.UTF8, sequence, destination)).ToArray());
}
@@ -359,7 +359,7 @@ namespace System.Text.Tests
ReadOnlySpan<char> inputData = "Hello";
long bytesWritten = EncodingExtensions.GetBytes(Encoding.UTF8, inputData, writer);
Assert.Equal(5, bytesWritten);
- Assert.Equal(Encoding.UTF8.GetBytes("Hello"), writer.WrittenSpan.ToArray());
+ Assert.Equal("Hello"u8.ToArray(), writer.WrittenSpan.ToArray());
// Then, a large input that goes through the chunked path.
// We alternate between 1-char and 2-char sequences so that the input will be split in
@@ -399,7 +399,7 @@ namespace System.Text.Tests
{
// First try the single-segment code path.
- ReadOnlySequence<byte> sequence = new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes("Hello!"));
+ ReadOnlySequence<byte> sequence = new ReadOnlySequence<byte>("Hello!"u8.ToArray());
Assert.Equal("Hello!", EncodingExtensions.GetString(Encoding.UTF8, sequence));
// Next try the multi-segment code path.
@@ -427,7 +427,7 @@ namespace System.Text.Tests
[Fact]
public static void GetChars_Encoding_ReadOnlySequence_IBufferWriter_SingleSegment()
{
- ReadOnlySequence<byte> sequence = new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes("Hello"));
+ ReadOnlySequence<byte> sequence = new ReadOnlySequence<byte>("Hello"u8.ToArray());
ArrayBufferWriter<char> writer = new ArrayBufferWriter<char>();
long charsWritten = EncodingExtensions.GetChars(Encoding.UTF8, sequence, writer);
@@ -466,7 +466,7 @@ namespace System.Text.Tests
// First try the single-segment code path.
- ReadOnlySequence<byte> sequence = new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes("Hello!"));
+ ReadOnlySequence<byte> sequence = new ReadOnlySequence<byte>("Hello!"u8.ToArray());
Assert.Equal("Hello!", destination.Slice(0, EncodingExtensions.GetChars(Encoding.UTF8, sequence, destination)).ToString());
// Next try the multi-segment code path.
@@ -507,7 +507,7 @@ namespace System.Text.Tests
// First, a small input that goes through the one-shot code path.
- ReadOnlySpan<byte> inputData = Encoding.UTF8.GetBytes("Hello");
+ ReadOnlySpan<byte> inputData = "Hello"u8;
long charsWritten = EncodingExtensions.GetChars(Encoding.UTF8, inputData, writer);
Assert.Equal(5, charsWritten);
Assert.Equal("Hello", writer.WrittenSpan.ToString());
diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.byte.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.byte.cs
index 60e3a6b676d..0681d04de2a 100644
--- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.byte.cs
+++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.byte.cs
@@ -44,7 +44,7 @@ namespace System.Memory.Tests
// [padding..hello] -> [ world ]
const int blockSize = 4096;
- byte[] items = Encoding.ASCII.GetBytes("Hello World");
+ byte[] items = "Hello World"u8.ToArray();
byte[] firstItems = Enumerable.Repeat((byte)'a', blockSize - 5).Concat(items.Take(5)).ToArray();
byte[] secondItems = items.Skip(5).Concat(Enumerable.Repeat((byte)'a', blockSize - (items.Length - 5))).ToArray();
diff --git a/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs b/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs
index b042eb9d556..ab7399d30bc 100644
--- a/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs
+++ b/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs
@@ -259,8 +259,8 @@ namespace System.Memory.Tests.SequenceReader
public void TryReadTo_Span_At_Segments_Boundary()
{
Span<byte> delimiter = new byte[] { 13, 10 }; // \r\n
- BufferSegment<byte> segment = new BufferSegment<byte>(Text.Encoding.ASCII.GetBytes("Hello\r"));
- segment.Append(Text.Encoding.ASCII.GetBytes("\nWorld")); // add next segment
+ BufferSegment<byte> segment = new BufferSegment<byte>("Hello\r"u8.ToArray());
+ segment.Append("\nWorld"u8.ToArray()); // add next segment
ReadOnlySequence<byte> inputSeq = new ReadOnlySequence<byte>(segment, 0, segment, 6); // span only the first segment!
SequenceReader<byte> sr = new SequenceReader<byte>(inputSeq);
bool r = sr.TryReadTo(out ReadOnlySpan<byte> _, delimiter);
diff --git a/src/libraries/System.Memory/tests/SequenceReader/SkipDelimiter.cs b/src/libraries/System.Memory/tests/SequenceReader/SkipDelimiter.cs
index 526a5fffe6b..a28b2d5435e 100644
--- a/src/libraries/System.Memory/tests/SequenceReader/SkipDelimiter.cs
+++ b/src/libraries/System.Memory/tests/SequenceReader/SkipDelimiter.cs
@@ -12,7 +12,7 @@ namespace System.Memory.Tests.SequenceReader
[Fact]
public void TryReadTo_SkipDelimiter()
{
- byte[] expected = Encoding.UTF8.GetBytes("This is our ^|understanding^|");
+ byte[] expected = "This is our ^|understanding^|"u8.ToArray();
ReadOnlySequence<byte> bytes = SequenceFactory.CreateUtf8("This is our ^|understanding^|| you see.");
SequenceReader<byte> reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'|', (byte)'^', advancePastDelimiter: true));
@@ -125,12 +125,12 @@ namespace System.Memory.Tests.SequenceReader
bytes = SequenceFactory.CreateUtf8("abc^|de|");
reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out span, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^|de"), span.ToArray());
+ Assert.Equal("abc^|de"u8.ToArray(), span.ToArray());
Assert.True(reader.End);
Assert.Equal(8, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out sequence, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^|de"), sequence.ToArray());
+ Assert.Equal("abc^|de"u8.ToArray(), sequence.ToArray());
Assert.True(reader.End);
Assert.Equal(8, reader.Consumed);
@@ -138,12 +138,12 @@ namespace System.Memory.Tests.SequenceReader
bytes = SequenceFactory.CreateUtf8("^|a|b");
reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out span, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("^|a"), span.ToArray());
+ Assert.Equal("^|a"u8.ToArray(), span.ToArray());
Assert.True(reader.IsNext((byte)'b'));
Assert.Equal(4, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out sequence, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("^|a"), sequence.ToArray());
+ Assert.Equal("^|a"u8.ToArray(), sequence.ToArray());
Assert.True(reader.IsNext((byte)'b'));
Assert.Equal(4, reader.Consumed);
@@ -151,12 +151,12 @@ namespace System.Memory.Tests.SequenceReader
bytes = SequenceFactory.CreateUtf8("^", "|a|b");
reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out span, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("^|a"), span.ToArray());
+ Assert.Equal("^|a"u8.ToArray(), span.ToArray());
Assert.True(reader.IsNext((byte)'b'));
Assert.Equal(4, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out sequence, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("^|a"), sequence.ToArray());
+ Assert.Equal("^|a"u8.ToArray(), sequence.ToArray());
Assert.True(reader.IsNext((byte)'b'));
Assert.Equal(4, reader.Consumed);
}
@@ -167,12 +167,12 @@ namespace System.Memory.Tests.SequenceReader
ReadOnlySequence<byte> bytes = SequenceFactory.CreateUtf8("abc^^|def");
SequenceReader<byte> reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), span.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), span.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(5, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out ReadOnlySequence<byte> sequence, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), sequence.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), sequence.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(5, reader.Consumed);
@@ -180,12 +180,12 @@ namespace System.Memory.Tests.SequenceReader
bytes = SequenceFactory.CreateUtf8("abc^^", "|def");
reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out span, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), span.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), span.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(5, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out sequence, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), sequence.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), sequence.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(5, reader.Consumed);
@@ -193,24 +193,24 @@ namespace System.Memory.Tests.SequenceReader
bytes = SequenceFactory.CreateUtf8("abc^", "^", "|def");
reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out span, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), span.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), span.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(5, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out sequence, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), sequence.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), sequence.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(5, reader.Consumed);
// Check advance past delimiter
reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out span, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), span.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), span.ToArray());
Assert.True(reader.IsNext((byte)'d'));
Assert.Equal(6, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out sequence, (byte)'|', (byte)'^', advancePastDelimiter: true));
- Assert.Equal(Encoding.UTF8.GetBytes("abc^^"), sequence.ToArray());
+ Assert.Equal("abc^^"u8.ToArray(), sequence.ToArray());
Assert.True(reader.IsNext((byte)'d'));
Assert.Equal(6, reader.Consumed);
@@ -218,12 +218,12 @@ namespace System.Memory.Tests.SequenceReader
bytes = SequenceFactory.CreateUtf8("^^|abc");
reader = new SequenceReader<byte>(bytes);
Assert.True(reader.TryReadTo(out span, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("^^"), span.ToArray());
+ Assert.Equal("^^"u8.ToArray(), span.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(2, reader.Consumed);
reader.Rewind(reader.Consumed);
Assert.True(reader.TryReadTo(out sequence, (byte)'|', (byte)'^', advancePastDelimiter: false));
- Assert.Equal(Encoding.UTF8.GetBytes("^^"), sequence.ToArray());
+ Assert.Equal("^^"u8.ToArray(), sequence.ToArray());
Assert.True(reader.IsNext((byte)'|'));
Assert.Equal(2, reader.Consumed);
diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
index 6d2fa2bd1df..c50f09b3e2f 100644
--- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
+++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
@@ -16,8 +16,8 @@ namespace System.Net.Http
{
internal sealed class WinHttpRequestStream : Stream
{
- private static readonly byte[] s_crLfTerminator = new byte[] { 0x0d, 0x0a }; // "\r\n"
- private static readonly byte[] s_endChunk = new byte[] { 0x30, 0x0d, 0x0a, 0x0d, 0x0a }; // "0\r\n\r\n"
+ private static readonly byte[] s_crLfTerminator = "\r\n"u8.ToArray();
+ private static readonly byte[] s_endChunk = "0\r\n\r\n"u8.ToArray();
private volatile bool _disposed;
private readonly WinHttpRequestState _state;
diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs
index 0277ca26e81..d18de54bc46 100644
--- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs
+++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs
@@ -30,7 +30,7 @@ namespace System.Net.Http.WinHttpHandlerFunctional.Tests
protected override Version UseVersion => new Version(2, 0);
- protected static byte[] DataBytes = Encoding.ASCII.GetBytes("data");
+ protected static byte[] DataBytes = "data"u8.ToArray();
protected static Frame MakeDataFrame(int streamId, byte[] data, bool endStream = false) =>
new DataFrame(data, (endStream ? FrameFlags.EndStream : FrameFlags.None), 0, streamId);
diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj
index ac4d036552f..93d7e9a899d 100644
--- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj
@@ -3,7 +3,6 @@
<TargetFrameworks>$(NetCoreAppCurrent)-windows;net48</TargetFrameworks>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
<DefineConstants>$(DefineConstants);WINHTTPHANDLER_TEST</DefineConstants>
- <LangVersion>10.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(CommonTestPath)System\Net\Configuration.cs"
diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/TrailingHeadersTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/TrailingHeadersTest.cs
index 5ac753c266e..2d473b8760e 100644
--- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/TrailingHeadersTest.cs
+++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/TrailingHeadersTest.cs
@@ -28,7 +28,7 @@ namespace System.Net.Http.WinHttpHandlerFunctional.Tests
protected override Version UseVersion => new Version(2, 0);
- protected static byte[] DataBytes = Encoding.ASCII.GetBytes("data");
+ protected static byte[] DataBytes = "data"u8.ToArray();
protected static readonly IList<HttpHeaderData> TrailingHeaders = new HttpHeaderData[] {
new HttpHeaderData("MyCoolTrailerHeader", "amazingtrailer"),
diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpResponseStreamTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpResponseStreamTest.cs
index 90900a0517e..9b5e37c9581 100644
--- a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpResponseStreamTest.cs
+++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpResponseStreamTest.cs
@@ -331,7 +331,7 @@ namespace System.Net.Http.WinHttpHandlerUnitTests
public void Read_NoOffsetAndNotEndOfData_FillsBuffer()
{
Stream stream = MakeResponseStream();
- byte[] testData = Encoding.UTF8.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ byte[] testData = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"u8.ToArray();
TestServer.ResponseBody = testData;
byte[] buffer = new byte[testData.Length];
@@ -348,7 +348,7 @@ namespace System.Net.Http.WinHttpHandlerUnitTests
public void Read_UsingOffsetAndNotEndOfData_FillsBufferFromOffset()
{
Stream stream = MakeResponseStream();
- byte[] testData = Encoding.UTF8.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ byte[] testData = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"u8.ToArray();
TestServer.ResponseBody = testData;
byte[] buffer = new byte[testData.Length];
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs
index dc38ad705ae..2cef6b1642a 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs
@@ -239,7 +239,7 @@ namespace System.Net.Http
using var args = new System.Runtime.InteropServices.JavaScript.Array();
if (request.RequestUri != null)
{
- args.Push(request.RequestUri.ToString());
+ args.Push(request.RequestUri.IsAbsoluteUri ? request.RequestUri.AbsoluteUri : request.RequestUri.ToString());
args.Push(requestObject);
}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs
index e522822c6ca..b0154dda843 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs
@@ -477,7 +477,7 @@ namespace System.Net.Http
private static readonly (HeaderDescriptor descriptor, byte[] value)[] s_hpackStaticHeaderTable = new (HeaderDescriptor, byte[])[LastHPackNormalHeaderId - FirstHPackNormalHeaderId + 1]
{
(KnownHeaders.AcceptCharset.Descriptor, Array.Empty<byte>()),
- (KnownHeaders.AcceptEncoding.Descriptor, Encoding.ASCII.GetBytes("gzip, deflate")),
+ (KnownHeaders.AcceptEncoding.Descriptor, "gzip, deflate"u8.ToArray()),
(KnownHeaders.AcceptLanguage.Descriptor, Array.Empty<byte>()),
(KnownHeaders.AcceptRanges.Descriptor, Array.Empty<byte>()),
(KnownHeaders.Accept.Descriptor, Array.Empty<byte>()),
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
index d3d2b39d280..7edd0b84b39 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
@@ -41,13 +41,13 @@ namespace System.Net.Http
/// </remarks>
private const int MaxChunkBytesAllowed = 16 * 1024;
- private static readonly byte[] s_contentLength0NewlineAsciiBytes = Encoding.ASCII.GetBytes("Content-Length: 0\r\n");
- private static readonly byte[] s_spaceHttp10NewlineAsciiBytes = Encoding.ASCII.GetBytes(" HTTP/1.0\r\n");
- private static readonly byte[] s_spaceHttp11NewlineAsciiBytes = Encoding.ASCII.GetBytes(" HTTP/1.1\r\n");
- private static readonly byte[] s_httpSchemeAndDelimiter = Encoding.ASCII.GetBytes(Uri.UriSchemeHttp + Uri.SchemeDelimiter);
- private static readonly byte[] s_http1DotBytes = Encoding.ASCII.GetBytes("HTTP/1.");
- private static readonly ulong s_http10Bytes = BitConverter.ToUInt64(Encoding.ASCII.GetBytes("HTTP/1.0"));
- private static readonly ulong s_http11Bytes = BitConverter.ToUInt64(Encoding.ASCII.GetBytes("HTTP/1.1"));
+ private static readonly byte[] s_contentLength0NewlineAsciiBytes = "Content-Length: 0\r\n"u8.ToArray();
+ private static readonly byte[] s_spaceHttp10NewlineAsciiBytes = " HTTP/1.0\r\n"u8.ToArray();
+ private static readonly byte[] s_spaceHttp11NewlineAsciiBytes = " HTTP/1.1\r\n"u8.ToArray();
+ private static readonly byte[] s_httpSchemeAndDelimiter = "http://"u8.ToArray();
+ private static readonly byte[] s_http1DotBytes = "HTTP/1."u8.ToArray();
+ private static readonly ulong s_http10Bytes = BitConverter.ToUInt64("HTTP/1.0"u8);
+ private static readonly ulong s_http11Bytes = BitConverter.ToUInt64("HTTP/1.1"u8);
private readonly HttpConnectionPool _pool;
private readonly Stream _stream;
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
index a84459ac06a..e61006f3437 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
@@ -848,6 +848,7 @@ namespace System.Net.Http.Functional.Tests
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
[MemberData(nameof(UseSocketsHttpHandler_WithIdFormat_MemberData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_HeadersAreInjectedOnRedirects(bool useSocketsHttpHandler, ActivityIdFormat idFormat)
{
Activity parent = new Activity("parent");
@@ -932,6 +933,7 @@ namespace System.Net.Http.Functional.Tests
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
[MemberData(nameof(SocketsHttpHandlerPropagators_WithIdFormat_MemberData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_CustomSocketsHttpHandlerPropagator_PropagatorIsUsed(DistributedContextPropagator propagator, ActivityIdFormat idFormat)
{
Activity parent = new Activity("parent");
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HPackTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HPackTest.cs
index c1a4cdb314c..b946c6d6fed 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HPackTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HPackTest.cs
@@ -32,6 +32,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(HeaderEncodingTestData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task HPack_HeaderEncoding(string headerName, string expectedValue, byte[] expectedEncoding)
{
await Http2LoopbackServer.CreateClientAndServerAsync(
@@ -68,10 +69,10 @@ namespace System.Net.Http.Functional.Tests
yield return new object[] { ":path", "/", new byte[] { 0x84 } };
// Indexed name, literal value.
- yield return new object[] { "content-type", "text/plain; charset=utf-8", new byte[] { 0x0F, 0x10, 0x19, 0x74, 0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x3B, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3D, 0x75, 0x74, 0x66, 0x2D, 0x38 } };
+ yield return new object[] { "content-type", "text/plain; charset=utf-8", "\u000f\u0010\u0019text/plain; charset=utf-8"u8.ToArray() };
// Literal name, literal value.
- yield return new object[] { LiteralHeaderName, LiteralHeaderValue, new byte[] { 0x00, 0x10, 0x78, 0x2D, 0x6C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6C, 0x2D, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0B, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x34, 0x35, 0x36 } };
+ yield return new object[] { LiteralHeaderName, LiteralHeaderValue, "\0\u0010x-literal-header\vtesting 456"u8.ToArray() };
}
}
}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs
index 0430fdfb7ec..56c7345946d 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs
@@ -26,6 +26,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task IncompleteResponseStream_ResponseDropped_CancelsRequestToServer()
{
if (UseQuicImplementationProvider == QuicImplementationProviders.Mock)
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 85d6ee9ca8e..d8def4049a7 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs
@@ -24,6 +24,7 @@ namespace System.Net.Http.Functional.Tests
private sealed class DerivedHttpHeaders : HttpHeaders { }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_RequestWithSimpleHeader_ResponseReferencesUnmodifiedRequestHeaders()
{
const string HeaderKey = "some-header-123", HeaderValue = "this is the expected header value";
@@ -48,6 +49,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "User-Agent is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_UserAgent_CorrectlyWritten()
{
string userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.18 Safari/537.36";
@@ -71,6 +73,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_LargeHeaders_CorrectlyWritten()
{
if (UseVersion == HttpVersion.Version30)
@@ -106,6 +109,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_DefaultHeaders_CorrectlyWritten()
{
const string Version = "2017-04-17";
@@ -167,6 +171,7 @@ namespace System.Net.Http.Functional.Tests
[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/69870", TestPlatforms.Android)]
public async Task SendAsync_SpecialHeaderKeyOrValue_Success(string key, string value, bool parsable)
{
if (PlatformDetection.IsBrowser && (key == "Content-Location" || key == "Date" || key == "Accept-CharSet"))
@@ -212,6 +217,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData("Content-Security-Policy", 4618)]
[InlineData("RandomCustomHeader", 12345)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_LargeHeader_Success(string headerName, int headerValueLength)
{
var rand = new Random(42);
@@ -236,6 +242,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_EmptyResponseHeader_Success()
{
IList<HttpHeaderData> headers = new HttpHeaderData[] {
@@ -267,6 +274,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_MissingExpires_ReturnNull()
{
await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
@@ -287,6 +295,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData("Thu, 01 Dec 1994 16:00:00 GMT", true)]
[InlineData("-1", false)]
[InlineData("0", false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_Expires_Success(string value, bool isValid)
{
await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
@@ -325,6 +334,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData("Accept-Encoding", "identity,gzip")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_RequestHeaderInResponse_Success(string name, string value)
{
await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
@@ -403,6 +413,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_WithZeroLengthHeaderName_Throws()
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -447,6 +458,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "Socket is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_CustomRequestEncodingSelector_CanSendNonAsciiHeaderValues()
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -502,6 +514,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[SkipOnPlatform(TestPlatforms.Browser, "Socket is not supported on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_CustomResponseEncodingSelector_CanReceiveNonAsciiHeaderValues()
{
await LoopbackServerFactory.CreateClientAndServerAsync(
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs
index d22e553f7a2..a0671010479 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs
@@ -70,6 +70,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_ClientPreface_Sent()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -84,6 +85,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_InitialSettings_SentAndAcked()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -116,6 +118,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_DataSentBeforeServerPreface_ProtocolError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -134,6 +137,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_NoResponseBody_Success()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -154,6 +158,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_ZeroLengthResponseBody_Success()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -212,6 +217,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_ServerSendsValidSettingsValues_Success()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -247,6 +253,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(SettingId.MaxFrameSize, 16383)]
[InlineData(SettingId.MaxFrameSize, 162777216)]
[InlineData(SettingId.InitialWindowSize, 0x80000000)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_ServerSendsInvalidSettingsValue_Error(SettingId settingId, uint value)
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -264,6 +271,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_StreamResetByServerBeforeHeadersSent_RequestFails()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -283,6 +291,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_StreamResetByServerAfterHeadersSent_RequestFails()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -305,6 +314,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_StreamResetByServerAfterPartialBodySent_RequestFails()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -329,6 +339,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_StreamRefused_RequestIsRetried()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -364,6 +375,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsync_StreamRefused_RequestIsRetried()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -404,6 +416,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses delays")]
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_SettingsFrameNotSentOnNewConnection_ClientApplies100StreamLimit()
{
const int DefaultMaxConcurrentStreams = 100;
@@ -455,6 +468,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses delays")]
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ServerDelaysSendingSettingsThenSetsLowerMaxConcurrentStreamsLimitThenIncreaseIt_ClientAppliesEachLimitChangeProperly()
{
const int DefaultMaxConcurrentStreams = 100;
@@ -515,6 +529,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses delays")]
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GetAsync_ServerSendSettingsWithoutMaxConcurrentStreams_ClientAppliesInfiniteLimit()
{
const int DefaultMaxConcurrentStreams = 100;
@@ -576,6 +591,7 @@ namespace System.Net.Http.Functional.Tests
// "If a DATA frame is received whose stream identifier field is 0x0, the recipient MUST
// respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR."
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task DataFrame_NoStream_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -602,6 +618,7 @@ namespace System.Net.Http.Functional.Tests
// "Receiving any frame other than HEADERS or PRIORITY on a stream in this state MUST
// be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR."
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task DataFrame_IdleStream_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -628,6 +645,7 @@ namespace System.Net.Http.Functional.Tests
// headers from the server on an idle stream. We fall back to treating this as a connection
// level error, as we do for other unexpected frames on idle streams.
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task HeadersFrame_IdleStream_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -695,6 +713,7 @@ namespace System.Net.Http.Functional.Tests
0, streamId);
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ResponseStreamFrames_ContinuationBeforeHeaders_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -715,6 +734,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ResponseStreamFrames_DataBeforeHeaders_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -735,6 +755,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ResponseStreamFrames_HeadersAfterHeadersWithoutEndHeaders_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -756,6 +777,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ResponseStreamFrames_HeadersAfterHeadersAndContinuationWithoutEndHeaders_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -778,6 +800,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ResponseStreamFrames_DataAfterHeadersWithoutEndHeaders_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -799,6 +822,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ResponseStreamFrames_DataAfterHeadersAndContinuationWithoutEndHeaders_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -824,6 +848,7 @@ namespace System.Net.Http.Functional.Tests
// "An endpoint MUST treat a GOAWAY frame with a stream identifier other than 0x0 as a
// connection error (Section 5.4.1) of type PROTOCOL_ERROR."
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_NonzeroStream_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -847,6 +872,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_NewRequest_NewConnection()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -878,6 +904,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_ServerDisconnect_AbortStreams()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -905,6 +932,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_RequestWithBody_ServerDisconnect_AbortStreamsAndThrowIOException()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -938,6 +966,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_UnprocessedStreamFirstRequestFinishedFirst_RequestRestarted()
{
// This test case is similar to GoAwayFrame_UnprocessedStreamFirstRequestWaitsUntilSecondFinishes_RequestRestarted
@@ -983,6 +1012,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_UnprocessedStreamFirstRequestWaitsUntilSecondFinishes_RequestRestarted()
{
using (await Watchdog.CreateAsync())
@@ -1025,6 +1055,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_RequestInFlight_Finished()
{
await Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
@@ -1070,6 +1101,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task DataFrame_TooLong_ConnectionError()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1092,6 +1124,7 @@ namespace System.Net.Http.Functional.Tests
[ConditionalTheory(nameof(SupportsAlpn))]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task CompletedResponse_FrameReceived_Ignored(bool sendDataFrame)
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1125,6 +1158,7 @@ namespace System.Net.Http.Functional.Tests
[ConditionalTheory(nameof(SupportsAlpn))]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task EmptyResponse_FrameReceived_Ignored(bool sendDataFrame)
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1153,6 +1187,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task CompletedResponse_WindowUpdateFrameReceived_Success()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1223,6 +1258,7 @@ namespace System.Net.Http.Functional.Tests
[ConditionalTheory(nameof(SupportsAlpn))]
[MemberData(nameof(ValidAndInvalidProtocolErrorsAndBool))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ResetResponseStream_FrameReceived_Ignored(ProtocolErrors error, bool dataFrame)
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1280,6 +1316,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_NoPendingStreams_ConnectionClosed()
{
using (await Watchdog.CreateAsync())
@@ -1301,6 +1338,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_AllPendingStreamsValid_RequestsSucceedAndConnectionClosed()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1365,6 +1403,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task GoAwayFrame_AbortAllPendingStreams_StreamFailWithExpectedException()
{
using (await Watchdog.CreateAsync())
@@ -1473,6 +1512,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_FlowControl_ClientDoesNotExceedWindows()
{
const int ContentSize = 100_000;
@@ -1565,6 +1605,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_InitialWindowSize_ClientDoesNotExceedWindows()
{
const int ContentSize = DefaultInitialWindowSize + 1000;
@@ -1684,6 +1725,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(DefaultInitialWindowSize + 32 * 1024)]
[InlineData(DefaultInitialWindowSize + 64 * 1024)]
[InlineData(DefaultInitialWindowSize + 96 * 1024)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_SendOverStreamWindowSizeWithoutExplicitFlush_ClientSendsUpToFullWindowSize(int contentSize)
{
var content = new ByteArrayContent(new byte[contentSize]);
@@ -1737,6 +1779,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(DefaultInitialWindowSize + 32 * 1024)]
[InlineData(DefaultInitialWindowSize + 64 * 1024)]
[InlineData(DefaultInitialWindowSize + 96 * 1024)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_SendOverConnectionWindowSizeWithoutExplicitFlush_ClientSendsUpToFullWindowSize(int contentSize)
{
var content = new ByteArrayContent(new byte[contentSize]);
@@ -1785,6 +1828,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_MaxConcurrentStreams_LimitEnforced()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1853,6 +1897,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_WaitingForStream_Cancellation()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1902,6 +1947,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_WaitingOnWindowCredit_Cancellation()
{
// The goal of this test is to get the client into the state where it has sent the headers,
@@ -1949,6 +1995,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_PendingSend_Cancellation()
{
// The goal of this test is to get the client into the state where it is sending content,
@@ -1987,6 +2034,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[InlineData(false)]
[InlineData(true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_PendingSend_SendsReset(bool waitForData)
{
var cts = new CancellationTokenSource();
@@ -2048,7 +2096,7 @@ namespace System.Net.Http.Functional.Tests
}
catch (System.OperationCanceledException) { };
Assert.Null(frame); // Make sure we do not get any frames after getting Rst.
- await connection.SendResponseBodyAsync(streamId, Encoding.ASCII.GetBytes("final"), isFinal: true);
+ await connection.SendResponseBodyAsync(streamId, "final"u8.ToArray(), isFinal: true);
await connection.WaitForConnectionShutdownAsync();
});
}
@@ -2056,6 +2104,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_PendingReceive_SendsReset(bool doRead)
{
var cts = new CancellationTokenSource();
@@ -2125,6 +2174,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2Connection_Should_Wrap_HttpContent_InvalidOperationException()
{
// test for https://github.com/dotnet/runtime/issues/30187
@@ -2152,6 +2202,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2Connection_Should_Not_Wrap_HttpContent_CustomException()
{
// Assert existing HttpConnection behaviour in which custom HttpContent exception types are surfaced as-is
@@ -2184,6 +2235,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncExpect100Continue_SendRequest_Ok(bool send100Continue)
{
await Http2LoopbackServer.CreateClientAndServerAsync(async url =>
@@ -2213,12 +2265,13 @@ namespace System.Net.Http.Functional.Tests
}
await connection.ReadBodyAsync();
await connection.SendResponseHeadersAsync(streamId, endStream: false, HttpStatusCode.OK);
- await connection.SendResponseBodyAsync(streamId, Encoding.ASCII.GetBytes("OK"));
+ await connection.SendResponseBodyAsync(streamId, "OK"u8.ToArray());
await connection.ShutdownIgnoringErrorsAsync(streamId);
});
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncExpect100Continue_NonSuccessResponse_RequestBodyNotSent()
{
string responseContent = "no no!";
@@ -2350,9 +2403,10 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_ClientSendsEndStream_Success()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2410,9 +2464,10 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_ServerSendsEndStream_Success()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2470,9 +2525,10 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_RequestContentException_ResetsStream()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2527,9 +2583,10 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_RequestContentExceptionAfterResponseEndReceivedButBeforeConsumed_ResetsStreamAndThrowsOnResponseStreamRead()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2591,9 +2648,10 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_CancelledBeforeResponseHeadersReceived_ResetsStream()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2647,9 +2705,10 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_ServerResetsStream_Throws()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2708,9 +2767,10 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_DisposeResponseBodyBeforeEnd_ResetsStreamAndThrowsOnRequestStreamWriteAndResponseStreamRead()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2775,9 +2835,10 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_DisposeResponseBodyAfterEndReceivedButBeforeConsumed_ResetsStreamAndThrowsOnRequestStreamWriteAndResponseStreamRead()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2848,9 +2909,10 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Uses Task.Delay")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_FinishRequestBodyAndDisposeResponseBodyAfterEndReceivedButBeforeConsumed_DoesNotResetStream()
{
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2913,6 +2975,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncDuplex_ServerCompletesResponseBodyThenResetsStreamWithNoError_SuccessAndRequestBodyCancelled()
{
// Per section 8.1 of the RFC:
@@ -2920,7 +2983,7 @@ namespace System.Net.Http.Functional.Tests
// We should stop sending the request body, but treat the request as successful and
// return the completed response body to the user.
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -2982,6 +3045,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PostAsyncNonDuplex_ServerCompletesResponseBodyThenResetsStreamWithNoError_SuccessAndRequestBodyCancelled()
{
// Per section 8.1 of the RFC:
@@ -2989,7 +3053,7 @@ namespace System.Net.Http.Functional.Tests
// We should stop sending the request body, but treat the request as successful and
// return the completed response body to the user.
- byte[] contentBytes = Encoding.UTF8.GetBytes("Hello world");
+ byte[] contentBytes = "Hello world"u8.ToArray();
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
{
@@ -3034,6 +3098,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(true, HttpStatusCode.OK)]
[InlineData(false, HttpStatusCode.OK)]
[OuterLoop("Uses Task.Delay")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_ConcurentSendReceive_Ok(bool shouldWaitForRequestBody, HttpStatusCode responseCode)
{
string requestContent = new string('*', 300);
@@ -3101,6 +3166,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[OuterLoop("Uses Task.Delay")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_ConcurentSendReceive_Fail()
{
TaskCompletionSource<bool> tsc = new TaskCompletionSource<bool>();
@@ -3173,6 +3239,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[OuterLoop("Waits for seconds for events that shouldn't happen")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_StreamContentRequestBody_WaitsForRequestBodyToComplete()
{
var waitToSendRequestBody = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -3222,6 +3289,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_ProtocolMismatch_Throws()
{
HttpClientHandler handler = CreateHttpClientHandler();
@@ -3248,7 +3316,7 @@ namespace System.Net.Http.Functional.Tests
await sslStream.AuthenticateAsServerAsync(options, CancellationToken.None).ConfigureAwait(false);
// Send back HTTP/1.1 response
- await sslStream.WriteAsync(Encoding.ASCII.GetBytes("HTTP/1.1 400 Unrecognized request\r\n\r\n"), CancellationToken.None);
+ await sslStream.WriteAsync("HTTP/1.1 400 Unrecognized request\r\n\r\n"u8.ToArray(), CancellationToken.None);
});
Exception e = await Assert.ThrowsAsync<HttpRequestException>(() => requestTask);
@@ -3258,6 +3326,7 @@ namespace System.Net.Http.Functional.Tests
// rfc7540 8.1.2.3.
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_MultipleStatusHeaders_Throws()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -3275,6 +3344,7 @@ namespace System.Net.Http.Functional.Tests
// rfc7540 8.1.2.3.
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_StatusHeaderNotFirst_Throws()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -3293,6 +3363,7 @@ namespace System.Net.Http.Functional.Tests
// rfc7540 8.1.2.3.
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_TrailigPseudo_Throw()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -3304,7 +3375,7 @@ namespace System.Net.Http.Functional.Tests
Http2LoopbackConnection connection = await server.EstablishConnectionAsync();
int streamId = await connection.ReadRequestHeaderAsync();
await connection.SendDefaultResponseHeadersAsync(streamId);
- await connection.SendResponseDataAsync(streamId, Encoding.ASCII.GetBytes("hello"), endStream: false);
+ await connection.SendResponseDataAsync(streamId, "hello"u8.ToArray(), endStream: false);
await connection.SendResponseHeadersAsync(streamId, endStream : true, isTrailingHeader : true, headers: headers);
await Assert.ThrowsAsync<HttpRequestException>(() => sendTask);
@@ -3315,6 +3386,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2SendAsync_LargeHeaders_CorrectlyWritten(int continuationCount)
{
// Intentionally larger than 2x16K in total because that's the limit that will trigger a CONTINUATION frame in HTTP2.
@@ -3358,6 +3430,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task InboundWindowSize_Exceeded_Throw()
{
var semaphore = new SemaphoreSlim(0);
@@ -3441,6 +3514,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[OuterLoop("Uses Task.Delay")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SocketSendQueueFull_RequestCanceled_ThrowsOperationCanceled()
{
TaskCompletionSource clientComplete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -3482,6 +3556,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task MaxResponseHeadersLength_Exact_Success(bool huffmanEncode)
{
await Http2LoopbackServer.CreateClientAndServerAsync(
@@ -3512,6 +3587,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task MaxResponseHeadersLength_Exceeded_Throws(bool huffmanEncode)
{
await Http2LoopbackServer.CreateClientAndServerAsync(
@@ -3541,6 +3617,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task MaxResponseHeadersLength_Malicious_Throws()
{
await Http2LoopbackServer.CreateClientAndServerAsync(
@@ -3568,6 +3645,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task DynamicTableSizeUpdate_Exceeds_Settings_Throws()
{
await Http2LoopbackServer.CreateClientAndServerAsync(
@@ -3593,6 +3671,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task DynamicTable_Reuse_Concat()
{
await Http2LoopbackServer.CreateClientAndServerAsync(
@@ -3623,6 +3702,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task DynamicTable_Resize_Success()
{
await Http2LoopbackServer.CreateClientAndServerAsync(
@@ -3701,6 +3781,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(DynamicTable_Data))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task DynamicTable_Receipt_Success(IEnumerable<HttpHeaderData> headers)
{
await Http2LoopbackServer.CreateClientAndServerAsync(
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Url.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Url.cs
new file mode 100644
index 00000000000..b180fbb8aa0
--- /dev/null
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Url.cs
@@ -0,0 +1,46 @@
+// 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.IO;
+using System.Net.Test.Common;
+using System.Threading.Tasks;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public class HttpClientHandlerTest_Url: HttpClientHandlerTestBase
+ {
+ public HttpClientHandlerTest_Url(ITestOutputHelper output) : base(output) { }
+
+ [Theory]
+ [InlineData("/test%20", "/test%20")]
+ [InlineData("/test ", "/test")]
+ [InlineData("/test%20?a=1", "/test%20?a=1")]
+ [InlineData("/test ?a=1", "/test%20?a=1")]
+ public async Task TrimmingTrailingWhiteSpace(string requestPath, string expectedServerPath)
+ {
+ string serverPath = null;
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ client.BaseAddress = url;
+
+ var getTask = client.GetAsync(requestPath);
+
+ var response = await server.HandleRequestAsync();
+ serverPath = response.Path;
+
+ await getTask;
+ }
+ });
+
+ Assert.Equal(expectedServerPath, serverPath);
+ }
+ }
+}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs
index 581a8bb5298..65030243c2f 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs
@@ -68,7 +68,8 @@ namespace System.Net.Http.Functional.Tests
protected static SocketsHttpHandler GetUnderlyingSocketsHttpHandler(HttpClientHandler handler)
{
- FieldInfo field = typeof(HttpClientHandler).GetField("_underlyingHandler", BindingFlags.Instance | BindingFlags.NonPublic);
+ var fieldName = PlatformDetection.IsMobile ? "_socketHandler" : "_underlyingHandler";
+ FieldInfo field = typeof(HttpClientHandler).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
return (SocketsHttpHandler)field?.GetValue(handler);
}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs
index da0b8a2edd1..00589f8f09c 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs
@@ -921,6 +921,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(HttpCompletionOption.ResponseContentRead)]
[InlineData(HttpCompletionOption.ResponseHeadersRead)]
[SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send is not supported on Android")]
public async Task Send_SingleThread_Loopback_Succeeds(HttpCompletionOption completionOption)
{
string content = "Test content";
@@ -975,6 +976,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[OuterLoop]
[SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send is not supported on Android")]
public async Task Send_CancelledRequestContent_Throws()
{
CancellationTokenSource cts = new CancellationTokenSource();
@@ -1026,6 +1028,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[OuterLoop]
[ActiveIssue("https://github.com/dotnet/runtime/issues/39056")]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send is not supported on Android")]
public async Task Send_TimeoutRequestContent_Throws()
{
await LoopbackServer.CreateClientAndServerAsync(
@@ -1074,6 +1077,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[OuterLoop]
[SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send is not supported on Android")]
public async Task Send_CancelledResponseContent_Throws()
{
string content = "Test content";
@@ -1129,6 +1133,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
[OuterLoop]
[SkipOnPlatform(TestPlatforms.Browser, "Synchronous Send is not supported on Browser")]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send is not supported on Android")]
public async Task Send_TimeoutResponseContent_Throws()
{
const string Content = "Test content";
@@ -1183,6 +1188,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(VersionSelectionMemberData))]
[SkipOnPlatform(TestPlatforms.Browser, "Version is ignored on Browser")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task SendAsync_CorrectVersionSelected_LoopbackServer(Version requestVersion, HttpVersionPolicy versionPolicy, Version serverVersion, bool useSsl, object expectedResult)
{
await HttpAgnosticLoopbackServer.CreateClientAndServerAsync(
@@ -1461,6 +1467,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "The Send method is not implemented on mobile platforms")]
public void Send_NullRequest_ThrowsException()
{
using var client = new CustomHttpClient();
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs
index 4ddd6633a2e..276733d9f37 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpContentTest.cs
@@ -366,7 +366,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(false)]
public async Task LoadIntoBufferAsync_CallOnMockContentWithLessLengthThanContentLengthHeader_BufferedStreamLengthMatchesActualLengthNotContentLengthHeaderValue(bool readStreamAsync)
{
- byte[] data = Encoding.UTF8.GetBytes("16 bytes of data");
+ byte[] data = "16 bytes of data"u8.ToArray();
var content = new MockContent(data);
content.Headers.ContentLength = 32; // Set the Content-Length header to a value > actual data length.
Assert.Equal(32, content.Headers.ContentLength);
@@ -961,15 +961,7 @@ namespace System.Net.Http.Functional.Tests
public MockContent(byte[] mockData, MockOptions options)
{
_options = options;
-
- if (mockData == null)
- {
- _mockData = Encoding.UTF8.GetBytes("data");
- }
- else
- {
- _mockData = mockData;
- }
+ _mockData = mockData ?? "data"u8.ToArray();
}
public byte[] GetMockData()
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MultipartContentTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MultipartContentTest.cs
index 1ac9ae91d01..457085ccb3d 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/MultipartContentTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MultipartContentTest.cs
@@ -150,7 +150,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(MultipartContentToStringMode.CopyToAsync, true)]
public async Task ReadAsStringAsync_OneSubContentWithHeaders_MatchesExpected(MultipartContentToStringMode mode, bool async)
{
- var subContent = new ByteArrayContent(Encoding.UTF8.GetBytes("This is a ByteArrayContent"));
+ var subContent = new ByteArrayContent("This is a ByteArrayContent"u8.ToArray());
subContent.Headers.Add("someHeaderName", "andSomeHeaderValue");
subContent.Headers.Add("someOtherHeaderName", new[] { "withNotOne", "ButTwoValues" });
subContent.Headers.Add("oneMoreHeader", new[] { "withNotOne", "AndNotTwo", "butThreeValues" });
@@ -177,7 +177,7 @@ namespace System.Net.Http.Functional.Tests
public async Task ReadAsStringAsync_TwoSubContents_MatchesExpected(MultipartContentToStringMode mode, bool async)
{
var mc = new MultipartContent("someSubtype", "theBoundary");
- mc.Add(new ByteArrayContent(Encoding.UTF8.GetBytes("This is a ByteArrayContent")));
+ mc.Add(new ByteArrayContent("This is a ByteArrayContent"u8.ToArray()));
mc.Add(new StringContent("This is a StringContent"));
Assert.Equal(
@@ -274,9 +274,9 @@ namespace System.Net.Http.Functional.Tests
var mc = new MultipartContent();
if (nestedContent)
{
- mc.Add(new ByteArrayContent(Encoding.UTF8.GetBytes("This is a ByteArrayContent")));
+ mc.Add(new ByteArrayContent("This is a ByteArrayContent"u8.ToArray()));
mc.Add(new StringContent("This is a StringContent"));
- mc.Add(new ByteArrayContent(Encoding.UTF8.GetBytes("Another ByteArrayContent :-)")));
+ mc.Add(new ByteArrayContent("Another ByteArrayContent :-)"u8.ToArray()));
}
var memStream = new MemoryStream();
@@ -399,7 +399,7 @@ namespace System.Net.Http.Functional.Tests
stringContent.Headers.Add("StringContent", "foo");
mc.Add(stringContent);
- var byteArrayContent = new ByteArrayContent(Encoding.ASCII.GetBytes("foo"));
+ var byteArrayContent = new ByteArrayContent("foo"u8.ToArray());
byteArrayContent.Headers.Add("ByteArrayContent", "foo");
mc.Add(byteArrayContent);
@@ -442,19 +442,19 @@ namespace System.Net.Http.Functional.Tests
var mc = new MultipartContent("subtype", "fooBoundary");
var stringContent = new StringContent("bar1");
- stringContent.Headers.Add("latin1", "\uD83D\uDE00");
+ stringContent.Headers.Add("latin1", "\U0001F600");
mc.Add(stringContent);
- var byteArrayContent = new ByteArrayContent(Encoding.ASCII.GetBytes("bar2"));
- byteArrayContent.Headers.Add("utf8", "\uD83D\uDE00");
+ var byteArrayContent = new ByteArrayContent("bar2"u8.ToArray());
+ byteArrayContent.Headers.Add("utf8", "\U0001F600");
mc.Add(byteArrayContent);
- byteArrayContent = new ByteArrayContent(Encoding.ASCII.GetBytes("bar3"));
- byteArrayContent.Headers.Add("ascii", "\uD83D\uDE00");
+ byteArrayContent = new ByteArrayContent("bar3"u8.ToArray());
+ byteArrayContent.Headers.Add("ascii", "\U0001F600");
mc.Add(byteArrayContent);
- byteArrayContent = new ByteArrayContent(Encoding.ASCII.GetBytes("bar4"));
- byteArrayContent.Headers.Add("default", "\uD83D\uDE00");
+ byteArrayContent = new ByteArrayContent("bar4"u8.ToArray());
+ byteArrayContent.Headers.Add("default", "\U0001F600");
mc.Add(byteArrayContent);
mc.HeaderEncodingSelector = (name, _) => name switch
@@ -476,28 +476,28 @@ namespace System.Net.Http.Functional.Tests
}
byte[] expected = Concat(
- Encoding.Latin1.GetBytes("--fooBoundary\r\n"),
- Encoding.Latin1.GetBytes("Content-Type: text/plain; charset=utf-8\r\n"),
- Encoding.Latin1.GetBytes("latin1: "),
- Encoding.Latin1.GetBytes("\uD83D\uDE00"),
- Encoding.Latin1.GetBytes("\r\n\r\n"),
- Encoding.Latin1.GetBytes("bar1"),
- Encoding.Latin1.GetBytes("\r\n--fooBoundary\r\n"),
- Encoding.Latin1.GetBytes("utf8: "),
- Encoding.UTF8.GetBytes("\uD83D\uDE00"),
- Encoding.Latin1.GetBytes("\r\n\r\n"),
- Encoding.Latin1.GetBytes("bar2"),
- Encoding.Latin1.GetBytes("\r\n--fooBoundary\r\n"),
- Encoding.Latin1.GetBytes("ascii: "),
- Encoding.ASCII.GetBytes("\uD83D\uDE00"),
- Encoding.Latin1.GetBytes("\r\n\r\n"),
- Encoding.Latin1.GetBytes("bar3"),
- Encoding.Latin1.GetBytes("\r\n--fooBoundary\r\n"),
- Encoding.Latin1.GetBytes("default: "),
- Encoding.Latin1.GetBytes("\uD83D\uDE00"),
- Encoding.Latin1.GetBytes("\r\n\r\n"),
- Encoding.Latin1.GetBytes("bar4"),
- Encoding.Latin1.GetBytes("\r\n--fooBoundary--\r\n"));
+ "--fooBoundary\r\n"u8.ToArray(),
+ "Content-Type: text/plain; charset=utf-8\r\n"u8.ToArray(),
+ "latin1: "u8.ToArray(),
+ Encoding.Latin1.GetBytes("\U0001F600"),
+ "\r\n\r\n"u8.ToArray(),
+ "bar1"u8.ToArray(),
+ "\r\n--fooBoundary\r\n"u8.ToArray(),
+ "utf8: "u8.ToArray(),
+ "\U0001F600"u8.ToArray(),
+ "\r\n\r\n"u8.ToArray(),
+ "bar2"u8.ToArray(),
+ "\r\n--fooBoundary\r\n"u8.ToArray(),
+ "ascii: "u8.ToArray(),
+ Encoding.ASCII.GetBytes("\U0001F600"),
+ "\r\n\r\n"u8.ToArray(),
+ "bar3"u8.ToArray(),
+ "\r\n--fooBoundary\r\n"u8.ToArray(),
+ "default: "u8.ToArray(),
+ Encoding.Latin1.GetBytes("\U0001F600"),
+ "\r\n\r\n"u8.ToArray(),
+ "bar4"u8.ToArray(),
+ "\r\n--fooBoundary--\r\n"u8.ToArray());
Assert.Equal(expected, ms.ToArray());
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamConformanceTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamConformanceTests.cs
index f7f28da5d19..200d0b1e9e3 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamConformanceTests.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamConformanceTests.cs
@@ -54,9 +54,9 @@ namespace System.Net.Http.Functional.Tests
// One chunk for the whole response body
await responseStream.WriteAsync(Encoding.ASCII.GetBytes($"{bodyData.Length:X}\r\n"));
await responseStream.WriteAsync(bodyData);
- await responseStream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
+ await responseStream.WriteAsync("\r\n"u8.ToArray());
}
- await responseStream.WriteAsync(Encoding.ASCII.GetBytes("0\r\n\r\n"));
+ await responseStream.WriteAsync("0\r\n\r\n"u8.ToArray());
}
}
@@ -70,9 +70,9 @@ namespace System.Net.Http.Functional.Tests
// One chunk per byte of the response body
await responseStream.WriteAsync(Encoding.ASCII.GetBytes($"1\r\n"));
await responseStream.WriteAsync(bodyData.AsMemory(i, 1));
- await responseStream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
+ await responseStream.WriteAsync("\r\n"u8.ToArray());
}
- await responseStream.WriteAsync(Encoding.ASCII.GetBytes("0\r\n\r\n"));
+ await responseStream.WriteAsync("0\r\n\r\n"u8.ToArray());
}
}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamZeroByteReadTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamZeroByteReadTests.cs
index 29a6b4cc99b..0d0ca2b4af1 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamZeroByteReadTests.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/ResponseStreamZeroByteReadTests.cs
@@ -48,7 +48,7 @@ namespace System.Net.Http.Functional.Tests
{
await stream.WriteAsync(Encoding.ASCII.GetBytes($"{data.Length:X}\r\n"));
await stream.WriteAsync(data);
- await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
+ await stream.WriteAsync("\r\n"u8.ToArray());
}
}
@@ -62,12 +62,11 @@ namespace System.Net.Http.Functional.Tests
{
await stream.WriteAsync(Encoding.ASCII.GetBytes($"1\r\n"));
await stream.WriteAsync(data.AsMemory(i, 1));
- await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
+ await stream.WriteAsync("\r\n"u8.ToArray());
}
}
}
- [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
public abstract class Http1ResponseStreamZeroByteReadTestBase
{
protected abstract string GetResponseHeaders();
@@ -82,6 +81,8 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(ZeroByteRead_IssuesZeroByteReadOnUnderlyingStream_MemberData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
+ [SkipOnPlatform(TestPlatforms.Browser, "ConnectCallback is not supported on Browser")]
public async Task ZeroByteRead_IssuesZeroByteReadOnUnderlyingStream(StreamConformanceTests.ReadWriteMode readMode, bool useSsl)
{
(Stream httpConnection, Stream server) = ConnectedStreams.CreateBidirectional(4096, int.MaxValue);
@@ -136,7 +137,7 @@ namespace System.Net.Http.Functional.Tests
await sawZeroByteRead.Task.WaitAsync(TimeSpan.FromSeconds(10));
Assert.False(zeroByteReadTask.IsCompleted);
- byte[] data = Encoding.UTF8.GetBytes("Hello");
+ byte[] data = "Hello"u8.ToArray();
await WriteAsync(server, data);
await server.FlushAsync();
@@ -238,6 +239,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ZeroByteRead_BlocksUntilDataIsAvailable(bool async)
{
var zeroByteReadIssued = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs
index 0fdd4c97771..96e3b53cdcb 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs
@@ -110,6 +110,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection(bool useSsl)
{
if (UseVersion == HttpVersion.Version30)
@@ -263,6 +264,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Incurs significant delay")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Expect100Continue_WaitsExpectedPeriodOfTimeBeforeSendingContent()
{
await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2FlowControl.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2FlowControl.cs
index 6b0e8850549..4cee5beec97 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2FlowControl.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2FlowControl.cs
@@ -30,6 +30,7 @@ namespace System.Net.Http.Functional.Tests
private static Http2Options NoAutoPingResponseHttp2Options => new Http2Options() { EnableTransparentPingResponse = false };
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task InitialHttp2StreamWindowSize_SentInSettingsFrame()
{
const int WindowSize = 123456;
@@ -49,6 +50,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(0)] // Invalid PING payload
[InlineData(1)] // Unexpected PING response
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public Task BadRttPingResponse_RequestShouldFail(int mode)
{
return Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
@@ -84,6 +86,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task HighBandwidthDelayProduct_ClientStreamReceiveWindowWindowScalesUp()
{
int maxCredit = await TestClientWindowScalingAsync(
@@ -98,6 +101,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public void DisableDynamicWindowScaling_HighBandwidthDelayProduct_WindowRemainsConstant()
{
static async Task RunTest()
@@ -118,6 +122,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public void MaxStreamWindowSize_WhenSet_WindowDoesNotScaleAboveMaximum()
{
const int MaxWindow = 654321;
@@ -141,6 +146,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public void StreamWindowScaleThresholdMultiplier_HighValue_WindowScalesSlower()
{
static async Task RunTest()
@@ -162,6 +168,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public void StreamWindowScaleThresholdMultiplier_LowValue_WindowScalesFaster()
{
static async Task RunTest()
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2KeepAlivePing.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2KeepAlivePing.cs
index d760e8e9c53..57ab51d3fa1 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2KeepAlivePing.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Http2KeepAlivePing.cs
@@ -40,6 +40,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task KeepAlivePingDelay_Infinite_NoKeepAlivePingIsSent()
{
await Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
@@ -100,6 +101,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(HttpKeepAlivePingPolicy.Always)]
[InlineData(HttpKeepAlivePingPolicy.WithActiveRequests)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task KeepAliveConfigured_KeepAlivePingsAreSentAccordingToPolicy(HttpKeepAlivePingPolicy policy)
{
await Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
@@ -179,6 +181,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task KeepAliveConfigured_NoPingResponseDuringActiveStream_RequestShouldFail()
{
await Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
@@ -229,6 +232,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop("Runs long")]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task HttpKeepAlivePingPolicy_Always_NoPingResponseBetweenStreams_SecondRequestShouldFail()
{
await Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
index f29c5e70b93..55ecefbe947 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
@@ -591,7 +591,7 @@ namespace System.Net.Http.Functional.Tests
{
public SocketsHttpHandler_TrailingHeaders_Test(ITestOutputHelper output) : base(output) { }
- protected static byte[] DataBytes = Encoding.ASCII.GetBytes("data");
+ protected static byte[] DataBytes = "data"u8.ToArray();
protected static readonly IList<HttpHeaderData> TrailingHeaders = new HttpHeaderData[] {
new HttpHeaderData("MyCoolTrailerHeader", "amazingtrailer"),
@@ -891,6 +891,7 @@ namespace System.Net.Http.Functional.Tests
protected override Version UseVersion => HttpVersion.Version20;
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_NoTrailingHeaders_EmptyCollection()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -919,6 +920,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(false)]
[InlineData(true)]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_MissingTrailer_TrailingHeadersAccepted(bool responseHasContentLength)
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -955,6 +957,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_TrailerHeaders_TrailingPseudoHeadersThrow()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -979,6 +982,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(false)]
[InlineData(true)]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsyncResponseHeadersReadOption_TrailingHeaders_Available(bool responseHasContentLength)
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1030,6 +1034,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_TrailerHeaders_TrailingHeaderNoBody()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1054,6 +1059,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2GetAsync_TrailingHeaders_NoData_EmptyResponseObserved()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
@@ -1301,26 +1307,26 @@ namespace System.Net.Http.Functional.Tests
// Validate writing APIs on clientStream
clientStream.WriteByte((byte)'!');
- clientStream.Write(new byte[] { (byte)'\r', (byte)'\n' }, 0, 2);
+ clientStream.Write("\r\n"u8.ToArray(), 0, 2);
Assert.Equal("!", await connection.ReadLineAsync());
- clientStream.Write(new Span<byte>(new byte[] { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'\r', (byte)'\n' }));
+ clientStream.Write("hello\r\n"u8);
Assert.Equal("hello", await connection.ReadLineAsync());
- await clientStream.WriteAsync(new byte[] { (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'\r', (byte)'\n' }, 0, 7);
+ await clientStream.WriteAsync("world\r\n"u8.ToArray(), 0, 7);
Assert.Equal("world", await connection.ReadLineAsync());
- await clientStream.WriteAsync(new Memory<byte>(new byte[] { (byte)'a', (byte)'n', (byte)'d', (byte)'\r', (byte)'\n' }, 0, 5));
+ await clientStream.WriteAsync(new Memory<byte>("and\r\n"u8.ToArray(), 0, 5));
Assert.Equal("and", await connection.ReadLineAsync());
- await Task.Factory.FromAsync(clientStream.BeginWrite, clientStream.EndWrite, new byte[] { (byte)'b', (byte)'e', (byte)'y', (byte)'o', (byte)'n', (byte)'d', (byte)'\r', (byte)'\n' }, 0, 8, null);
+ await Task.Factory.FromAsync(clientStream.BeginWrite, clientStream.EndWrite, "beyond\r\n"u8.ToArray(), 0, 8, null);
Assert.Equal("beyond", await connection.ReadLineAsync());
clientStream.Flush();
await clientStream.FlushAsync();
// Validate reading APIs on clientStream
- await connection.Stream.WriteAsync(Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyz"));
+ await connection.Stream.WriteAsync("abcdefghijklmnopqrstuvwxyz"u8.ToArray());
var buffer = new byte[1];
Assert.Equal('a', clientStream.ReadByte());
@@ -1533,6 +1539,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData("PooledConnectionLifetime")]
[InlineData("PooledConnectionIdleTimeout")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_SmallConnectionTimeout_SubsequentRequestUsesDifferentConnection(string timeoutPropertyName)
{
await Http2LoopbackServerFactory.CreateServerAsync(async (server, url) =>
@@ -1619,6 +1626,7 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop]
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public void HandlerDroppedWithoutDisposal_NotKeptAlive()
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -2216,6 +2224,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_MultipleConnectionsEnabled_ManyRequestsEnqueuedSimultaneously_SufficientConnectionsCreated()
{
// This is equal to Http2Connection.InitialMaxConcurrentStreams, which is the limit we impose before we have received the peer's initial SETTINGS frame.
@@ -2309,6 +2318,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(nameof(SupportsAlpn))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_MultipleConnectionsEnabled_OpenAndCloseMultipleConnections_Success()
{
const int MaxConcurrentStreams = 2;
@@ -2368,6 +2378,7 @@ namespace System.Net.Http.Functional.Tests
[ConditionalFact(nameof(SupportsAlpn))]
[OuterLoop("Incurs long delay")]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task Http2_MultipleConnectionsEnabled_IdleConnectionTimeoutExpired_ConnectionRemovedAndNewCreated()
{
const int MaxConcurrentStreams = 2;
@@ -2532,6 +2543,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(true, true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_ContextHasCorrectProperties_Success(bool syncRequest, bool syncCallback)
{
if (syncRequest && UseVersion > HttpVersion.Version11)
@@ -2540,6 +2552,12 @@ namespace System.Net.Http.Functional.Tests
return;
}
+ if (syncRequest && PlatformDetection.IsMobile)
+ {
+ // Sync requests are not supported on mobile platforms
+ return;
+ }
+
await LoopbackServerFactory.CreateClientAndServerAsync(
async uri =>
{
@@ -2585,6 +2603,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_BindLocalAddress_Success(bool useSsl)
{
GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl };
@@ -2619,6 +2638,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_UseMemoryBuffer_Success(bool useSsl)
{
(Stream clientStream, Stream serverStream) = ConnectedStreams.CreateBidirectional();
@@ -2657,6 +2677,7 @@ namespace System.Net.Http.Functional.Tests
[ActiveIssue("https://github.com/dotnet/runtime/issues/44183", TestPlatforms.Windows)]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_UseUnixDomainSocket_Success(bool useSsl)
{
GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl };
@@ -2706,12 +2727,13 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_ConnectionPrefix_Success(bool useSsl)
{
GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl };
- byte[] RequestPrefix = Encoding.UTF8.GetBytes("request prefix\r\n");
- byte[] ResponsePrefix = Encoding.UTF8.GetBytes("response prefix\r\n");
+ byte[] RequestPrefix = "request prefix\r\n"u8.ToArray();
+ byte[] ResponsePrefix = "response prefix\r\n"u8.ToArray();
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
@@ -2835,6 +2857,7 @@ namespace System.Net.Http.Functional.Tests
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_SslStream_OK(bool useSslStream)
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -2883,6 +2906,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_DerivedSslStream_OK()
{
await LoopbackServerFactory.CreateClientAndServerAsync(
@@ -2927,6 +2951,7 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ConnectCallback_NoAlpn_OK()
{
// Create HTTP 1.1 loopback. Http2 should downgrade
@@ -3088,6 +3113,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(PlaintextStreamFilter_ContextHasCorrectProperties_Success_MemberData))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send is not supported on Android")]
public async Task PlaintextStreamFilter_ContextHasCorrectProperties_Success(bool useSsl, bool syncRequest, bool syncCallback)
{
if (syncRequest && UseVersion > HttpVersion.Version11)
@@ -3136,6 +3162,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PlaintextStreamFilter_SimpleDelegatingStream_Success(bool useSsl)
{
GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl };
@@ -3174,10 +3201,11 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PlaintextStreamFilter_ConnectionPrefix_Success(bool useSsl)
{
- byte[] RequestPrefix = Encoding.UTF8.GetBytes("request prefix\r\n");
- byte[] ResponsePrefix = Encoding.UTF8.GetBytes("response prefix\r\n");
+ byte[] RequestPrefix = "request prefix\r\n"u8.ToArray();
+ byte[] ResponsePrefix = "response prefix\r\n"u8.ToArray();
using var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
@@ -3254,6 +3282,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PlaintextStreamFilter_ExceptionDuringCallback_ThrowsHttpRequestExceptionWithInnerException(bool useSsl)
{
Exception e = new Exception("hello!");
@@ -3295,6 +3324,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PlaintextStreamFilter_ReturnsNull_ThrowsHttpRequestException(bool useSsl)
{
GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl };
@@ -3339,6 +3369,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PlaintextStreamFilter_CustomStream_Success(bool useSsl)
{
GenericLoopbackOptions options = new GenericLoopbackOptions() { UseSsl = useSsl };
@@ -3355,7 +3386,7 @@ namespace System.Net.Http.Functional.Tests
context.PlaintextStream.Dispose();
MemoryStream memoryStream = new MemoryStream();
- memoryStream.Write(Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"));
+ memoryStream.Write("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"u8);
memoryStream.Seek(0, SeekOrigin.Begin);
DelegateStream newStream = new DelegateStream(
@@ -3386,6 +3417,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[InlineData(false)]
[InlineData(true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task PlaintextStreamFilter_Logging_Success(bool useSsl)
{
bool log = int.TryParse(Environment.GetEnvironmentVariable("DOTNET_TEST_SOCKETSHTTPHANDLERLOG"), out int value) && value == 1;
@@ -3703,6 +3735,7 @@ namespace System.Net.Http.Functional.Tests
[InlineData(1, 0)]
[InlineData(1, 2)]
[InlineData(2, 1)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task ContentLength_DoesNotMatchRequestContentLength_Throws(int contentLength, int bytesSent)
{
await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs
index cda46fff4c6..67a6d5451d9 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs
@@ -27,6 +27,7 @@ namespace System.Net.Http.Functional.Tests
[Theory]
[MemberData(nameof(TestLoopbackAsync_MemberData))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69870", TestPlatforms.Android)]
public async Task TestLoopbackAsync(string scheme, bool useSsl, bool useAuth, string host)
{
if (useSsl && UseVersion == HttpVersion.Version20 && !PlatformDetection.SupportsAlpn)
@@ -129,6 +130,7 @@ namespace System.Net.Http.Functional.Tests
}
[SkipOnPlatform(TestPlatforms.Browser, "UseProxy not supported on Browser")]
+ [SkipOnPlatform(TestPlatforms.Android, "The sync Send method is not supported on mobile platforms")]
public sealed class SocksProxyTest_Http1_Sync : SocksProxyTest
{
public SocksProxyTest_Http1_Sync(ITestOutputHelper helper) : base(helper) { }
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs
index 6e67a0173ea..87c44e4ba6b 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs
@@ -7,6 +7,7 @@ using Xunit.Abstractions;
namespace System.Net.Http.Functional.Tests
{
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_HttpProtocolTests : HttpProtocolTests
{
public SyncHttpHandler_HttpProtocolTests(ITestOutputHelper output) : base(output) { }
@@ -14,12 +15,14 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_HttpProtocolTests_Dribble : HttpProtocolTests_Dribble
{
public SyncHttpHandler_HttpProtocolTests_Dribble(ITestOutputHelper output) : base(output) { }
protected override bool TestAsync => false;
}
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_DiagnosticsTest : DiagnosticsTest
{
public SyncHttpHandler_DiagnosticsTest(ITestOutputHelper output) : base(output) { }
@@ -27,6 +30,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowserDomSupportedOrNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_PostScenarioTest : PostScenarioTest
{
public SyncHttpHandler_PostScenarioTest(ITestOutputHelper output) : base(output) { }
@@ -34,6 +38,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_HttpClientHandlerTest : HttpClientHandlerTest
{
public SyncHttpHandler_HttpClientHandlerTest(ITestOutputHelper output) : base(output) { }
@@ -41,12 +46,14 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandlerTest_AutoRedirect : HttpClientHandlerTest_AutoRedirect
{
public SyncHttpHandlerTest_AutoRedirect(ITestOutputHelper output) : base(output) { }
protected override bool TestAsync => false;
}
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_HttpClientHandler_Decompression_Tests : HttpClientHandler_Decompression_Test
{
public SyncHttpHandler_HttpClientHandler_Decompression_Tests(ITestOutputHelper output) : base(output) { }
@@ -54,6 +61,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_IdnaProtocolTests : IdnaProtocolTests
{
public SyncHttpHandler_IdnaProtocolTests(ITestOutputHelper output) : base(output) { }
@@ -62,6 +70,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandlerTest_RequestRetry : HttpClientHandlerTest_RequestRetry
{
public SyncHttpHandlerTest_RequestRetry(ITestOutputHelper output) : base(output) { }
@@ -69,6 +78,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandlerTest_Cookies : HttpClientHandlerTest_Cookies
{
public SyncHttpHandlerTest_Cookies(ITestOutputHelper output) : base(output) { }
@@ -76,6 +86,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandlerTest_Cookies_Http11 : HttpClientHandlerTest_Cookies_Http11
{
public SyncHttpHandlerTest_Cookies_Http11(ITestOutputHelper output) : base(output) { }
@@ -83,6 +94,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_HttpClientHandler_Cancellation_Test : SocketsHttpHandler_Cancellation_Test
{
public SyncHttpHandler_HttpClientHandler_Cancellation_Test(ITestOutputHelper output) : base(output) { }
@@ -90,6 +102,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_HttpClientHandler_Authentication_Test : HttpClientHandler_Authentication_Test
{
public SyncHttpHandler_HttpClientHandler_Authentication_Test(ITestOutputHelper output) : base(output) { }
@@ -97,6 +110,7 @@ namespace System.Net.Http.Functional.Tests
}
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandler_Connect_Test : HttpClientHandler_Connect_Test
{
public SyncHttpHandler_Connect_Test(ITestOutputHelper output) : base(output) { }
@@ -104,6 +118,7 @@ namespace System.Net.Http.Functional.Tests
}
[SkipOnPlatform(TestPlatforms.Browser, "System.Net.Sockets is not supported on this platform.")]
+ [SkipOnPlatform(TestPlatforms.Android, "Synchronous Send method is not supported on Android.")]
public sealed class SyncHttpHandlerTest_HttpClientHandlerTest_Headers : HttpClientHandlerTest_Headers
{
public SyncHttpHandlerTest_HttpClientHandlerTest_Headers(ITestOutputHelper output) : base(output) { }
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 6d390623b91..59a84cb1826 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
@@ -345,6 +345,7 @@
<Compile Include="HPackTest.cs" />
<Compile Include="HttpClientHandlerTest.Http1.cs" />
<Compile Include="HttpClientHandlerTest.Http2.cs" />
+ <Compile Include="HttpClientHandlerTest.Url.cs" />
<Compile Include="$(CommonTestPath)System\Net\Http\HttpClientHandlerTest.AcceptAllCerts.cs"
Link="Common\System\Net\Http\HttpClientHandlerTest.AcceptAllCerts.cs" />
<Compile Include="$(CommonTestPath)System\Net\Http\HttpClientHandlerTest.Decompression.cs"
diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/MultipartContentTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/MultipartContentTest.cs
index e89d38c204b..bfac32cb531 100644
--- a/src/libraries/System.Net.Http/tests/UnitTests/Headers/MultipartContentTest.cs
+++ b/src/libraries/System.Net.Http/tests/UnitTests/Headers/MultipartContentTest.cs
@@ -18,19 +18,19 @@ namespace System.Net.Http.Tests
var complexContent = new MultipartContent();
var stringContent = new StringContent("bar1");
- stringContent.Headers.Add("latin1", "\uD83D\uDE00");
+ stringContent.Headers.Add("latin1", "\U0001F600");
complexContent.Add(stringContent);
- var byteArrayContent = new ByteArrayContent(Encoding.ASCII.GetBytes("bar2"));
- byteArrayContent.Headers.Add("utf8", "\uD83D\uDE00");
+ var byteArrayContent = new ByteArrayContent("bar2"u8.ToArray());
+ byteArrayContent.Headers.Add("utf8", "\U0001F600");
complexContent.Add(byteArrayContent);
- byteArrayContent = new ByteArrayContent(Encoding.ASCII.GetBytes("bar3"));
- byteArrayContent.Headers.Add("ascii", "\uD83D\uDE00");
+ byteArrayContent = new ByteArrayContent("bar3"u8.ToArray());
+ byteArrayContent.Headers.Add("ascii", "\U0001F600");
complexContent.Add(byteArrayContent);
- byteArrayContent = new ByteArrayContent(Encoding.ASCII.GetBytes("bar4"));
- byteArrayContent.Headers.Add("default", "\uD83D\uDE00");
+ byteArrayContent = new ByteArrayContent("bar4"u8.ToArray());
+ byteArrayContent.Headers.Add("default", "\U0001F600");
complexContent.Add(byteArrayContent);
stringContent = new StringContent("bar5");
diff --git a/src/libraries/System.Net.Http/tests/UnitTests/MockContent.cs b/src/libraries/System.Net.Http/tests/UnitTests/MockContent.cs
index 84971cbe30f..56dac20a58a 100644
--- a/src/libraries/System.Net.Http/tests/UnitTests/MockContent.cs
+++ b/src/libraries/System.Net.Http/tests/UnitTests/MockContent.cs
@@ -69,15 +69,7 @@ namespace System.Net.Http.Tests
public MockContent(byte[] mockData, MockOptions options)
{
_options = options;
-
- if (mockData == null)
- {
- _mockData = Encoding.UTF8.GetBytes("data");
- }
- else
- {
- _mockData = mockData;
- }
+ _mockData = mockData ?? "data"u8.ToArray();
}
public byte[] GetMockData()
diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs b/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs
index d0159245503..e42cfb07a05 100644
--- a/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs
+++ b/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs
@@ -64,7 +64,7 @@ namespace System.Net
private HttpListenerContext _context;
private bool _isChunked;
- private static byte[] s_100continue = Encoding.ASCII.GetBytes("HTTP/1.1 100 Continue\r\n\r\n");
+ private static byte[] s_100continue = "HTTP/1.1 100 Continue\r\n\r\n"u8.ToArray();
internal HttpListenerRequest(HttpListenerContext context)
{
diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStreamAsyncResult.cs b/src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStreamAsyncResult.cs
index 64514975250..28649cc6ce0 100644
--- a/src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStreamAsyncResult.cs
+++ b/src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStreamAsyncResult.cs
@@ -107,7 +107,7 @@ namespace System.Net
return Header;
}
- private static readonly byte[] s_CRLFArray = new byte[] { (byte)'\r', (byte)'\n' };
+ private static readonly byte[] s_CRLFArray = "\r\n"u8.ToArray();
internal HttpResponseStreamAsyncResult(object asyncObject, object? userState, AsyncCallback? callback, byte[] buffer, int offset, int size, bool chunked, bool sentHeaders, ThreadPoolBoundHandle boundHandle) : base(asyncObject, userState, callback)
{
diff --git a/src/libraries/System.Net.HttpListener/tests/HttpListenerAuthenticationTests.cs b/src/libraries/System.Net.HttpListener/tests/HttpListenerAuthenticationTests.cs
index 89d5c2428e0..900fea85114 100644
--- a/src/libraries/System.Net.HttpListener/tests/HttpListenerAuthenticationTests.cs
+++ b/src/libraries/System.Net.HttpListener/tests/HttpListenerAuthenticationTests.cs
@@ -102,7 +102,7 @@ namespace System.Net.Tests
{
yield return new object[] { string.Empty, HttpStatusCode.Unauthorized };
yield return new object[] { null, HttpStatusCode.Unauthorized };
- yield return new object[] { Convert.ToBase64String(Encoding.ASCII.GetBytes("username")), HttpStatusCode.BadRequest };
+ yield return new object[] { Convert.ToBase64String("username"u8), HttpStatusCode.BadRequest };
yield return new object[] { "abc", HttpStatusCode.InternalServerError };
}
diff --git a/src/libraries/System.Net.HttpListener/tests/HttpListenerContextTests.cs b/src/libraries/System.Net.HttpListener/tests/HttpListenerContextTests.cs
index a276a610b40..e7e234d612f 100644
--- a/src/libraries/System.Net.HttpListener/tests/HttpListenerContextTests.cs
+++ b/src/libraries/System.Net.HttpListener/tests/HttpListenerContextTests.cs
@@ -101,7 +101,7 @@ namespace System.Net.Tests
[ConditionalFact(nameof(IsNotWindows7))]
public async Task AcceptWebSocketAsync_AuthorizationInHeaders_ThrowsNotImplementedException()
{
- Socket.Options.SetRequestHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("user:password")));
+ Socket.Options.SetRequestHeader("Authorization", "Basic " + Convert.ToBase64String("user:password"u8));
Factory.GetListener().AuthenticationSchemes = AuthenticationSchemes.Basic;
HttpListenerContext context = await GetWebSocketContext();
diff --git a/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.cs b/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.cs
index e2d1d826d44..581ba91fb9d 100644
--- a/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.cs
+++ b/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.cs
@@ -13,7 +13,7 @@ namespace System.Net.Tests
{
protected HttpListenerFactory Factory { get; }
protected Socket Client { get; }
- protected static byte[] SimpleMessage { get; } = Encoding.UTF8.GetBytes("Hello");
+ protected static byte[] SimpleMessage { get; } = "Hello"u8.ToArray();
public HttpListenerResponseTestBase()
{
diff --git a/src/libraries/System.Net.HttpListener/tests/HttpResponseStreamTests.cs b/src/libraries/System.Net.HttpListener/tests/HttpResponseStreamTests.cs
index 841fae8c293..62fb2be6840 100644
--- a/src/libraries/System.Net.HttpListener/tests/HttpResponseStreamTests.cs
+++ b/src/libraries/System.Net.HttpListener/tests/HttpResponseStreamTests.cs
@@ -62,7 +62,7 @@ namespace System.Net.Tests
outputStream.Close();
}
- byte[] extraBytesSentAfterClose = Encoding.UTF8.GetBytes("Should not be sent.");
+ byte[] extraBytesSentAfterClose = "Should not be sent."u8.ToArray();
await outputStream.WriteAsync(extraBytesSentAfterClose, 0, extraBytesSentAfterClose.Length);
}
@@ -100,7 +100,7 @@ namespace System.Net.Tests
outputStream.Close();
}
- byte[] extraBytesSentAfterClose = Encoding.UTF8.GetBytes("Should not be sent.");
+ byte[] extraBytesSentAfterClose = "Should not be sent."u8.ToArray();
outputStream.Write(extraBytesSentAfterClose, 0, extraBytesSentAfterClose.Length);
}
@@ -308,7 +308,7 @@ namespace System.Net.Tests
using (HttpListenerResponse response = serverContext.Response)
{
Stream output = response.OutputStream;
- byte[] responseBuffer = Encoding.UTF8.GetBytes("A long string");
+ byte[] responseBuffer = "A long string"u8.ToArray();
response.ContentLength64 = responseBuffer.Length - 1;
try
{
@@ -337,7 +337,7 @@ namespace System.Net.Tests
{
Stream output = response.OutputStream;
- byte[] responseBuffer = Encoding.UTF8.GetBytes("A long string");
+ byte[] responseBuffer = "A long string"u8.ToArray();
response.ContentLength64 = responseBuffer.Length + 1;
// Throws when there are bytes left to write
@@ -363,7 +363,7 @@ namespace System.Net.Tests
{
Stream output = response.OutputStream;
- byte[] responseBuffer = Encoding.UTF8.GetBytes("A long string");
+ byte[] responseBuffer = "A long string"u8.ToArray();
response.ContentLength64 = responseBuffer.Length + 1;
// Throws when there are bytes left to write
diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/EncodedStreamFactory.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/EncodedStreamFactory.cs
index 5b1001c6a9a..86d020c349e 100644
--- a/src/libraries/System.Net.Mail/src/System/Net/Mime/EncodedStreamFactory.cs
+++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/EncodedStreamFactory.cs
@@ -40,6 +40,6 @@ namespace System.Net.Mime
Encoding.ASCII.GetBytes("=?" + encoding.HeaderName + "?" + (useBase64Encoding ? "B?" : "Q?"));
//The footer that marks the end of a quoted string of some sort
- private static readonly byte[] s_footer = new byte[] { (byte)'?', (byte)'=' };
+ private static readonly byte[] s_footer = "?="u8.ToArray();
}
}
diff --git a/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs b/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs
index e269cc6eeea..26aa4580dd5 100644
--- a/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs
+++ b/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs
@@ -16,8 +16,8 @@ namespace Systen.Net.Mail.Tests
{
public class LoopbackSmtpServer : IDisposable
{
- private static readonly ReadOnlyMemory<byte> s_messageTerminator = new byte[] { (byte)'\r', (byte)'\n' };
- private static readonly ReadOnlyMemory<byte> s_bodyTerminator = new byte[] { (byte)'\r', (byte)'\n', (byte)'.', (byte)'\r', (byte)'\n' };
+ private static readonly ReadOnlyMemory<byte> s_messageTerminator = "\r\n"u8.ToArray();
+ private static readonly ReadOnlyMemory<byte> s_bodyTerminator = "\r\n.\r\n"u8.ToArray();
public bool ReceiveMultipleConnections = false;
public bool SupportSmtpUTF8 = false;
diff --git a/src/libraries/System.Net.Mail/tests/Unit/QuotedPrintableStreamTest.cs b/src/libraries/System.Net.Mail/tests/Unit/QuotedPrintableStreamTest.cs
index 0c66e26d9c6..0e9f66fa2bb 100644
--- a/src/libraries/System.Net.Mail/tests/Unit/QuotedPrintableStreamTest.cs
+++ b/src/libraries/System.Net.Mail/tests/Unit/QuotedPrintableStreamTest.cs
@@ -50,12 +50,8 @@ namespace System.Net.Mime.Tests
var outputStream = new MemoryStream();
var testStream = new QuotedPrintableStream(outputStream, false);
- byte[] bytesToWrite1 = Encoding.ASCII.GetBytes("Hello \r");
- testStream.Write(bytesToWrite1, 0, bytesToWrite1.Length);
-
- byte[] bytesToWrite2 = Encoding.ASCII.GetBytes("\n World");
- testStream.Write(bytesToWrite2, 0, bytesToWrite2.Length);
-
+ testStream.Write("Hello \r"u8);
+ testStream.Write("\n World"u8);
testStream.Flush();
// We told it not to encode them, but they got split across writes so it could not
diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs
index 8a87d2f0111..0e48bb4777b 100644
--- a/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs
+++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/TestSettings.cs
@@ -18,7 +18,7 @@ namespace System.Net.NetworkInformation.Tests
// By default, FreeBSD supports buffer only up to 56 bytes
public static readonly byte[] PayloadAsBytes = Encoding.UTF8.GetBytes(OperatingSystem.IsFreeBSD() ? TestSettings.PayloadAsString.Substring(0, 55) : TestSettings.PayloadAsString);
- public static readonly byte[] PayloadAsBytesShort = Encoding.UTF8.GetBytes("ABCDEF0123456789");
+ public static readonly byte[] PayloadAsBytesShort = "ABCDEF0123456789"u8.ToArray();
public static IPAddress[] GetLocalIPAddresses()
{
diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs
index 6eedee6a6c7..0cb01e754b0 100644
--- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs
+++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs
@@ -16,8 +16,6 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
{
internal sealed unsafe class MsQuicApi
{
- private static readonly byte[] s_appName = Encoding.ASCII.GetBytes("System.Net.Quic");
-
private static readonly Version MinWindowsVersion = new Version(10, 0, 20145, 1000);
private static readonly Version MsQuicVersion = new Version(2, 0);
@@ -38,7 +36,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
{
ApiTable = apiTable;
- fixed (byte* pAppName = s_appName)
+ fixed (byte* pAppName = "System.Net.Quic"u8)
{
var cfg = new QUIC_REGISTRATION_CONFIG {
AppName = (sbyte*)pAppName,
diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs
index a14b21f4f08..65e78735e12 100644
--- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs
+++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs
@@ -25,7 +25,7 @@ namespace System.Net.Quic.Tests
[Collection(nameof(DisableParallelization))]
public class MsQuicTests : QuicTestBase<MsQuicProviderFactory>
{
- private static byte[] s_data = Encoding.UTF8.GetBytes("Hello world!");
+ private static byte[] s_data = "Hello world!"u8.ToArray();
public MsQuicTests(ITestOutputHelper output) : base(output) { }
@@ -630,7 +630,7 @@ namespace System.Net.Quic.Tests
{
(QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection();
- ReadOnlyMemory<byte> helloWorld = Encoding.ASCII.GetBytes("Hello world!");
+ ReadOnlyMemory<byte> helloWorld = "Hello world!"u8.ToArray();
ReadOnlySequence<byte> ros = CreateReadOnlySequenceFromBytes(helloWorld.ToArray());
Assert.False(ros.IsSingleSegment);
diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs
index 7f4e03a9769..0fe8068fcdc 100644
--- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs
+++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs
@@ -15,7 +15,7 @@ namespace System.Net.Quic.Tests
public abstract class QuicStreamTests<T> : QuicTestBase<T>
where T : IQuicImplProviderFactory, new()
{
- private static byte[] s_data = Encoding.UTF8.GetBytes("Hello world!");
+ private static byte[] s_data = "Hello world!"u8.ToArray();
public QuicStreamTests(ITestOutputHelper output) : base(output) { }
[Fact]
@@ -179,7 +179,7 @@ namespace System.Net.Quic.Tests
{
byte[] buffer = new byte[64];
QuicStream clientStream = await clientConnection.OpenBidirectionalStreamAsync();
- ValueTask writeTask = clientStream.WriteAsync(Encoding.UTF8.GetBytes("PING"), endStream: true);
+ ValueTask writeTask = clientStream.WriteAsync("PING"u8.ToArray(), endStream: true);
ValueTask<QuicStream> acceptTask = serverConnection.AcceptStreamAsync();
await new Task[] { writeTask.AsTask(), acceptTask.AsTask() }.WhenAllOrAnyFailed(PassingTestTimeoutMilliseconds);
QuicStream serverStream = acceptTask.Result;
diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs
index 8566d0cd40f..b613b6dd44f 100644
--- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs
+++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs
@@ -20,8 +20,8 @@ namespace System.Net.Quic.Tests
public abstract class QuicTestBase<T>
where T : IQuicImplProviderFactory, new()
{
- private static readonly byte[] s_ping = Encoding.UTF8.GetBytes("PING");
- private static readonly byte[] s_pong = Encoding.UTF8.GetBytes("PONG");
+ private static readonly byte[] s_ping = "PING"u8.ToArray();
+ private static readonly byte[] s_pong = "PONG"u8.ToArray();
private static readonly IQuicImplProviderFactory s_factory = new T();
public static QuicImplementationProvider ImplementationProvider { get; } = s_factory.GetProvider();
diff --git a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
index 6cf0d7d7740..d1f5e58b349 100644
--- a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
+++ b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
@@ -79,7 +79,7 @@ namespace System.Net.Tests
private const string absoluteUri = "ftp://localhost/";
- private static readonly byte[] helloWorldBytes = Encoding.UTF8.GetBytes("Hello world");
+ private static readonly byte[] helloWorldBytes = "Hello world"u8.ToArray();
private static readonly byte[] largeFileBytes = Enumerable.Range(0, 10 * 1024 * 1024).Select((i) => (byte)(i % 256)).ToArray();
[ConditionalTheory(nameof(LocalServerAvailable))]
diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs
index 1601097c308..b0f4e008eb6 100644
--- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs
@@ -42,11 +42,11 @@ namespace System.Net
//
private static X509Certificate2? GetRemoteCertificate(
- SafeDeleteContext securityContext,
+ SafeDeleteContext? securityContext,
bool retrieveChainCertificates,
ref X509Chain? chain)
{
- SafeSslHandle sslContext = ((SafeDeleteSslContext)securityContext).SslContext;
+ SafeSslHandle? sslContext = ((SafeDeleteSslContext?)securityContext)?.SslContext;
if (sslContext == null)
return null;
diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs
index d50425cd579..44d8e3a5dfd 100644
--- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs
@@ -48,7 +48,7 @@ namespace System.Net
}
private static X509Certificate2? GetRemoteCertificate(
- SafeDeleteContext securityContext,
+ SafeDeleteContext? securityContext,
bool retrieveChainCertificates,
ref X509Chain? chain)
{
diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.cs
index 6f57de312c1..b21b1bac664 100644
--- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.cs
@@ -18,10 +18,10 @@ namespace System.Net
private static volatile X509Store? s_myMachineCertStoreEx;
private static X509Chain? s_chain;
- internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext securityContext) =>
+ internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext) =>
GetRemoteCertificate(securityContext, retrieveChainCertificates: false, ref s_chain);
- internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext securityContext, ref X509Chain? chain) =>
+ internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext, ref X509Chain? chain) =>
GetRemoteCertificate(securityContext, retrieveChainCertificates: true, ref chain);
static partial void CheckSupportsStore(StoreLocation storeLocation, ref bool hasSupport);
diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs
index f218ce28751..e86c79b2bf7 100644
--- a/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs
@@ -10,9 +10,9 @@ namespace System.Net.Security
public readonly struct SslApplicationProtocol : IEquatable<SslApplicationProtocol>
{
private static readonly Encoding s_utf8 = Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
- private static readonly byte[] s_http3Utf8 = new byte[] { 0x68, 0x33 }; // "h3"
- private static readonly byte[] s_http2Utf8 = new byte[] { 0x68, 0x32 }; // "h2"
- private static readonly byte[] s_http11Utf8 = new byte[] { 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 }; // "http/1.1"
+ private static readonly byte[] s_http3Utf8 = "h3"u8.ToArray();
+ private static readonly byte[] s_http2Utf8 = "h2"u8.ToArray();
+ private static readonly byte[] s_http11Utf8 = "http/1.1"u8.ToArray();
// Refer to IANA on ApplicationProtocols: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
/// <summary>Defines a <see cref="SslApplicationProtocol"/> instance for HTTP 3.0.</summary>
diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
index af45303e999..872da0d4065 100644
--- a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
@@ -17,8 +17,6 @@ namespace System.Net.Security
internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticationOptions)
{
- Debug.Assert(sslClientAuthenticationOptions.TargetHost != null);
-
if (CertValidationDelegate == null)
{
CertValidationDelegate = sslClientAuthenticationOptions.RemoteCertificateValidationCallback;
@@ -26,7 +24,7 @@ namespace System.Net.Security
else if (sslClientAuthenticationOptions.RemoteCertificateValidationCallback != null &&
CertValidationDelegate != sslClientAuthenticationOptions.RemoteCertificateValidationCallback)
{
- // Callback was set in constructor to differet value.
+ // Callback was set in constructor to different value.
throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(RemoteCertificateValidationCallback)));
}
@@ -49,7 +47,10 @@ namespace System.Net.Security
IsServer = false;
RemoteCertRequired = true;
// RFC 6066 section 3 says to exclude trailing dot from fully qualified DNS hostname
- TargetHost = sslClientAuthenticationOptions.TargetHost.TrimEnd('.');
+ if (sslClientAuthenticationOptions.TargetHost != null)
+ {
+ TargetHost = sslClientAuthenticationOptions.TargetHost.TrimEnd('.');
+ }
// Client specific options.
CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode;
diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs
index 44163221458..c9c00510cb6 100644
--- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs
@@ -117,7 +117,7 @@ namespace System.Net.Security
private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, CancellationToken cancellationToken)
{
- NetSecurityTelemetry.Log.HandshakeStart(IsServer, _sslAuthenticationOptions!.TargetHost);
+ NetSecurityTelemetry.Log.HandshakeStart(IsServer, _sslAuthenticationOptions.TargetHost);
long startingTimestamp = Stopwatch.GetTimestamp();
try
@@ -185,7 +185,7 @@ namespace System.Net.Security
throw new InvalidOperationException(SR.net_ssl_renegotiate_buffer);
}
- _sslAuthenticationOptions!.RemoteCertRequired = true;
+ _sslAuthenticationOptions.RemoteCertRequired = true;
_isRenego = true;
@@ -222,7 +222,7 @@ namespace System.Net.Security
}
while (message.Status.ErrorCode == SecurityStatusPalErrorCode.ContinueNeeded);
- CompleteHandshake(_sslAuthenticationOptions!);
+ CompleteHandshake(_sslAuthenticationOptions);
}
finally
{
@@ -332,7 +332,7 @@ namespace System.Net.Security
}
}
- CompleteHandshake(_sslAuthenticationOptions!);
+ CompleteHandshake(_sslAuthenticationOptions);
}
finally
{
@@ -394,7 +394,7 @@ namespace System.Net.Security
// SNI if it exist. Even if we could not parse the hello, we can fall-back to default certificate.
if (_lastFrame.TargetName != null)
{
- _sslAuthenticationOptions!.TargetHost = _lastFrame.TargetName;
+ _sslAuthenticationOptions.TargetHost = _lastFrame.TargetName;
}
if (_sslAuthenticationOptions.ServerOptionDelegate != null)
@@ -504,7 +504,7 @@ namespace System.Net.Security
return true;
}
- if (!VerifyRemoteCertificate(_sslAuthenticationOptions!.CertValidationDelegate, _sslAuthenticationOptions!.CertificateContext?.Trust, ref alertToken, out sslPolicyErrors, out chainStatus))
+ if (!VerifyRemoteCertificate(_sslAuthenticationOptions.CertValidationDelegate, _sslAuthenticationOptions.CertificateContext?.Trust, ref alertToken, out sslPolicyErrors, out chainStatus))
{
_handshakeCompleted = false;
return false;
@@ -746,7 +746,7 @@ namespace System.Net.Security
// If that happen before EncryptData() runs, _handshakeWaiter will be set to null
// and EncryptData() will work normally e.g. no waiting, just exclusion with DecryptData()
- if (_sslAuthenticationOptions!.AllowRenegotiation || SslProtocol == SslProtocols.Tls13 || _nestedAuth != 0)
+ if (_sslAuthenticationOptions.AllowRenegotiation || SslProtocol == SslProtocols.Tls13 || _nestedAuth != 0)
{
// create TCS only if we plan to proceed. If not, we will throw later outside of the lock.
// Tls1.3 does not have renegotiation. However on Windows this error code is used
diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs
index b732dfe4d24..f0494c3ba70 100644
--- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs
@@ -100,7 +100,7 @@ namespace System.Net.Security
{
get
{
- return _sslAuthenticationOptions!.RemoteCertRequired;
+ return _sslAuthenticationOptions.RemoteCertRequired;
}
}
@@ -251,7 +251,7 @@ namespace System.Net.Security
try
{
issuers = GetRequestCertificateAuthorities();
- remoteCert = CertificateValidationPal.GetRemoteCertificate(_securityContext!);
+ remoteCert = CertificateValidationPal.GetRemoteCertificate(_securityContext);
if (_sslAuthenticationOptions.ClientCertificates == null)
{
_sslAuthenticationOptions.ClientCertificates = new X509CertificateCollection();
@@ -929,7 +929,7 @@ namespace System.Net.Security
try
{
- X509Certificate2? certificate = CertificateValidationPal.GetRemoteCertificate(_securityContext!, ref chain);
+ X509Certificate2? certificate = CertificateValidationPal.GetRemoteCertificate(_securityContext, ref chain);
if (_remoteCertificate != null && certificate != null &&
certificate.RawDataMemory.Span.SequenceEqual(_remoteCertificate.RawDataMemory.Span))
{
diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs
index 44bbfee78f2..10d3c2eb14f 100644
--- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs
+++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs
@@ -321,7 +321,6 @@ namespace System.Net.Security
public void AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions)
{
ArgumentNullException.ThrowIfNull(sslClientAuthenticationOptions);
- ArgumentNullException.ThrowIfNull(sslClientAuthenticationOptions.TargetHost, nameof(sslClientAuthenticationOptions.TargetHost));
ThrowIfExceptional();
@@ -384,7 +383,6 @@ namespace System.Net.Security
public Task AuthenticateAsClientAsync(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(sslClientAuthenticationOptions);
- ArgumentNullException.ThrowIfNull(sslClientAuthenticationOptions.TargetHost, nameof(sslClientAuthenticationOptions.TargetHost));
ThrowIfExceptional();
_sslAuthenticationOptions.UpdateOptions(sslClientAuthenticationOptions);
@@ -624,7 +622,7 @@ namespace System.Net.Security
{
get
{
- return _sslAuthenticationOptions != null ? _sslAuthenticationOptions.TargetHost : string.Empty;
+ return _sslAuthenticationOptions.TargetHost;
}
}
diff --git a/src/libraries/System.Net.Security/tests/EnterpriseTests/NegotiateStreamLoopbackTest.cs b/src/libraries/System.Net.Security/tests/EnterpriseTests/NegotiateStreamLoopbackTest.cs
index bf8272c3f09..d6815f599a2 100644
--- a/src/libraries/System.Net.Security/tests/EnterpriseTests/NegotiateStreamLoopbackTest.cs
+++ b/src/libraries/System.Net.Security/tests/EnterpriseTests/NegotiateStreamLoopbackTest.cs
@@ -23,7 +23,7 @@ namespace System.Net.Security.Enterprise.Tests
private const string TargetName = "HOST/linuxclient.linux.contoso.com";
private const int PartialBytesToRead = 5;
- private static readonly byte[] s_sampleMsg = Encoding.UTF8.GetBytes("Sample Test Message");
+ private static readonly byte[] s_sampleMsg = "Sample Test Message"u8.ToArray();
private const int MaxWriteDataSize = 63 * 1024; // NegoState.MaxWriteDataSize
private static string s_longString = new string('A', MaxWriteDataSize) + 'Z';
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs
index bbfefa4223d..b61b0ef105a 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs
@@ -19,7 +19,7 @@ namespace System.Net.Security.Tests
[PlatformSpecific(TestPlatforms.Windows)] // NegotiateStream only supports client-side functionality on Unix
public class NegotiateStreamInvalidOperationTest
{
- private static readonly byte[] s_sampleMsg = Encoding.UTF8.GetBytes("Sample Test Message");
+ private static readonly byte[] s_sampleMsg = "Sample Test Message"u8.ToArray();
private const string TargetName = "testTargetName";
[Fact]
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamKerberosTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamKerberosTest.cs
index 8ca45a58f46..df74c839db7 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamKerberosTest.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamKerberosTest.cs
@@ -157,7 +157,7 @@ namespace System.Net.Security.Tests
Assert.True(auth.IsSigned);
// Send a message to the server. Encode the test data into a byte array.
- byte[] message = Encoding.UTF8.GetBytes("Hello from the client.");
+ byte[] message = "Hello from the client."u8.ToArray();
await auth.WriteAsync(message, 0, message.Length);
}
}
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs
index 043ab1fd09d..76a1c318928 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs
@@ -20,7 +20,7 @@ namespace System.Net.Security.Tests
public static bool IsNtlmInstalled => Capability.IsNtlmInstalled();
private const int PartialBytesToRead = 5;
- protected static readonly byte[] s_sampleMsg = Encoding.UTF8.GetBytes("Sample Test Message");
+ protected static readonly byte[] s_sampleMsg = "Sample Test Message"u8.ToArray();
private const int MaxWriteDataSize = 63 * 1024; // NegoState.MaxWriteDataSize
private static string s_longString = new string('A', MaxWriteDataSize) + 'Z';
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs
index cbac2f93039..75afa305b54 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs
@@ -114,6 +114,26 @@ namespace System.Net.Security.Tests
}
}
}
+
+ [Fact]
+ public async Task ClientOptions_TargetHostNull_OK()
+ {
+ (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams();
+ using (client)
+ using (server)
+ {
+ var serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = Configuration.Certificates.GetServerCertificate() };
+ var clientOptions = new SslClientAuthenticationOptions() { RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true };
+
+ Assert.Null(clientOptions.TargetHost);
+
+ await TestConfiguration.WhenAllOrAnyFailedWithTimeout(
+ client.AuthenticateAsClientAsync(clientOptions),
+ server.AuthenticateAsServerAsync(serverOptions));
+ Assert.Equal(string.Empty, client.TargetHostName);
+ Assert.Equal(string.Empty, server.TargetHostName);
+ }
+ }
}
public sealed class SslClientAuthenticationOptionsTestBase_Sync : SslClientAuthenticationOptionsTestBase
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs
index 7520221e6e9..469c0a13b71 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs
@@ -55,7 +55,7 @@ namespace System.Net.Security.Tests
Assert.True(ssl.IsEncrypted);
// Issue request that triggers renegotiation from server.
- byte[] message = Encoding.UTF8.GetBytes("GET /EchoClientCertificate.ashx HTTP/1.1\r\nHost: corefx-net-tls.azurewebsites.net\r\n\r\n");
+ byte[] message = "GET /EchoClientCertificate.ashx HTTP/1.1\r\nHost: corefx-net-tls.azurewebsites.net\r\n\r\n"u8.ToArray();
await ssl.WriteAsync(message, 0, message.Length);
// Initiate Read operation, that results in starting renegotiation as per server response to the above request.
@@ -94,7 +94,7 @@ namespace System.Net.Security.Tests
Assert.True(ssl.IsEncrypted);
// Issue request that triggers regotiation from server.
- byte[] message = Encoding.UTF8.GetBytes("GET /EchoClientCertificate.ashx HTTP/1.1\r\nHost: corefx-net-tls.azurewebsites.net\r\n\r\n");
+ byte[] message = "GET /EchoClientCertificate.ashx HTTP/1.1\r\nHost: corefx-net-tls.azurewebsites.net\r\n\r\n"u8.ToArray();
await ssl.WriteAsync(message, 0, message.Length);
// Initiate Read operation, that results in starting renegotiation as per server response to the above request.
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs
index 2de22f5325c..1c8cfdb54b4 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs
@@ -164,7 +164,7 @@ namespace System.Net.Security.Tests
Assert.True(ssl.IsEncrypted);
// Issue request that triggers regotiation from server.
- byte[] message = Encoding.UTF8.GetBytes("GET /EchoClientCertificate.ashx HTTP/1.1\r\nHost: corefx-net-tls.azurewebsites.net\r\n\r\n");
+ byte[] message = "GET /EchoClientCertificate.ashx HTTP/1.1\r\nHost: corefx-net-tls.azurewebsites.net\r\n\r\n"u8.ToArray();
if (useSync)
{
ssl.Write(message, 0, message.Length);
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
index 8d0dae26892..873f7546e65 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
@@ -20,7 +20,7 @@ namespace System.Net.Security.Tests
public abstract class SslStreamStreamToStreamTest
{
- private readonly byte[] _sampleMsg = Encoding.UTF8.GetBytes("Sample Test Message");
+ private readonly byte[] _sampleMsg = "Sample Test Message"u8.ToArray();
protected static async Task WithServerCertificate(X509Certificate serverCertificate, Func<X509Certificate, string, Task> func)
{
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs
index f4cddb99932..62383aa1633 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs
@@ -43,8 +43,8 @@ namespace System.Net.Security.Tests
private static readonly X509BasicConstraintsExtension s_eeConstraints =
new X509BasicConstraintsExtension(false, false, 0, false);
- public static readonly byte[] s_ping = Encoding.UTF8.GetBytes("PING");
- public static readonly byte[] s_pong = Encoding.UTF8.GetBytes("PONG");
+ public static readonly byte[] s_ping = "PING"u8.ToArray();
+ public static readonly byte[] s_pong = "PONG"u8.ToArray();
public static bool AllowAnyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs
index fe016e6c631..477abd602d0 100644
--- a/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs
+++ b/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs
@@ -13,9 +13,9 @@ namespace System.Net.Security.Tests
[Fact]
public void Constants_Values_AreCorrect()
{
- Assert.Equal(new SslApplicationProtocol(new byte[] { 0x68, 0x33 }), SslApplicationProtocol.Http3);
- Assert.Equal(new SslApplicationProtocol(new byte[] { 0x68, 0x32 }), SslApplicationProtocol.Http2);
- Assert.Equal(new SslApplicationProtocol(new byte[] { 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 }), SslApplicationProtocol.Http11);
+ Assert.Equal(new SslApplicationProtocol("h3"u8.ToArray()), SslApplicationProtocol.Http3);
+ Assert.Equal(new SslApplicationProtocol("h2"u8.ToArray()), SslApplicationProtocol.Http2);
+ Assert.Equal(new SslApplicationProtocol("http/1.1"u8.ToArray()), SslApplicationProtocol.Http11);
}
[Fact]
@@ -42,7 +42,7 @@ namespace System.Net.Security.Tests
[Fact]
public void Constructor_ByteArray_Copies()
{
- byte[] expected = Encoding.UTF8.GetBytes("hello");
+ byte[] expected = "hello"u8.ToArray();
SslApplicationProtocol byteProtocol = new SslApplicationProtocol(expected);
ArraySegment<byte> arraySegment;
diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs
index e9bd105165f..6a86b2c5fab 100644
--- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs
+++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs
@@ -190,7 +190,7 @@ namespace System.Net.Sockets.Tests
using (NetworkStream s = client.GetStream())
{
- byte[] getRequest = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n\r\n");
+ byte[] getRequest = "GET / HTTP/1.1\r\n\r\n"u8.ToArray();
await s.WriteAsync(getRequest, 0, getRequest.Length);
Assert.NotEqual(-1, s.ReadByte()); // just verify we successfully get any data back
}
@@ -240,7 +240,7 @@ namespace System.Net.Sockets.Tests
using (NetworkStream s = client.GetStream())
{
- byte[] getRequest = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n\r\n");
+ byte[] getRequest = "GET / HTTP/1.1\r\n\r\n"u8.ToArray();
s.Write(getRequest, 0, getRequest.Length);
Assert.NotEqual(-1, s.ReadByte()); // just verify we successfully get any data back
}
diff --git a/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs b/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs
index f9fd4e3c564..ac0035eb415 100644
--- a/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs
+++ b/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs
@@ -77,7 +77,7 @@ namespace System.Net.WebSockets.Tests
public async Task ReceiveAsync_UTF8SplitAcrossMultipleBuffers_ValidDataReceived()
{
// 1 character - 2 bytes
- byte[] payload = Encoding.UTF8.GetBytes("\u00E6");
+ byte[] payload = "\u00E6"u8.ToArray();
var frame = new byte[payload.Length + 2];
frame[0] = 0x81; // FIN = true, Opcode = Text
frame[1] = (byte)payload.Length;
@@ -294,7 +294,7 @@ namespace System.Net.WebSockets.Tests
Assert.Equal(WebSocketState.Open, socket.State);
// Ask server to send us a close
- await socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(".close")), WebSocketMessageType.Text, true, default);
+ await socket.SendAsync(new ArraySegment<byte>(".close"u8.ToArray()), WebSocketMessageType.Text, true, default);
// Verify received server-initiated close message.
WebSocketReceiveResult recvResult = await socket.ReceiveAsync(new ArraySegment<byte>(new byte[256]), default);
diff --git a/src/libraries/System.Net.WebSockets/tests/WebSocketDeflateTests.cs b/src/libraries/System.Net.WebSockets/tests/WebSocketDeflateTests.cs
index 03ae5981c9b..cec40f41f87 100644
--- a/src/libraries/System.Net.WebSockets/tests/WebSocketDeflateTests.cs
+++ b/src/libraries/System.Net.WebSockets/tests/WebSocketDeflateTests.cs
@@ -77,11 +77,11 @@ namespace System.Net.WebSockets.Tests
DangerousDeflateOptions = new WebSocketDeflateOptions()
});
- await websocket.SendAsync(Encoding.UTF8.GetBytes("Hello"), WebSocketMessageType.Text, true, CancellationToken);
+ await websocket.SendAsync("Hello"u8.ToArray(), WebSocketMessageType.Text, true, CancellationToken);
Assert.Equal("C107F248CDC9C90700", Convert.ToHexString(stream.NextAvailableBytes));
stream.Clear();
- await websocket.SendAsync(Encoding.UTF8.GetBytes("Hello"), WebSocketMessageType.Text, true, CancellationToken);
+ await websocket.SendAsync("Hello"u8.ToArray(), WebSocketMessageType.Text, true, CancellationToken);
// Because context takeover is set by default if we try to send
// the same message it should result in fewer bytes.
@@ -98,7 +98,7 @@ namespace System.Net.WebSockets.Tests
DangerousDeflateOptions = new WebSocketDeflateOptions()
});
- byte[] bytes = Encoding.UTF8.GetBytes("Hello");
+ byte[] bytes = "Hello"u8.ToArray();
WebSocketMessageFlags flags = WebSocketMessageFlags.DisableCompression | WebSocketMessageFlags.EndOfMessage;
await websocket.SendAsync(bytes, WebSocketMessageType.Text, flags, CancellationToken);
@@ -116,7 +116,7 @@ namespace System.Net.WebSockets.Tests
DangerousDeflateOptions = new WebSocketDeflateOptions()
});
- byte[] bytes = Encoding.UTF8.GetBytes("Hello");
+ byte[] bytes = "Hello"u8.ToArray();
await websocket.SendAsync(Memory<byte>.Empty, WebSocketMessageType.Text, endOfMessage: false, CancellationToken);
await websocket.SendAsync(bytes, WebSocketMessageType.Text, endOfMessage: true, CancellationToken);
@@ -181,7 +181,7 @@ namespace System.Net.WebSockets.Tests
for (var i = 0; i < 100; ++i)
{
- await websocket.SendAsync(Encoding.UTF8.GetBytes("Hello"), WebSocketMessageType.Text, true, CancellationToken);
+ await websocket.SendAsync("Hello"u8.ToArray(), WebSocketMessageType.Text, true, CancellationToken);
// Without context takeover the message should look the same every time
Assert.Equal("C107F248CDC9C90700", Convert.ToHexString(stream.NextAvailableBytes));
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 5d0c75eb639..d3d733b73f5 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
@@ -14,6 +14,7 @@
<IsiOSLike Condition="'$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'">true</IsiOSLike>
<IsMobileLike Condition="'$(TargetsBrowser)' == 'true' or '$(IsiOSLike)' == 'true' or '$(TargetsAndroid)' == 'true'">true</IsMobileLike>
<SupportsArmIntrinsics Condition="'$(Platform)' == 'arm64'">true</SupportsArmIntrinsics>
+ <SupportsWasmIntrinsics Condition="'$(Platform)' == 'wasm'">true</SupportsWasmIntrinsics>
<SupportsX86Intrinsics Condition="'$(Platform)' == 'x64' or ('$(Platform)' == 'x86' and '$(TargetsUnix)' != 'true')">true</SupportsX86Intrinsics>
<ILLinkSharedDirectory>$(MSBuildThisFileDirectory)ILLink\</ILLinkSharedDirectory>
<IsBigEndian Condition="'$(Platform)' == 's390x'">true</IsBigEndian>
@@ -2023,8 +2024,8 @@
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetCwd.cs">
<Link>Common\Interop\Unix\System.Native\Interop.GetCwd.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetDefaultTimeZone.Android.cs" Condition="'$(TargetsAndroid)' == 'true' or '$(TargetsLinuxBionic)' == 'true'">
- <Link>Common\Interop\Unix\System.Native\Interop.GetDefaultTimeZone.Android.cs</Link>
+ <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetDefaultTimeZone.AnyMobile.cs" Condition="'$(TargetsAndroid)' == 'true' or '$(TargetsLinuxBionic)' == 'true' or '$(IsiOSLike)' == 'true'">
+ <Link>Common\Interop\Unix\System.Native\Interop.GetDefaultTimeZone.AnyMobile.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetHostName.cs">
<Link>Common\Interop\Unix\System.Native\Interop.GetHostName.cs</Link>
@@ -2242,7 +2243,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.FreeBSD.cs" Condition="'$(TargetsFreeBSD)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Linux.cs" Condition="'$(TargetsLinux)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.OSX.cs" Condition="'$(TargetsOSX)' == 'true' or '$(TargetsMacCatalyst)' == 'true'" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Environment.iOS.cs" Condition="'$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.iOS.cs" Condition="'$(IsiOSLike)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.OSVersion.Unix.cs" Condition="'$(IsOSXLike)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.SunOS.cs" Condition="'$(Targetsillumos)' == 'true' or '$(TargetsSolaris)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.FullGlobalizationData.Unix.cs" Condition="'$(UseMinimalGlobalizationData)' != 'true'" />
@@ -2274,6 +2275,14 @@
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStatus.SetTimes.OSX.cs" />
</ItemGroup>
+ <ItemGroup Condition="'$(IsiOSLike)' == 'true'">
+ <Compile Include="$(CommonPath)Interop\OSX\System.Native\Interop.SearchPath.cs">
+ <Link>Common\Interop\OSX\Interop.SearchPath.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\OSX\System.Native\Interop.SearchPathTempDirectory.cs">
+ <Link>Common\Interop\OSX\Interop.SearchPathTempDirectory.cs</Link>
+ </Compile>
+ </ItemGroup>
<ItemGroup Condition="'$(TargetsMacCatalyst)' == 'true'">
<Compile Include="$(CommonPath)Interop\OSX\System.Native\Interop.iOSSupportVersion.cs" Link="Common\Interop\OSX\System.Native\Interop.iOSSupportVersion.cs" />
</ItemGroup>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs
index 201f52af7f8..bc62fc90b08 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs
@@ -558,45 +558,44 @@ namespace System.Collections.Generic
// - The floating-point comparisons here assume no NaNs, which is valid only because the sorting routines
// themselves special-case NaN with a pre-pass that ensures none are present in the values being sorted
// by moving them all to the front first and then sorting the rest.
- // - The `? true : false` is to work-around poor codegen: https://github.com/dotnet/runtime/issues/37904#issuecomment-644180265.
// - These are duplicated here rather than being on a helper type due to current limitations around generic inlining.
[MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call
private static bool LessThan(ref T left, ref T right)
{
- if (typeof(T) == typeof(byte)) return (byte)(object)left < (byte)(object)right ? true : false;
- if (typeof(T) == typeof(sbyte)) return (sbyte)(object)left < (sbyte)(object)right ? true : false;
- if (typeof(T) == typeof(ushort)) return (ushort)(object)left < (ushort)(object)right ? true : false;
- if (typeof(T) == typeof(short)) return (short)(object)left < (short)(object)right ? true : false;
- if (typeof(T) == typeof(uint)) return (uint)(object)left < (uint)(object)right ? true : false;
- if (typeof(T) == typeof(int)) return (int)(object)left < (int)(object)right ? true : false;
- if (typeof(T) == typeof(ulong)) return (ulong)(object)left < (ulong)(object)right ? true : false;
- if (typeof(T) == typeof(long)) return (long)(object)left < (long)(object)right ? true : false;
- if (typeof(T) == typeof(nuint)) return (nuint)(object)left < (nuint)(object)right ? true : false;
- if (typeof(T) == typeof(nint)) return (nint)(object)left < (nint)(object)right ? true : false;
- if (typeof(T) == typeof(float)) return (float)(object)left < (float)(object)right ? true : false;
- if (typeof(T) == typeof(double)) return (double)(object)left < (double)(object)right ? true : false;
- if (typeof(T) == typeof(Half)) return (Half)(object)left < (Half)(object)right ? true : false;
- return left.CompareTo(right) < 0 ? true : false;
+ if (typeof(T) == typeof(byte)) return (byte)(object)left < (byte)(object)right;
+ if (typeof(T) == typeof(sbyte)) return (sbyte)(object)left < (sbyte)(object)right;
+ if (typeof(T) == typeof(ushort)) return (ushort)(object)left < (ushort)(object)right;
+ if (typeof(T) == typeof(short)) return (short)(object)left < (short)(object)right;
+ if (typeof(T) == typeof(uint)) return (uint)(object)left < (uint)(object)right;
+ if (typeof(T) == typeof(int)) return (int)(object)left < (int)(object)right;
+ if (typeof(T) == typeof(ulong)) return (ulong)(object)left < (ulong)(object)right;
+ if (typeof(T) == typeof(long)) return (long)(object)left < (long)(object)right;
+ if (typeof(T) == typeof(nuint)) return (nuint)(object)left < (nuint)(object)right;
+ if (typeof(T) == typeof(nint)) return (nint)(object)left < (nint)(object)right;
+ if (typeof(T) == typeof(float)) return (float)(object)left < (float)(object)right;
+ if (typeof(T) == typeof(double)) return (double)(object)left < (double)(object)right;
+ if (typeof(T) == typeof(Half)) return (Half)(object)left < (Half)(object)right;
+ return left.CompareTo(right) < 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call
private static bool GreaterThan(ref T left, ref T right)
{
- if (typeof(T) == typeof(byte)) return (byte)(object)left > (byte)(object)right ? true : false;
- if (typeof(T) == typeof(sbyte)) return (sbyte)(object)left > (sbyte)(object)right ? true : false;
- if (typeof(T) == typeof(ushort)) return (ushort)(object)left > (ushort)(object)right ? true : false;
- if (typeof(T) == typeof(short)) return (short)(object)left > (short)(object)right ? true : false;
- if (typeof(T) == typeof(uint)) return (uint)(object)left > (uint)(object)right ? true : false;
- if (typeof(T) == typeof(int)) return (int)(object)left > (int)(object)right ? true : false;
- if (typeof(T) == typeof(ulong)) return (ulong)(object)left > (ulong)(object)right ? true : false;
- if (typeof(T) == typeof(long)) return (long)(object)left > (long)(object)right ? true : false;
- if (typeof(T) == typeof(nuint)) return (nuint)(object)left > (nuint)(object)right ? true : false;
- if (typeof(T) == typeof(nint)) return (nint)(object)left > (nint)(object)right ? true : false;
- if (typeof(T) == typeof(float)) return (float)(object)left > (float)(object)right ? true : false;
- if (typeof(T) == typeof(double)) return (double)(object)left > (double)(object)right ? true : false;
- if (typeof(T) == typeof(Half)) return (Half)(object)left > (Half)(object)right ? true : false;
- return left.CompareTo(right) > 0 ? true : false;
+ if (typeof(T) == typeof(byte)) return (byte)(object)left > (byte)(object)right;
+ if (typeof(T) == typeof(sbyte)) return (sbyte)(object)left > (sbyte)(object)right;
+ if (typeof(T) == typeof(ushort)) return (ushort)(object)left > (ushort)(object)right;
+ if (typeof(T) == typeof(short)) return (short)(object)left > (short)(object)right;
+ if (typeof(T) == typeof(uint)) return (uint)(object)left > (uint)(object)right;
+ if (typeof(T) == typeof(int)) return (int)(object)left > (int)(object)right;
+ if (typeof(T) == typeof(ulong)) return (ulong)(object)left > (ulong)(object)right;
+ if (typeof(T) == typeof(long)) return (long)(object)left > (long)(object)right;
+ if (typeof(T) == typeof(nuint)) return (nuint)(object)left > (nuint)(object)right;
+ if (typeof(T) == typeof(nint)) return (nint)(object)left > (nint)(object)right;
+ if (typeof(T) == typeof(float)) return (float)(object)left > (float)(object)right;
+ if (typeof(T) == typeof(double)) return (double)(object)left > (double)(object)right;
+ if (typeof(T) == typeof(Half)) return (Half)(object)left > (Half)(object)right;
+ return left.CompareTo(right) > 0;
}
}
@@ -1056,44 +1055,43 @@ namespace System.Collections.Generic
// - The floating-point comparisons here assume no NaNs, which is valid only because the sorting routines
// themselves special-case NaN with a pre-pass that ensures none are present in the values being sorted
// by moving them all to the front first and then sorting the rest.
- // - The `? true : false` is to work-around poor codegen: https://github.com/dotnet/runtime/issues/37904#issuecomment-644180265.
// - These are duplicated here rather than being on a helper type due to current limitations around generic inlining.
[MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call
private static bool LessThan(ref TKey left, ref TKey right)
{
- if (typeof(TKey) == typeof(byte)) return (byte)(object)left < (byte)(object)right ? true : false;
- if (typeof(TKey) == typeof(sbyte)) return (sbyte)(object)left < (sbyte)(object)right ? true : false;
- if (typeof(TKey) == typeof(ushort)) return (ushort)(object)left < (ushort)(object)right ? true : false;
- if (typeof(TKey) == typeof(short)) return (short)(object)left < (short)(object)right ? true : false;
- if (typeof(TKey) == typeof(uint)) return (uint)(object)left < (uint)(object)right ? true : false;
- if (typeof(TKey) == typeof(int)) return (int)(object)left < (int)(object)right ? true : false;
- if (typeof(TKey) == typeof(ulong)) return (ulong)(object)left < (ulong)(object)right ? true : false;
- if (typeof(TKey) == typeof(long)) return (long)(object)left < (long)(object)right ? true : false;
- if (typeof(TKey) == typeof(nuint)) return (nuint)(object)left < (nuint)(object)right ? true : false;
- if (typeof(TKey) == typeof(nint)) return (nint)(object)left < (nint)(object)right ? true : false;
- if (typeof(TKey) == typeof(float)) return (float)(object)left < (float)(object)right ? true : false;
- if (typeof(TKey) == typeof(double)) return (double)(object)left < (double)(object)right ? true : false;
- if (typeof(TKey) == typeof(Half)) return (Half)(object)left < (Half)(object)right ? true : false;
+ if (typeof(TKey) == typeof(byte)) return (byte)(object)left < (byte)(object)right;
+ if (typeof(TKey) == typeof(sbyte)) return (sbyte)(object)left < (sbyte)(object)right;
+ if (typeof(TKey) == typeof(ushort)) return (ushort)(object)left < (ushort)(object)right;
+ if (typeof(TKey) == typeof(short)) return (short)(object)left < (short)(object)right;
+ if (typeof(TKey) == typeof(uint)) return (uint)(object)left < (uint)(object)right;
+ if (typeof(TKey) == typeof(int)) return (int)(object)left < (int)(object)right;
+ if (typeof(TKey) == typeof(ulong)) return (ulong)(object)left < (ulong)(object)right;
+ if (typeof(TKey) == typeof(long)) return (long)(object)left < (long)(object)right;
+ if (typeof(TKey) == typeof(nuint)) return (nuint)(object)left < (nuint)(object)right;
+ if (typeof(TKey) == typeof(nint)) return (nint)(object)left < (nint)(object)right;
+ if (typeof(TKey) == typeof(float)) return (float)(object)left < (float)(object)right;
+ if (typeof(TKey) == typeof(double)) return (double)(object)left < (double)(object)right;
+ if (typeof(TKey) == typeof(Half)) return (Half)(object)left < (Half)(object)right;
return left.CompareTo(right) < 0 ? true : false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call
private static bool GreaterThan(ref TKey left, ref TKey right)
{
- if (typeof(TKey) == typeof(byte)) return (byte)(object)left > (byte)(object)right ? true : false;
- if (typeof(TKey) == typeof(sbyte)) return (sbyte)(object)left > (sbyte)(object)right ? true : false;
- if (typeof(TKey) == typeof(ushort)) return (ushort)(object)left > (ushort)(object)right ? true : false;
- if (typeof(TKey) == typeof(short)) return (short)(object)left > (short)(object)right ? true : false;
- if (typeof(TKey) == typeof(uint)) return (uint)(object)left > (uint)(object)right ? true : false;
- if (typeof(TKey) == typeof(int)) return (int)(object)left > (int)(object)right ? true : false;
- if (typeof(TKey) == typeof(ulong)) return (ulong)(object)left > (ulong)(object)right ? true : false;
- if (typeof(TKey) == typeof(long)) return (long)(object)left > (long)(object)right ? true : false;
- if (typeof(TKey) == typeof(nuint)) return (nuint)(object)left > (nuint)(object)right ? true : false;
- if (typeof(TKey) == typeof(nint)) return (nint)(object)left > (nint)(object)right ? true : false;
- if (typeof(TKey) == typeof(float)) return (float)(object)left > (float)(object)right ? true : false;
- if (typeof(TKey) == typeof(double)) return (double)(object)left > (double)(object)right ? true : false;
- if (typeof(TKey) == typeof(Half)) return (Half)(object)left > (Half)(object)right ? true : false;
+ if (typeof(TKey) == typeof(byte)) return (byte)(object)left > (byte)(object)right;
+ if (typeof(TKey) == typeof(sbyte)) return (sbyte)(object)left > (sbyte)(object)right;
+ if (typeof(TKey) == typeof(ushort)) return (ushort)(object)left > (ushort)(object)right;
+ if (typeof(TKey) == typeof(short)) return (short)(object)left > (short)(object)right;
+ if (typeof(TKey) == typeof(uint)) return (uint)(object)left > (uint)(object)right;
+ if (typeof(TKey) == typeof(int)) return (int)(object)left > (int)(object)right;
+ if (typeof(TKey) == typeof(ulong)) return (ulong)(object)left > (ulong)(object)right;
+ if (typeof(TKey) == typeof(long)) return (long)(object)left > (long)(object)right;
+ if (typeof(TKey) == typeof(nuint)) return (nuint)(object)left > (nuint)(object)right;
+ if (typeof(TKey) == typeof(nint)) return (nint)(object)left > (nint)(object)right;
+ if (typeof(TKey) == typeof(float)) return (float)(object)left > (float)(object)right;
+ if (typeof(TKey) == typeof(double)) return (double)(object)left > (double)(object)right;
+ if (typeof(TKey) == typeof(Half)) return (Half)(object)left > (Half)(object)right;
return left.CompareTo(right) > 0 ? true : false;
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
index b924c55c601..2ae4a31496c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
@@ -1605,8 +1605,7 @@ namespace System
}
if ((year & 3) != 0) return false;
if ((year & 15) == 0) return true;
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (uint)year % 25 != 0 ? true : false;
+ return (uint)year % 25 != 0;
}
// Constructs a DateTime from a string. The string must specify a
diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs
index 9f22b48fde7..b9cb7624fc6 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs
@@ -93,7 +93,6 @@ namespace System
return newDelegate;
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Delegate? d1, Delegate? d2)
{
@@ -101,14 +100,12 @@ namespace System
// so it can become a simple test
if (d2 is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (d1 is null) ? true : false;
+ return d1 is null;
}
return ReferenceEquals(d2, d1) ? true : d2.Equals((object?)d1);
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Delegate? d1, Delegate? d2)
{
@@ -116,8 +113,7 @@ namespace System
// so it can become a simple test
if (d2 is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (d1 is null) ? false : true;
+ return d1 is not null;
}
return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs
index 675e83fe050..d6212cd0bcf 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs
@@ -7,6 +7,7 @@ namespace System.Diagnostics
// hardware supports it. Otherwise, the class will fall back to DateTime
// and uses ticks as a measurement.
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
public partial class Stopwatch
{
private const long TicksPerMillisecond = 10000;
@@ -150,5 +151,7 @@ namespace System.Diagnostics
// convert high resolution perf counter to DateTime ticks
return unchecked((long)(GetRawElapsedTicks() * s_tickFrequency));
}
+
+ private string DebuggerDisplay => $"{Elapsed} (IsRunning = {_isRunning})";
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs
index 90512ca598b..92af242c4df 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs
@@ -1,13 +1,124 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.IO;
+using System.Threading;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
+using NSSearchPathDirectory = Interop.Sys.NSSearchPathDirectory;
namespace System
{
public static partial class Environment
{
+#if !TARGET_MACCATALYST
// iOS/tvOS aren't allowed to call libproc APIs so return 0 here, this also matches what we returned in earlier releases
public static long WorkingSet => 0;
+#endif
+
+ private static Dictionary<SpecialFolder, string>? s_specialFolders;
+
+ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option)
+ {
+ if (s_specialFolders == null)
+ {
+ Interlocked.CompareExchange(ref s_specialFolders, new Dictionary<SpecialFolder, string>(), null);
+ }
+
+ string? path;
+ lock (s_specialFolders)
+ {
+ if (!s_specialFolders.TryGetValue(folder, out path))
+ {
+ path = GetSpecialFolder(folder) ?? string.Empty;
+ s_specialFolders[folder] = path;
+ }
+ }
+ return path;
+ }
+
+ private static string? GetSpecialFolder(SpecialFolder folder)
+ {
+ switch (folder)
+ {
+ case SpecialFolder.Personal:
+ case SpecialFolder.LocalApplicationData:
+ return CombineDocumentDirectory(string.Empty);
+
+ case SpecialFolder.ApplicationData:
+ // note: at first glance that looked like a good place to return NSLibraryDirectory
+ // but it would break isolated storage for existing applications
+ return CombineDocumentDirectory(".config");
+
+ case SpecialFolder.Resources:
+ return Interop.Sys.SearchPath(NSSearchPathDirectory.NSLibraryDirectory); // older (8.2 and previous) would return String.Empty
+
+ case SpecialFolder.Desktop:
+ case SpecialFolder.DesktopDirectory:
+ return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Desktop");
+
+ case SpecialFolder.MyMusic:
+ return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Music");
+
+ case SpecialFolder.MyPictures:
+ return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Pictures");
+
+ case SpecialFolder.Templates:
+ return CombineDocumentDirectory("Templates");
+
+ case SpecialFolder.MyVideos:
+ return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos");
+
+ case SpecialFolder.CommonTemplates:
+ return "/usr/share/templates";
+
+ case SpecialFolder.Fonts:
+ return CombineDocumentDirectory(".fonts");
+
+ case SpecialFolder.Favorites:
+ return CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, "Favorites");
+
+ case SpecialFolder.ProgramFiles:
+ return Interop.Sys.SearchPath(NSSearchPathDirectory.NSApplicationDirectory);
+
+ case SpecialFolder.InternetCache:
+ return Interop.Sys.SearchPath(NSSearchPathDirectory.NSCachesDirectory);
+
+ case SpecialFolder.UserProfile:
+ return GetEnvironmentVariable("HOME");
+
+ case SpecialFolder.CommonApplicationData:
+ return "/usr/share";
+
+ default:
+ return string.Empty;
+ }
+
+ static string CombineSearchPath(NSSearchPathDirectory searchPath, string subdirectory)
+ {
+ string? path = Interop.Sys.SearchPath(searchPath);
+ return path != null ?
+ Path.Combine(path, subdirectory) :
+ string.Empty;
+ }
+
+ static string CombineDocumentDirectory(string subdirectory)
+ {
+#if TARGET_TVOS
+ string? path = CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, Path.Combine("Caches", "Documents"));
+ // Special version of CombineSearchPath which creates the path if needed.
+ // This isn't needed for "real" search paths which always exist, but on tvOS
+ // the base path is really a subdirectory we define rather than an OS directory.
+ // In order to not treat Directory.Exists(SpecialFolder.ApplicationData) differently
+ // on tvOS, guarantee that it exists by creating it here
+ if (!Directory.Exists(path))
+ Directory.CreateDirectory(path);
+ path = Path.Combine(path, subdirectory);
+#else
+ string? path = CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, subdirectory);
+#endif
+ return path;
+ }
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Ordinal.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Ordinal.cs
index b31bb25c9e8..ef51de122f7 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/Ordinal.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/Ordinal.cs
@@ -164,9 +164,7 @@ namespace System.Globalization
return false; // not exact match, and first input isn't in [A-Za-z]
}
- // The ternary operator below seems redundant but helps RyuJIT generate more optimal code.
- // See https://github.com/dotnet/runtime/issues/4207.
- return (valueA == (valueB | 0x20u)) ? true : false;
+ return valueA == (valueB | 0x20u);
}
Debug.Assert(length == 0);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/SortVersion.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/SortVersion.cs
index 93ca171b29e..4b2cbae329b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/SortVersion.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/SortVersion.cs
@@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
namespace System.Globalization
{
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class SortVersion : IEquatable<SortVersion?>
{
private readonly int m_NlsVersion; // Do not rename (binary serialization)
@@ -59,7 +59,6 @@ namespace System.Globalization
return m_NlsVersion * 7 | m_SortId.GetHashCode();
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(SortVersion? left, SortVersion? right)
{
@@ -67,8 +66,7 @@ namespace System.Globalization
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
return right.Equals(left);
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs
index 0e64c0b4d34..751a59f9eab 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs
@@ -617,7 +617,6 @@ namespace System.IO
internal static void CreateSymbolicLink(string path, string pathToTarget, bool isDirectory)
{
- string pathToTargetFullPath = PathInternal.GetLinkTargetFullPath(path, pathToTarget);
Interop.CheckIo(Interop.Sys.SymLink(pathToTarget, path), path, isDirectory);
}
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 1d74f6e1def..d3c4ded4bdb 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs
@@ -505,7 +505,7 @@ namespace System.IO
}
}
- private void WriteFormatHelper(string format, ParamsArray args, bool appendNewLine)
+ private void WriteFormatHelper(string format, ReadOnlySpan<object?> args, bool appendNewLine)
{
int estimatedLength = (format?.Length ?? 0) + args.Length * 8;
var vsb = estimatedLength <= 256 ?
@@ -523,7 +523,7 @@ namespace System.IO
{
if (GetType() == typeof(StreamWriter))
{
- WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: false);
+ WriteFormatHelper(format, new ReadOnlySpan<object?>(in arg0), appendNewLine: false);
}
else
{
@@ -535,7 +535,8 @@ namespace System.IO
{
if (GetType() == typeof(StreamWriter))
{
- WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: false);
+ TwoObjects two = new TwoObjects(arg0, arg1);
+ WriteFormatHelper(format, MemoryMarshal.CreateReadOnlySpan(ref two.Arg0, 2), appendNewLine: false);
}
else
{
@@ -547,7 +548,8 @@ namespace System.IO
{
if (GetType() == typeof(StreamWriter))
{
- WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: false);
+ ThreeObjects three = new ThreeObjects(arg0, arg1, arg2);
+ WriteFormatHelper(format, MemoryMarshal.CreateReadOnlySpan(ref three.Arg0, 3), appendNewLine: false);
}
else
{
@@ -563,7 +565,7 @@ namespace System.IO
{
ArgumentNullException.Throw(format is null ? nameof(format) : nameof(arg)); // same as base logic
}
- WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: false);
+ WriteFormatHelper(format, arg, appendNewLine: false);
}
else
{
@@ -575,7 +577,7 @@ namespace System.IO
{
if (GetType() == typeof(StreamWriter))
{
- WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: true);
+ WriteFormatHelper(format, new ReadOnlySpan<object?>(in arg0), appendNewLine: true);
}
else
{
@@ -587,7 +589,8 @@ namespace System.IO
{
if (GetType() == typeof(StreamWriter))
{
- WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: true);
+ TwoObjects two = new TwoObjects(arg0, arg1);
+ WriteFormatHelper(format, MemoryMarshal.CreateReadOnlySpan(ref two.Arg0, 2), appendNewLine: true);
}
else
{
@@ -599,7 +602,8 @@ namespace System.IO
{
if (GetType() == typeof(StreamWriter))
{
- WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: true);
+ ThreeObjects three = new ThreeObjects(arg0, arg1, arg2);
+ WriteFormatHelper(format, MemoryMarshal.CreateReadOnlySpan(ref three.Arg0, 3), appendNewLine: true);
}
else
{
@@ -612,7 +616,7 @@ namespace System.IO
if (GetType() == typeof(StreamWriter))
{
ArgumentNullException.ThrowIfNull(arg);
- WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: true);
+ WriteFormatHelper(format, arg, appendNewLine: true);
}
else
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs
index 17ec3897a4f..b6b98837d80 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs
@@ -2724,8 +2724,7 @@ namespace System
return null;
}
- // Ternary op is a workaround for https://github.com/dotnet/runtime/issues/4207
- private static bool IsWhite(int ch) => ch == 0x20 || (uint)(ch - 0x09) <= (0x0D - 0x09) ? true : false;
+ private static bool IsWhite(int ch) => ch == 0x20 || (uint)(ch - 0x09) <= (0x0D - 0x09);
private static bool IsDigit(int ch) => ((uint)ch - '0') <= 9;
diff --git a/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs b/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs
index a995fe70be9..cc10e8b136a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs
@@ -1,75 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+// These types are temporary workarounds for an inability to stackalloc object references.
+// Once we're able to do `stackalloc object[n]`, these can be removed.
+
+// Suppress warnings for unused private fields
+#pragma warning disable CS0169
+#pragma warning disable CA1823
+#pragma warning disable IDE0051
+
namespace System
{
- internal readonly struct ParamsArray
+ internal struct TwoObjects
{
- // Sentinel fixed-length arrays eliminate the need for a "count" field keeping this
- // struct down to just 4 fields. These are only used for their "Length" property,
- // that is, their elements are never set or referenced.
- private static readonly object?[] s_oneArgArray = new object?[1];
- private static readonly object?[] s_twoArgArray = new object?[2];
- private static readonly object?[] s_threeArgArray = new object?[3];
-
- private readonly object? _arg0;
- private readonly object? _arg1;
- private readonly object? _arg2;
+ internal object? Arg0;
+ private object? _arg1;
- // After construction, the first three elements of this array will never be accessed
- // because the indexer will retrieve those values from arg0, arg1, and arg2.
- private readonly object?[] _args;
-
- public ParamsArray(object? arg0)
+ public TwoObjects(object? arg0, object? arg1)
{
- _arg0 = arg0;
- _arg1 = null;
- _arg2 = null;
-
- // Always assign this.args to make use of its "Length" property
- _args = s_oneArgArray;
- }
-
- public ParamsArray(object? arg0, object? arg1)
- {
- _arg0 = arg0;
+ Arg0 = arg0;
_arg1 = arg1;
- _arg2 = null;
-
- // Always assign this.args to make use of its "Length" property
- _args = s_twoArgArray;
}
+ }
- public ParamsArray(object? arg0, object? arg1, object? arg2)
+ internal struct ThreeObjects
+ {
+ internal object? Arg0;
+ private object? _arg1;
+ private object? _arg2;
+
+ public ThreeObjects(object? arg0, object? arg1, object? arg2)
{
- _arg0 = arg0;
+ Arg0 = arg0;
_arg1 = arg1;
_arg2 = arg2;
-
- // Always assign this.args to make use of its "Length" property
- _args = s_threeArgArray;
- }
-
- public ParamsArray(object?[] args)
- {
- int len = args.Length;
- _arg0 = len > 0 ? args[0] : null;
- _arg1 = len > 1 ? args[1] : null;
- _arg2 = len > 2 ? args[2] : null;
- _args = args;
- }
-
- public int Length => _args.Length;
-
- public object? this[int index] => index == 0 ? _arg0 : GetAtSlow(index);
-
- private object? GetAtSlow(int index)
- {
- if (index == 1)
- return _arg1;
- if (index == 2)
- return _arg2;
- return _args[index];
}
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs
index 46d61cd16d3..f6445df9671 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs
@@ -8,8 +8,8 @@ using System.Configuration.Assemblies;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Security;
-using System.Runtime.CompilerServices;
using System.Runtime.Loader;
+using System.Runtime.CompilerServices;
namespace System.Reflection
{
@@ -188,12 +188,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInfo.cs
index 178c872b34b..c4619fdead1 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInfo.cs
@@ -28,12 +28,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/EventInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/EventInfo.cs
index 02f19f16bbb..07e1f5bd15c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/EventInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/EventInfo.cs
@@ -91,12 +91,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs
index a50821d7ed0..a2090f56d48 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs
@@ -46,12 +46,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MemberInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MemberInfo.cs
index 61381b7edc8..89cc304a0ef 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MemberInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MemberInfo.cs
@@ -50,12 +50,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs
index 3c93886aa4f..36d40f1ce85 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs
@@ -70,12 +70,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs
index 7e16e554c08..5e8afa6d70e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs
@@ -45,12 +45,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Module.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Module.cs
index e3fe7fa4dde..9efb2ac1803 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Module.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Module.cs
@@ -149,12 +149,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs
index 1208a88b6b3..89f398f1f91 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs
@@ -65,12 +65,11 @@ namespace System.Reflection
// so it can become a simple test
if (right is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (left is null) ? true : false;
+ return left is null;
}
// Try fast reference equality and opposite null check prior to calling the slower virtual Equals
- if ((object?)left == (object)right)
+ if (ReferenceEquals(left, right))
{
return true;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs
index b11c5c4c181..5b52162fa14 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs
@@ -95,7 +95,7 @@ namespace System.Runtime.CompilerServices
/// <param name="fldHandle">A field handle that specifies the location of the data to be referred to by the ReadOnlySpan{T}. The Rva of the field must be aligned on a natural boundary of type T</param>
/// <returns>A ReadOnlySpan{T} of the data stored in the field</returns>
/// <exception cref="ArgumentException"><paramref name="fldHandle"/> does not refer to a field which is an Rva, is misaligned, or T is of an invalid type.</exception>
- /// <remarks>This method is intended for compiler use rather than use directly in code. T must be one of byte, sbyte, char, short, ushort, int, long, ulong, float, or double.</remarks>
+ /// <remarks>This method is intended for compiler use rather than use directly in code. T must be one of byte, sbyte, bool, char, short, ushort, int, uint, long, ulong, float, or double.</remarks>
[Intrinsic]
public static unsafe ReadOnlySpan<T> CreateSpan<T>(RuntimeFieldHandle fldHandle) => new ReadOnlySpan<T>(GetSpanDataFrom(fldHandle, typeof(T).TypeHandle, out int length), 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 7bb34a7f00c..c9ce8cd78b2 100644
--- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
@@ -436,17 +436,19 @@ namespace System
public static string Format([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0)
{
- return FormatHelper(null, format, new ParamsArray(arg0));
+ return FormatHelper(null, format, new ReadOnlySpan<object?>(in arg0));
}
public static string Format([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1)
{
- return FormatHelper(null, format, new ParamsArray(arg0, arg1));
+ TwoObjects two = new TwoObjects(arg0, arg1);
+ return FormatHelper(null, format, MemoryMarshal.CreateReadOnlySpan(ref two.Arg0, 2));
}
public static string Format([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2)
{
- return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
+ ThreeObjects three = new ThreeObjects(arg0, arg1, arg2);
+ return FormatHelper(null, format, MemoryMarshal.CreateReadOnlySpan(ref three.Arg0, 3));
}
public static string Format([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] args)
@@ -458,22 +460,24 @@ namespace System
ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args));
}
- return FormatHelper(null, format, new ParamsArray(args));
+ return FormatHelper(null, format, args);
}
public static string Format(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0)
{
- return FormatHelper(provider, format, new ParamsArray(arg0));
+ return FormatHelper(provider, format, new ReadOnlySpan<object?>(in arg0));
}
public static string Format(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1)
{
- return FormatHelper(provider, format, new ParamsArray(arg0, arg1));
+ TwoObjects two = new TwoObjects(arg0, arg1);
+ return FormatHelper(provider, format, MemoryMarshal.CreateReadOnlySpan(ref two.Arg0, 2));
}
public static string Format(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2)
{
- return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
+ ThreeObjects three = new ThreeObjects(arg0, arg1, arg2);
+ return FormatHelper(provider, format, MemoryMarshal.CreateReadOnlySpan(ref three.Arg0, 3));
}
public static string Format(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] args)
@@ -485,10 +489,10 @@ namespace System
ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args));
}
- return FormatHelper(provider, format, new ParamsArray(args));
+ return FormatHelper(provider, format, args);
}
- private static string FormatHelper(IFormatProvider? provider, string format, ParamsArray args)
+ private static string FormatHelper(IFormatProvider? provider, string format, ReadOnlySpan<object?> args)
{
ArgumentNullException.ThrowIfNull(format);
diff --git a/src/libraries/System.Private.CoreLib/src/System/String.cs b/src/libraries/System.Private.CoreLib/src/System/String.cs
index b52d632ea30..4ab552f9cc7 100644
--- a/src/libraries/System.Private.CoreLib/src/System/String.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/String.cs
@@ -485,9 +485,7 @@ namespace System
[NonVersionable]
public static bool IsNullOrEmpty([NotNullWhen(false)] string? value)
{
- // Ternary operator returning true/false prevents redundant asm generation:
- // https://github.com/dotnet/runtime/issues/4207
- return (value == null || 0 == value.Length) ? true : false;
+ return value == null || value.Length == 0;
}
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] string? value)
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 2ef8aca4a79..3b8f4624c24 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs
@@ -1410,11 +1410,22 @@ namespace System.Text
return Insert(index, value.ToString(), 1);
}
- public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0) => AppendFormatHelper(null, format, new ParamsArray(arg0));
+ public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0)
+ {
+ return AppendFormatHelper(null, format, new ReadOnlySpan<object?>(in arg0));
+ }
- public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1));
+ public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1)
+ {
+ TwoObjects two = new TwoObjects(arg0, arg1);
+ return AppendFormatHelper(null, format, MemoryMarshal.CreateReadOnlySpan(ref two.Arg0, 2));
+ }
- public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
+ 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, MemoryMarshal.CreateReadOnlySpan(ref three.Arg0, 3));
+ }
public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] args)
{
@@ -1425,14 +1436,25 @@ namespace System.Text
ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args));
}
- return AppendFormatHelper(null, format, new ParamsArray(args));
+ return AppendFormatHelper(null, format, args);
}
- public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0) => AppendFormatHelper(provider, format, new ParamsArray(arg0));
+ public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0)
+ {
+ return AppendFormatHelper(provider, format, new ReadOnlySpan<object?>(in arg0));
+ }
- public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1));
+ public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1)
+ {
+ TwoObjects two = new TwoObjects(arg0, arg1);
+ return AppendFormatHelper(provider, format, MemoryMarshal.CreateReadOnlySpan(ref two.Arg0, 2));
+ }
- public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
+ 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, MemoryMarshal.CreateReadOnlySpan(ref three.Arg0, 3));
+ }
public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] args)
{
@@ -1443,231 +1465,202 @@ namespace System.Text
ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args));
}
- return AppendFormatHelper(provider, format, new ParamsArray(args));
+ return AppendFormatHelper(provider, format, args);
}
- private static void FormatError()
- {
- throw new FormatException(SR.Format_InvalidString);
- }
-
- // Undocumented exclusive limits on the range for Argument Hole Index and Argument Hole Alignment.
- private const int IndexLimit = 1000000; // Note: 0 <= ArgIndex < IndexLimit
- private const int WidthLimit = 1000000; // Note: -WidthLimit < ArgAlign < WidthLimit
-
- internal StringBuilder AppendFormatHelper(IFormatProvider? provider, string format, ParamsArray args)
+ internal StringBuilder AppendFormatHelper(IFormatProvider? provider, string format, ReadOnlySpan<object?> args)
{
ArgumentNullException.ThrowIfNull(format);
- int pos = 0;
- int len = format.Length;
- char ch = '\x0';
+ // Undocumented exclusive limits on the range for Argument Hole Index and Argument Hole Alignment.
+ const int IndexLimit = 1_000_000; // Note: 0 <= ArgIndex < IndexLimit
+ const int WidthLimit = 1_000_000; // Note: -WidthLimit < ArgAlign < WidthLimit
- ICustomFormatter? cf = null;
- if (provider != null)
- {
- cf = (ICustomFormatter?)provider.GetFormat(typeof(ICustomFormatter));
- }
+ // Query the provider (if one was supplied) for an ICustomFormatter. If there is one,
+ // it needs to be used to transform all arguments.
+ ICustomFormatter? cf = (ICustomFormatter?)provider?.GetFormat(typeof(ICustomFormatter));
+ // Repeatedly find the next hole and process it.
+ int pos = 0;
+ char ch;
while (true)
{
- while (pos < len)
+ // Skip until either the end of the input or the first unescaped opening brace, whichever comes first.
+ // Along the way we need to also unescape escaped closing braces.
+ while (true)
{
- ch = format[pos];
-
- pos++;
- // Is it a closing brace?
- if (ch == '}')
+ // Find the next brace. If there isn't one, the remainder of the input is text to be appended, and we're done.
+ if ((uint)pos >= (uint)format.Length)
{
- // Check next character (if there is one) to see if it is escaped. eg }}
- if (pos < len && format[pos] == '}')
- {
- pos++;
- }
- else
- {
- // Otherwise treat it as an error (Mismatched closing brace)
- FormatError();
- }
+ return this;
}
- // Is it an opening brace?
- else if (ch == '{')
+
+ ReadOnlySpan<char> remainder = format.AsSpan(pos);
+ int countUntilNextBrace = remainder.IndexOfAny('{', '}');
+ if (countUntilNextBrace < 0)
{
- // Check next character (if there is one) to see if it is escaped. eg {{
- if (pos < len && format[pos] == '{')
- {
- pos++;
- }
- else
- {
- // Otherwise treat it as the opening brace of an Argument Hole.
- pos--;
- break;
- }
+ Append(remainder);
+ return this;
}
- // If it's neither then treat the character as just text.
- Append(ch);
- }
- //
- // Start of parsing of Argument Hole.
- // Argument Hole ::= { Index (, WS* Alignment WS*)? (: Formatting)? }
- //
- if (pos == len)
- {
- break;
- }
+ // Append the text until the brace.
+ Append(remainder.Slice(0, countUntilNextBrace));
+ pos += countUntilNextBrace;
- //
- // Start of parsing required Index parameter.
- // Index ::= ('0'-'9')+ WS*
- //
- pos++;
- // If reached end of text then error (Unexpected end of text)
- // or character is not a digit then error (Unexpected Character)
- if (pos == len || !char.IsAsciiDigit(ch = format[pos])) FormatError();
- int index = 0;
- do
- {
- index = index * 10 + ch - '0';
- pos++;
- // If reached end of text then error (Unexpected end of text)
- if (pos == len)
+ // Get the brace. It must be followed by another character, either a copy of itself in the case of being
+ // escaped, or an arbitrary character that's part of the hole in the case of an opening brace.
+ char brace = format[pos];
+ ch = MoveNext(format, ref pos);
+ if (brace == ch)
+ {
+ Append(ch);
+ pos++;
+ continue;
+ }
+
+ // This wasn't an escape, so it must be an opening brace.
+ if (brace != '{')
{
- FormatError();
+ ThrowHelper.ThrowFormatInvalidString();
}
- ch = format[pos];
- // so long as character is digit and value of the index is less than 1000000 ( index limit )
- }
- while (char.IsAsciiDigit(ch) && index < IndexLimit);
- // If value of index is not within the range of the arguments passed in then error (Index out of range)
- if (index >= args.Length)
- {
- throw new FormatException(SR.Format_IndexOutOfRange);
+ // Proceed to parse the hole.
+ break;
}
- // Consume optional whitespace.
- while (pos < len && (ch = format[pos]) == ' ') pos++;
- // End of parsing index parameter.
-
- //
- // Start of parsing of optional Alignment
- // Alignment ::= comma WS* minus? ('0'-'9')+ WS*
- //
- bool leftJustify = false;
+ // We're now positioned just after the opening brace of an argument hole, which consists of
+ // an opening brace, an index, an optional width preceded by a comma, and an optional format
+ // preceded by a colon, with arbitrary amounts of spaces throughout.
int width = 0;
- // Is the character a comma, which indicates the start of alignment parameter.
- if (ch == ',')
- {
- pos++;
+ bool leftJustify = false;
+ ReadOnlySpan<char> itemFormatSpan = default; // used if itemFormat is null
- // Consume Optional whitespace
- while (pos < len && format[pos] == ' ') pos++;
+ // First up is the index parameter, which is of the form:
+ // at least on digit
+ // optional any number of spaces
+ // We've already read the first digit into ch.
+ Debug.Assert(format[pos - 1] == '{');
+ Debug.Assert(ch != '{');
+ int index = ch - '0';
+ if ((uint)index >= 10u)
+ {
+ ThrowHelper.ThrowFormatInvalidString();
+ }
- // If reached the end of the text then error (Unexpected end of text)
- if (pos == len)
+ // Common case is a single digit index followed by a closing brace. If it's not a closing brace,
+ // proceed to finish parsing the full hole format.
+ ch = MoveNext(format, ref pos);
+ if (ch != '}')
+ {
+ // Continue consuming optional additional digits.
+ while (char.IsAsciiDigit(ch) && index < IndexLimit)
{
- FormatError();
+ index = index * 10 + ch - '0';
+ ch = MoveNext(format, ref pos);
}
- // Is there a minus sign?
- ch = format[pos];
- if (ch == '-')
+ // Consume optional whitespace.
+ while (ch == ' ')
{
- // Yes, then alignment is left justified.
- leftJustify = true;
- pos++;
- // If reached end of text then error (Unexpected end of text)
- if (pos == len)
- {
- FormatError();
- }
- ch = format[pos];
+ ch = MoveNext(format, ref pos);
}
- // If current character is not a digit then error (Unexpected character)
- if (!char.IsAsciiDigit(ch))
- {
- FormatError();
- }
- // Parse alignment digits.
- do
+ // Parse the optional alignment, which is of the form:
+ // comma
+ // optional any number of spaces
+ // optional -
+ // at least one digit
+ // optional any number of spaces
+ if (ch == ',')
{
- width = width * 10 + ch - '0';
- pos++;
- // If reached end of text then error. (Unexpected end of text)
- if (pos == len)
+ // Consume optional whitespace.
+ do
{
- FormatError();
+ ch = MoveNext(format, ref pos);
}
- ch = format[pos];
- // So long a current character is a digit and the value of width is less than 100000 ( width limit )
- }
- while (char.IsAsciiDigit(ch) && width < WidthLimit);
- // end of parsing Argument Alignment
- }
-
- // Consume optional whitespace
- while (pos < len && (ch = format[pos]) == ' ') pos++;
+ while (ch == ' ');
- //
- // Start of parsing of optional formatting parameter.
- //
- object? arg = args[index];
-
- ReadOnlySpan<char> itemFormatSpan = default; // used if itemFormat is null
- // Is current character a colon? which indicates start of formatting parameter.
- if (ch == ':')
- {
- pos++;
- int startPos = pos;
-
- while (true)
- {
- // If reached end of text then error. (Unexpected end of text)
- if (pos == len)
+ // Consume an optional minus sign indicating left alignment.
+ if (ch == '-')
{
- FormatError();
+ leftJustify = true;
+ ch = MoveNext(format, ref pos);
}
- ch = format[pos];
- if (ch == '}')
+ // Parse alignment digits. The read character must be a digit.
+ width = ch - '0';
+ if ((uint)width >= 10u)
{
- // Argument hole closed
- break;
+ ThrowHelper.ThrowFormatInvalidString();
}
- else if (ch == '{')
+ ch = MoveNext(format, ref pos);
+ while (char.IsAsciiDigit(ch) && width < WidthLimit)
{
- // Braces inside the argument hole are not supported
- FormatError();
+ width = width * 10 + ch - '0';
+ ch = MoveNext(format, ref pos);
}
- pos++;
+ // Consume optional whitespace
+ while (ch == ' ')
+ {
+ ch = MoveNext(format, ref pos);
+ }
}
- if (pos > startPos)
+ // The next character needs to either be a closing brace for the end of the hole,
+ // or a colon indicating the start of the format.
+ if (ch != '}')
{
- itemFormatSpan = format.AsSpan(startPos, pos - startPos);
+ if (ch != ':')
+ {
+ // Unexpected character
+ ThrowHelper.ThrowFormatInvalidString();
+ }
+
+ // Search for the closing brace; everything in between is the format,
+ // but opening braces aren't allowed.
+ int startingPos = pos;
+ while (true)
+ {
+ ch = MoveNext(format, ref pos);
+
+ if (ch == '}')
+ {
+ // Argument hole closed
+ break;
+ }
+
+ if (ch == '{')
+ {
+ // Braces inside the argument hole are not supported
+ ThrowHelper.ThrowFormatInvalidString();
+ }
+ }
+
+ startingPos++;
+ itemFormatSpan = format.AsSpan(startingPos, pos - startingPos);
}
}
- else if (ch != '}')
- {
- // Unexpected character
- FormatError();
- }
// Construct the output for this arg hole.
+ Debug.Assert(format[pos] == '}');
pos++;
string? s = null;
string? itemFormat = null;
+ if ((uint)index >= (uint)args.Length)
+ {
+ throw new FormatException(SR.Format_IndexOutOfRange);
+ }
+ object? arg = args[index];
+
if (cf != null)
{
- if (itemFormatSpan.Length != 0)
+ if (!itemFormatSpan.IsEmpty)
{
itemFormat = new string(itemFormatSpan);
}
+
s = cf.Format(itemFormat, arg, provider);
}
@@ -1684,16 +1677,15 @@ namespace System.Text
// Untrusted ISpanFormattable implementations might return an erroneous charsWritten value,
// and m_ChunkLength might end up being used in Unsafe code, so fail if we get back an
// out-of-range charsWritten value.
- FormatError();
+ ThrowHelper.ThrowFormatInvalidString();
}
m_ChunkLength += charsWritten;
// Pad the end, if needed.
- int padding = width - charsWritten;
- if (leftJustify && padding > 0)
+ if (leftJustify && width > charsWritten)
{
- Append(' ', padding);
+ Append(' ', width - charsWritten);
}
// Continue to parse other characters.
@@ -1709,30 +1701,43 @@ namespace System.Text
}
s = formattableArg.ToString(itemFormat, provider);
}
- else if (arg != null)
+ else
{
- s = arg.ToString();
+ s = arg?.ToString();
}
+
+ s ??= string.Empty;
}
+
// Append it to the final output of the Format String.
- if (s == null)
+ if (width <= s.Length)
{
- s = string.Empty;
+ Append(s);
}
- int pad = width - s.Length;
- if (!leftJustify && pad > 0)
+ else if (leftJustify)
+ {
+ Append(s);
+ Append(' ', width - s.Length);
+ }
+ else
{
- Append(' ', pad);
+ Append(' ', width - s.Length);
+ Append(s);
}
- Append(s);
- if (leftJustify && pad > 0)
+ // Continue parsing the rest of the format string.
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static char MoveNext(string format, ref int pos)
+ {
+ pos++;
+ if ((uint)pos >= (uint)format.Length)
{
- Append(' ', pad);
+ ThrowHelper.ThrowFormatInvalidString();
}
- // Continue to parse other characters.
+ return format[pos];
}
- return this;
}
/// <summary>
@@ -2633,7 +2638,7 @@ namespace System.Text
{
// Protect against faulty ISpanFormattable implementations returning invalid charsWritten values.
// Other code in _stringBuilder uses Unsafe manipulation, and we want to ensure m_ChunkLength remains safe.
- FormatError();
+ ThrowHelper.ThrowFormatInvalidString();
}
_stringBuilder.m_ChunkLength += charsWritten;
@@ -2686,7 +2691,7 @@ namespace System.Text
{
// Protect against faulty ISpanFormattable implementations returning invalid charsWritten values.
// Other code in _stringBuilder uses Unsafe manipulation, and we want to ensure m_ChunkLength remains safe.
- FormatError();
+ ThrowHelper.ThrowFormatInvalidString();
}
_stringBuilder.m_ChunkLength += charsWritten;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.AppendFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.AppendFormat.cs
index 652e73086cb..5d45f01ca76 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.AppendFormat.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.AppendFormat.cs
@@ -1,260 +1,209 @@
// 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.Text
{
internal ref partial struct ValueStringBuilder
{
- public void AppendFormat(string format, object? arg0) => AppendFormatHelper(null, format, new ParamsArray(arg0));
-
- public void AppendFormat(string format, object? arg0, object? arg1) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1));
-
- public void AppendFormat(string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
-
- public void AppendFormat(string format, params object?[] args)
- {
- 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.
- ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args));
- }
-
- AppendFormatHelper(null, format, new ParamsArray(args));
- }
-
- public void AppendFormat(IFormatProvider? provider, string format, object? arg0) => AppendFormatHelper(provider, format, new ParamsArray(arg0));
-
- public void AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1));
-
- public void AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
-
- public void AppendFormat(IFormatProvider? provider, string format, params object?[] args)
- {
- 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.
- ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args));
- }
-
- AppendFormatHelper(provider, format, new ParamsArray(args));
- }
-
// Copied from StringBuilder, can't be done via generic extension
// as ValueStringBuilder is a ref struct and cannot be used in a generic.
- internal void AppendFormatHelper(IFormatProvider? provider, string format, ParamsArray args)
+ internal void AppendFormatHelper(IFormatProvider? provider, string format, ReadOnlySpan<object?> args)
{
ArgumentNullException.ThrowIfNull(format);
// Undocumented exclusive limits on the range for Argument Hole Index and Argument Hole Alignment.
- const int IndexLimit = 1000000; // Note: 0 <= ArgIndex < IndexLimit
- const int WidthLimit = 1000000; // Note: -WidthLimit < ArgAlign < WidthLimit
+ const int IndexLimit = 1_000_000; // Note: 0 <= ArgIndex < IndexLimit
+ const int WidthLimit = 1_000_000; // Note: -WidthLimit < ArgAlign < WidthLimit
- int pos = 0;
- int len = format.Length;
- char ch = '\0';
+ // Query the provider (if one was supplied) for an ICustomFormatter. If there is one,
+ // it needs to be used to transform all arguments.
ICustomFormatter? cf = (ICustomFormatter?)provider?.GetFormat(typeof(ICustomFormatter));
+ // Repeatedly find the next hole and process it.
+ int pos = 0;
+ char ch;
while (true)
{
- while (pos < len)
+ // Skip until either the end of the input or the first unescaped opening brace, whichever comes first.
+ // Along the way we need to also unescape escaped closing braces.
+ while (true)
{
- ch = format[pos];
-
- pos++;
- // Is it a closing brace?
- if (ch == '}')
+ // Find the next brace. If there isn't one, the remainder of the input is text to be appended, and we're done.
+ if ((uint)pos >= (uint)format.Length)
{
- // Check next character (if there is one) to see if it is escaped. eg }}
- if (pos < len && format[pos] == '}')
- {
- pos++;
- }
- else
- {
- // Otherwise treat it as an error (Mismatched closing brace)
- ThrowFormatError();
- }
+ return;
}
- // Is it a opening brace?
- else if (ch == '{')
+
+ ReadOnlySpan<char> remainder = format.AsSpan(pos);
+ int countUntilNextBrace = remainder.IndexOfAny('{', '}');
+ if (countUntilNextBrace < 0)
{
- // Check next character (if there is one) to see if it is escaped. eg {{
- if (pos < len && format[pos] == '{')
- {
- pos++;
- }
- else
- {
- // Otherwise treat it as the opening brace of an Argument Hole.
- pos--;
- break;
- }
+ Append(remainder);
+ return;
}
- // If it's neither then treat the character as just text.
- Append(ch);
- }
- //
- // Start of parsing of Argument Hole.
- // Argument Hole ::= { Index (, WS* Alignment WS*)? (: Formatting)? }
- //
- if (pos == len)
- {
- break;
- }
+ // Append the text until the brace.
+ Append(remainder.Slice(0, countUntilNextBrace));
+ pos += countUntilNextBrace;
- //
- // Start of parsing required Index parameter.
- // Index ::= ('0'-'9')+ WS*
- //
- pos++;
- // If reached end of text then error (Unexpected end of text)
- // or character is not a digit then error (Unexpected Character)
- if (pos == len || !char.IsAsciiDigit(ch = format[pos])) ThrowFormatError();
- int index = 0;
- do
- {
- index = index * 10 + ch - '0';
- pos++;
- // If reached end of text then error (Unexpected end of text)
- if (pos == len)
+ // Get the brace. It must be followed by another character, either a copy of itself in the case of being
+ // escaped, or an arbitrary character that's part of the hole in the case of an opening brace.
+ char brace = format[pos];
+ ch = MoveNext(format, ref pos);
+ if (brace == ch)
{
- ThrowFormatError();
+ Append(ch);
+ pos++;
+ continue;
}
- ch = format[pos];
- // so long as character is digit and value of the index is less than 1000000 ( index limit )
- }
- while (char.IsAsciiDigit(ch) && index < IndexLimit);
- // If value of index is not within the range of the arguments passed in then error (Index out of range)
- if (index >= args.Length)
- {
- throw new FormatException(SR.Format_IndexOutOfRange);
- }
+ // This wasn't an escape, so it must be an opening brace.
+ if (brace != '{')
+ {
+ ThrowFormatInvalidString();
+ }
- // Consume optional whitespace.
- while (pos < len && (ch = format[pos]) == ' ') pos++;
- // End of parsing index parameter.
+ // Proceed to parse the hole.
+ break;
+ }
- //
- // Start of parsing of optional Alignment
- // Alignment ::= comma WS* minus? ('0'-'9')+ WS*
- //
- bool leftJustify = false;
+ // We're now positioned just after the opening brace of an argument hole, which consists of
+ // an opening brace, an index, an optional width preceded by a comma, and an optional format
+ // preceded by a colon, with arbitrary amounts of spaces throughout.
int width = 0;
- // Is the character a comma, which indicates the start of alignment parameter.
- if (ch == ',')
- {
- pos++;
+ bool leftJustify = false;
+ ReadOnlySpan<char> itemFormatSpan = default; // used if itemFormat is null
- // Consume Optional whitespace
- while (pos < len && format[pos] == ' ') pos++;
+ // First up is the index parameter, which is of the form:
+ // at least on digit
+ // optional any number of spaces
+ // We've already read the first digit into ch.
+ Debug.Assert(format[pos - 1] == '{');
+ Debug.Assert(ch != '{');
+ int index = ch - '0';
+ if ((uint)index >= 10u)
+ {
+ ThrowFormatInvalidString();
+ }
- // If reached the end of the text then error (Unexpected end of text)
- if (pos == len)
+ // Common case is a single digit index followed by a closing brace. If it's not a closing brace,
+ // proceed to finish parsing the full hole format.
+ ch = MoveNext(format, ref pos);
+ if (ch != '}')
+ {
+ // Continue consuming optional additional digits.
+ while (char.IsAsciiDigit(ch) && index < IndexLimit)
{
- ThrowFormatError();
+ index = index * 10 + ch - '0';
+ ch = MoveNext(format, ref pos);
}
- // Is there a minus sign?
- ch = format[pos];
- if (ch == '-')
+ // Consume optional whitespace.
+ while (ch == ' ')
{
- // Yes, then alignment is left justified.
- leftJustify = true;
- pos++;
- // If reached end of text then error (Unexpected end of text)
- if (pos == len)
- {
- ThrowFormatError();
- }
- ch = format[pos];
+ ch = MoveNext(format, ref pos);
}
- // If current character is not a digit then error (Unexpected character)
- if (!char.IsAsciiDigit(ch))
- {
- ThrowFormatError();
- }
- // Parse alignment digits.
- do
+ // Parse the optional alignment, which is of the form:
+ // comma
+ // optional any number of spaces
+ // optional -
+ // at least one digit
+ // optional any number of spaces
+ if (ch == ',')
{
- width = width * 10 + ch - '0';
- pos++;
- // If reached end of text then error. (Unexpected end of text)
- if (pos == len)
+ // Consume optional whitespace.
+ do
{
- ThrowFormatError();
+ ch = MoveNext(format, ref pos);
}
- ch = format[pos];
- // So long a current character is a digit and the value of width is less than 100000 ( width limit )
- }
- while (char.IsAsciiDigit(ch) && width < WidthLimit);
- // end of parsing Argument Alignment
- }
-
- // Consume optional whitespace
- while (pos < len && (ch = format[pos]) == ' ') pos++;
-
- //
- // Start of parsing of optional formatting parameter.
- //
- object? arg = args[index];
-
- ReadOnlySpan<char> itemFormatSpan = default; // used if itemFormat is null
- // Is current character a colon? which indicates start of formatting parameter.
- if (ch == ':')
- {
- pos++;
- int startPos = pos;
+ while (ch == ' ');
- while (true)
- {
- // If reached end of text then error. (Unexpected end of text)
- if (pos == len)
+ // Consume an optional minus sign indicating left alignment.
+ if (ch == '-')
{
- ThrowFormatError();
+ leftJustify = true;
+ ch = MoveNext(format, ref pos);
}
- ch = format[pos];
- if (ch == '}')
+ // Parse alignment digits. The read character must be a digit.
+ width = ch - '0';
+ if ((uint)width >= 10u)
{
- // Argument hole closed
- break;
+ ThrowFormatInvalidString();
}
- else if (ch == '{')
+ ch = MoveNext(format, ref pos);
+ while (char.IsAsciiDigit(ch) && width < WidthLimit)
{
- // Braces inside the argument hole are not supported
- ThrowFormatError();
+ width = width * 10 + ch - '0';
+ ch = MoveNext(format, ref pos);
}
- pos++;
+ // Consume optional whitespace
+ while (ch == ' ')
+ {
+ ch = MoveNext(format, ref pos);
+ }
}
- if (pos > startPos)
+ // The next character needs to either be a closing brace for the end of the hole,
+ // or a colon indicating the start of the format.
+ if (ch != '}')
{
- itemFormatSpan = format.AsSpan(startPos, pos - startPos);
+ if (ch != ':')
+ {
+ // Unexpected character
+ ThrowFormatInvalidString();
+ }
+
+ // Search for the closing brace; everything in between is the format,
+ // but opening braces aren't allowed.
+ int startingPos = pos;
+ while (true)
+ {
+ ch = MoveNext(format, ref pos);
+
+ if (ch == '}')
+ {
+ // Argument hole closed
+ break;
+ }
+
+ if (ch == '{')
+ {
+ // Braces inside the argument hole are not supported
+ ThrowFormatInvalidString();
+ }
+ }
+
+ startingPos++;
+ itemFormatSpan = format.AsSpan(startingPos, pos - startingPos);
}
}
- else if (ch != '}')
- {
- // Unexpected character
- ThrowFormatError();
- }
// Construct the output for this arg hole.
+ Debug.Assert(format[pos] == '}');
pos++;
string? s = null;
string? itemFormat = null;
+ if ((uint)index >= (uint)args.Length)
+ {
+ throw new FormatException(SR.Format_IndexOutOfRange);
+ }
+ object? arg = args[index];
+
if (cf != null)
{
- if (itemFormatSpan.Length != 0)
+ if (!itemFormatSpan.IsEmpty)
{
itemFormat = new string(itemFormatSpan);
}
+
s = cf.Format(itemFormat, arg, provider);
}
@@ -269,10 +218,9 @@ namespace System.Text
_pos += charsWritten;
// Pad the end, if needed.
- int padding = width - charsWritten;
- if (leftJustify && padding > 0)
+ if (leftJustify && width > charsWritten)
{
- Append(' ', padding);
+ Append(' ', width - charsWritten);
}
// Continue to parse other characters.
@@ -288,34 +236,45 @@ namespace System.Text
}
s = formattableArg.ToString(itemFormat, provider);
}
- else if (arg != null)
+ else
{
- s = arg.ToString();
+ s = arg?.ToString();
}
+
+ s ??= string.Empty;
}
+
// Append it to the final output of the Format String.
- if (s == null)
+ if (width <= s.Length)
+ {
+ Append(s);
+ }
+ else if (leftJustify)
{
- s = string.Empty;
+ Append(s);
+ Append(' ', width - s.Length);
}
- int pad = width - s.Length;
- if (!leftJustify && pad > 0)
+ else
{
- Append(' ', pad);
+ Append(' ', width - s.Length);
+ Append(s);
}
- Append(s);
- if (leftJustify && pad > 0)
+ // Continue parsing the rest of the format string.
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static char MoveNext(string format, ref int pos)
+ {
+ pos++;
+ if ((uint)pos >= (uint)format.Length)
{
- Append(' ', pad);
+ ThrowFormatInvalidString();
}
- // Continue to parse other characters.
+ return format[pos];
}
}
- private static void ThrowFormatError()
- {
- throw new FormatException(SR.Format_InvalidString);
- }
+ private static void ThrowFormatInvalidString() => throw new FormatException(SR.Format_InvalidString);
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs
index a51f23fadb7..bc49c5549f4 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs
@@ -387,6 +387,11 @@ namespace System.Threading
}
}
+ private const int ProcessorsPerAssignableWorkItemQueue = 16;
+ private static readonly int s_assignableWorkItemQueueCount =
+ Environment.ProcessorCount <= 32 ? 0 :
+ (Environment.ProcessorCount + (ProcessorsPerAssignableWorkItemQueue - 1)) / ProcessorsPerAssignableWorkItemQueue;
+
private bool _loggingEnabled;
private bool _dispatchNormalPriorityWorkFirst;
private int _mayHaveHighPriorityWorkItems;
@@ -395,6 +400,16 @@ namespace System.Threading
internal readonly ConcurrentQueue<object> workItems = new ConcurrentQueue<object>();
internal readonly ConcurrentQueue<object> highPriorityWorkItems = new ConcurrentQueue<object>();
+ // SOS's ThreadPool command depends on the following name. The global queue doesn't scale well beyond a point of
+ // concurrency. Some additional queues may be added and assigned to a limited number of worker threads if necessary to
+ // help with limiting the concurrency level.
+ internal readonly ConcurrentQueue<object>[] _assignableWorkItemQueues =
+ new ConcurrentQueue<object>[s_assignableWorkItemQueueCount];
+
+ private readonly LowLevelLock _queueAssignmentLock = new();
+ private readonly int[] _assignedWorkItemQueueThreadCounts =
+ s_assignableWorkItemQueueCount > 0 ? new int[s_assignableWorkItemQueueCount] : Array.Empty<int>();
+
[StructLayout(LayoutKind.Sequential)]
private struct CacheLineSeparated
{
@@ -409,9 +424,126 @@ namespace System.Threading
public ThreadPoolWorkQueue()
{
+ for (int i = 0; i < s_assignableWorkItemQueueCount; i++)
+ {
+ _assignableWorkItemQueues[i] = new ConcurrentQueue<object>();
+ }
+
RefreshLoggingEnabled();
}
+ private void AssignWorkItemQueue(ThreadPoolWorkQueueThreadLocals tl)
+ {
+ Debug.Assert(s_assignableWorkItemQueueCount > 0);
+
+ _queueAssignmentLock.Acquire();
+
+ // Determine the first queue that has not yet been assigned to the limit of worker threads
+ int queueIndex = -1;
+ int minCount = int.MaxValue;
+ int minCountQueueIndex = 0;
+ for (int i = 0; i < s_assignableWorkItemQueueCount; i++)
+ {
+ int count = _assignedWorkItemQueueThreadCounts[i];
+ Debug.Assert(count >= 0);
+ if (count < ProcessorsPerAssignableWorkItemQueue)
+ {
+ queueIndex = i;
+ _assignedWorkItemQueueThreadCounts[queueIndex] = count + 1;
+ break;
+ }
+
+ if (count < minCount)
+ {
+ minCount = count;
+ minCountQueueIndex = i;
+ }
+ }
+
+ if (queueIndex < 0)
+ {
+ // All queues have been fully assigned. Choose the queue that has been assigned to the least number of worker
+ // threads.
+ queueIndex = minCountQueueIndex;
+ _assignedWorkItemQueueThreadCounts[queueIndex]++;
+ }
+
+ _queueAssignmentLock.Release();
+
+ tl.queueIndex = queueIndex;
+ tl.assignedGlobalWorkItemQueue = _assignableWorkItemQueues[queueIndex];
+ }
+
+ private void TryReassignWorkItemQueue(ThreadPoolWorkQueueThreadLocals tl)
+ {
+ Debug.Assert(s_assignableWorkItemQueueCount > 0);
+
+ int queueIndex = tl.queueIndex;
+ if (queueIndex == 0)
+ {
+ return;
+ }
+
+ if (!_queueAssignmentLock.TryAcquire())
+ {
+ return;
+ }
+
+ // If the currently assigned queue is assigned to other worker threads, try to reassign an earlier queue to this
+ // worker thread if the earlier queue is not assigned to the limit of worker threads
+ Debug.Assert(_assignedWorkItemQueueThreadCounts[queueIndex] >= 0);
+ if (_assignedWorkItemQueueThreadCounts[queueIndex] > 1)
+ {
+ for (int i = 0; i < queueIndex; i++)
+ {
+ if (_assignedWorkItemQueueThreadCounts[i] < ProcessorsPerAssignableWorkItemQueue)
+ {
+ _assignedWorkItemQueueThreadCounts[queueIndex]--;
+ queueIndex = i;
+ _assignedWorkItemQueueThreadCounts[queueIndex]++;
+ break;
+ }
+ }
+ }
+
+ _queueAssignmentLock.Release();
+
+ tl.queueIndex = queueIndex;
+ tl.assignedGlobalWorkItemQueue = _assignableWorkItemQueues[queueIndex];
+ }
+
+ private void UnassignWorkItemQueue(ThreadPoolWorkQueueThreadLocals tl)
+ {
+ Debug.Assert(s_assignableWorkItemQueueCount > 0);
+
+ int queueIndex = tl.queueIndex;
+
+ _queueAssignmentLock.Acquire();
+ int newCount = --_assignedWorkItemQueueThreadCounts[queueIndex];
+ _queueAssignmentLock.Release();
+
+ Debug.Assert(newCount >= 0);
+ if (newCount > 0)
+ {
+ return;
+ }
+
+ // This queue is not assigned to any other worker threads. Move its work items to the global queue to prevent them
+ // from being starved for a long duration.
+ bool movedWorkItem = false;
+ ConcurrentQueue<object> queue = tl.assignedGlobalWorkItemQueue;
+ while (_assignedWorkItemQueueThreadCounts[queueIndex] <= 0 && queue.TryDequeue(out object? workItem))
+ {
+ workItems.Enqueue(workItem);
+ movedWorkItem = true;
+ }
+
+ if (movedWorkItem)
+ {
+ EnsureThreadRequested();
+ }
+ }
+
public ThreadPoolWorkQueueThreadLocals GetOrCreateThreadLocals() =>
ThreadPoolWorkQueueThreadLocals.threadLocals ?? CreateThreadLocals();
@@ -479,7 +611,11 @@ namespace System.Threading
}
else
{
- workItems.Enqueue(callback);
+ ConcurrentQueue<object> queue =
+ s_assignableWorkItemQueueCount > 0 && (tl = ThreadPoolWorkQueueThreadLocals.threadLocals) != null
+ ? tl.assignedGlobalWorkItemQueue
+ : workItems;
+ queue.Enqueue(callback);
}
EnsureThreadRequested();
@@ -533,32 +669,53 @@ namespace System.Threading
return workItem;
}
- // Check for global work items
+ // Check for work items from the assigned global queue
+ if (s_assignableWorkItemQueueCount > 0 && tl.assignedGlobalWorkItemQueue.TryDequeue(out workItem))
+ {
+ return workItem;
+ }
+
+ // Check for work items from the global queue
if (workItems.TryDequeue(out workItem))
{
return workItem;
}
- // Try to steal from other threads' local work items
- WorkStealingQueue localWsq = tl.workStealingQueue;
- WorkStealingQueue[] queues = WorkStealingQueueList.Queues;
- int c = queues.Length;
- Debug.Assert(c > 0, "There must at least be a queue for this thread.");
- int maxIndex = c - 1;
- uint i = tl.random.NextUInt32() % (uint)c;
- while (c > 0)
+ // Check for work items in other assignable global queues
+ uint randomValue = tl.random.NextUInt32();
+ if (s_assignableWorkItemQueueCount > 0)
{
- i = (i < maxIndex) ? i + 1 : 0;
- WorkStealingQueue otherQueue = queues[i];
- if (otherQueue != localWsq && otherQueue.CanSteal)
+ int queueIndex = tl.queueIndex;
+ int c = s_assignableWorkItemQueueCount;
+ int maxIndex = c - 1;
+ for (int i = (int)(randomValue % (uint)c); c > 0; i = i < maxIndex ? i + 1 : 0, c--)
{
- workItem = otherQueue.TrySteal(ref missedSteal);
- if (workItem != null)
+ if (i != queueIndex && _assignableWorkItemQueues[i].TryDequeue(out workItem))
{
return workItem;
}
}
- c--;
+ }
+
+ // Try to steal from other threads' local work items
+ {
+ WorkStealingQueue localWsq = tl.workStealingQueue;
+ WorkStealingQueue[] queues = WorkStealingQueueList.Queues;
+ int c = queues.Length;
+ Debug.Assert(c > 0, "There must at least be a queue for this thread.");
+ int maxIndex = c - 1;
+ for (int i = (int)(randomValue % (uint)c); c > 0; i = i < maxIndex ? i + 1 : 0, c--)
+ {
+ WorkStealingQueue otherQueue = queues[i];
+ if (otherQueue != localWsq && otherQueue.CanSteal)
+ {
+ workItem = otherQueue.TrySteal(ref missedSteal);
+ if (workItem != null)
+ {
+ return workItem;
+ }
+ }
+ }
}
return null;
@@ -594,7 +751,19 @@ namespace System.Threading
}
}
- public long GlobalCount => (long)highPriorityWorkItems.Count + workItems.Count;
+ public long GlobalCount
+ {
+ get
+ {
+ long count = (long)highPriorityWorkItems.Count + workItems.Count;
+ for (int i = 0; i < s_assignableWorkItemQueueCount; i++)
+ {
+ count += _assignableWorkItemQueues[i].Count;
+ }
+
+ return count;
+ }
+ }
// Time in ms for which ThreadPoolWorkQueue.Dispatch keeps executing normal work items before either returning from
// Dispatch (if YieldFromDispatchLoop is true), or performing periodic activities
@@ -612,6 +781,11 @@ namespace System.Threading
ThreadPoolWorkQueue workQueue = ThreadPool.s_workQueue;
ThreadPoolWorkQueueThreadLocals tl = workQueue.GetOrCreateThreadLocals();
+ if (s_assignableWorkItemQueueCount > 0)
+ {
+ workQueue.AssignWorkItemQueue(tl);
+ }
+
// Before dequeuing the first work item, acknowledge that the thread request has been satisfied
workQueue.MarkThreadRequestSatisfied();
@@ -625,7 +799,12 @@ namespace System.Threading
if (dispatchNormalPriorityWorkFirst && !tl.workStealingQueue.CanSteal)
{
workQueue._dispatchNormalPriorityWorkFirst = !dispatchNormalPriorityWorkFirst;
- workQueue.workItems.TryDequeue(out workItem);
+ ConcurrentQueue<object> queue =
+ s_assignableWorkItemQueueCount > 0 ? tl.assignedGlobalWorkItemQueue : workQueue.workItems;
+ if (!queue.TryDequeue(out workItem) && s_assignableWorkItemQueueCount > 0)
+ {
+ workQueue.workItems.TryDequeue(out workItem);
+ }
}
if (workItem == null)
@@ -635,6 +814,11 @@ namespace System.Threading
if (workItem == null)
{
+ if (s_assignableWorkItemQueueCount > 0)
+ {
+ workQueue.UnassignWorkItemQueue(tl);
+ }
+
//
// No work.
// If we missed a steal, though, there may be more work in the queue.
@@ -689,6 +873,11 @@ namespace System.Threading
if (workItem == null)
{
+ if (s_assignableWorkItemQueueCount > 0)
+ {
+ workQueue.UnassignWorkItemQueue(tl);
+ }
+
//
// No work.
// If we missed a steal, though, there may be more work in the queue.
@@ -753,6 +942,10 @@ namespace System.Threading
// processing work items.
tl.TransferLocalWork();
tl.isProcessingHighPriorityWorkItems = false;
+ if (s_assignableWorkItemQueueCount > 0)
+ {
+ workQueue.UnassignWorkItemQueue(tl);
+ }
return false;
}
@@ -769,9 +962,20 @@ namespace System.Threading
// The runtime-specific thread pool implementation requires the Dispatch loop to return to the VM
// periodically to let it perform its own work
tl.isProcessingHighPriorityWorkItems = false;
+ if (s_assignableWorkItemQueueCount > 0)
+ {
+ workQueue.UnassignWorkItemQueue(tl);
+ }
return true;
}
+ if (s_assignableWorkItemQueueCount > 0)
+ {
+ // Due to hill climbing, over time arbitrary worker threads may stop working and eventually unbalance the
+ // queue assignments. Periodically try to reassign a queue to keep the assigned queues busy.
+ workQueue.TryReassignWorkItemQueue(tl);
+ }
+
// This method will continue to dispatch work items. Refresh the start tick count for the next dispatch
// quantum and do some periodic activities.
startTickCount = currentTickCount;
@@ -823,6 +1027,8 @@ namespace System.Threading
public static ThreadPoolWorkQueueThreadLocals? threadLocals;
public bool isProcessingHighPriorityWorkItems;
+ public int queueIndex;
+ public ConcurrentQueue<object> assignedGlobalWorkItemQueue;
public readonly ThreadPoolWorkQueue workQueue;
public readonly ThreadPoolWorkQueue.WorkStealingQueue workStealingQueue;
public readonly Thread currentThread;
@@ -831,6 +1037,7 @@ namespace System.Threading
public ThreadPoolWorkQueueThreadLocals(ThreadPoolWorkQueue tpq)
{
+ assignedGlobalWorkItemQueue = tpq.workItems;
workQueue = tpq;
workStealingQueue = new ThreadPoolWorkQueue.WorkStealingQueue();
ThreadPoolWorkQueue.WorkStealingQueueList.Add(workStealingQueue);
@@ -1404,6 +1611,15 @@ namespace System.Threading
yield return workItem;
}
+ // Enumerate assignable global queues
+ foreach (ConcurrentQueue<object> queue in s_workQueue._assignableWorkItemQueues)
+ {
+ foreach (object workItem in queue)
+ {
+ yield return workItem;
+ }
+ }
+
// Enumerate global queue
foreach (object workItem in s_workQueue.workItems)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs
index 6185cf65dd3..a2db43c9ca0 100644
--- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs
@@ -562,6 +562,12 @@ namespace System
throw ex;
}
+ [DoesNotReturn]
+ internal static void ThrowFormatInvalidString()
+ {
+ throw new FormatException(SR.Format_InvalidString);
+ }
+
private static Exception GetArraySegmentCtorValidationFailedException(Array? array, int offset, int count)
{
if (array == null)
diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs
index e1dc5f1434e..3426ac0ce25 100644
--- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs
@@ -5,8 +5,9 @@ using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
-using System.Text;
+using System.Runtime.InteropServices;
using System.Security;
+using System.Text;
using Microsoft.Win32.SafeHandles;
namespace System
@@ -382,6 +383,13 @@ namespace System
/// <summary>
/// Gets the tzfile raw data for the current 'local' time zone using the following rules.
+ ///
+ /// On iOS / tvOS
+ /// 1. Read the TZ environment variable. If it is set, use it.
+ /// 2. Get the default TZ from the device
+ /// 3. Use UTC if all else fails.
+ ///
+ /// On all other platforms
/// 1. Read the TZ environment variable. If it is set, use it.
/// 2. Look for the data in /etc/localtime.
/// 3. Look for the data in GetTimeZoneDirectory()/localtime.
@@ -393,16 +401,21 @@ namespace System
id = null;
string? tzVariable = GetTzEnvironmentVariable();
- // If the env var is null, use the localtime file
+ // If the env var is null, on iOS/tvOS, grab the default tz from the device.
+ // On all other platforms, use the localtime file.
if (tzVariable == null)
{
+#if TARGET_IOS || TARGET_TVOS
+ tzVariable = Interop.Sys.GetDefaultTimeZone();
+#else
return
TryLoadTzFile("/etc/localtime", ref rawData, ref id) ||
TryLoadTzFile(Path.Combine(GetTimeZoneDirectory(), "localtime"), ref rawData, ref id);
+#endif
}
// If it's empty, use UTC (TryGetLocalTzFile() should return false).
- if (tzVariable.Length == 0)
+ if (string.IsNullOrEmpty(tzVariable))
{
return false;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Version.cs b/src/libraries/System.Private.CoreLib/src/System/Version.cs
index 50551dc3e39..1c7751e6f19 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Version.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Version.cs
@@ -1,11 +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.Globalization;
using System.Diagnostics;
-using System.Text;
-using System.Runtime.CompilerServices;
using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Runtime.CompilerServices;
namespace System
{
@@ -16,7 +15,7 @@ namespace System
// specified component.
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class Version : ICloneable, IComparable, IComparable<Version?>, IEquatable<Version?>, ISpanFormattable
{
// AssemblyName depends on the order staying the same
@@ -372,7 +371,6 @@ namespace System
return int.TryParse(component, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsedComponent) && parsedComponent >= 0;
}
- // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Version? v1, Version? v2)
{
@@ -380,8 +378,7 @@ namespace System
// so it can become a simple test
if (v2 is null)
{
- // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
- return (v1 is null) ? true : false;
+ return v1 is null;
}
// Quick reference equality test prior to calling the virtual Equality
diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs
index 7d9bab87855..a700b7184ef 100644
--- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs
+++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs
@@ -31,11 +31,11 @@ namespace System.Xml
// UTF-8 is fastpath, so that's how these are stored
// Compare methods adapt to Unicode.
- private static readonly byte[] s_encodingAttr = new byte[] { (byte)'e', (byte)'n', (byte)'c', (byte)'o', (byte)'d', (byte)'i', (byte)'n', (byte)'g' };
- private static readonly byte[] s_encodingUTF8 = new byte[] { (byte)'u', (byte)'t', (byte)'f', (byte)'-', (byte)'8' };
- private static readonly byte[] s_encodingUnicode = new byte[] { (byte)'u', (byte)'t', (byte)'f', (byte)'-', (byte)'1', (byte)'6' };
- private static readonly byte[] s_encodingUnicodeLE = new byte[] { (byte)'u', (byte)'t', (byte)'f', (byte)'-', (byte)'1', (byte)'6', (byte)'l', (byte)'e' };
- private static readonly byte[] s_encodingUnicodeBE = new byte[] { (byte)'u', (byte)'t', (byte)'f', (byte)'-', (byte)'1', (byte)'6', (byte)'b', (byte)'e' };
+ private static readonly byte[] s_encodingAttr = "encoding"u8.ToArray();
+ private static readonly byte[] s_encodingUTF8 = "utf-8"u8.ToArray();
+ private static readonly byte[] s_encodingUnicode = "utf-16"u8.ToArray();
+ private static readonly byte[] s_encodingUnicodeLE = "utf-16le"u8.ToArray();
+ private static readonly byte[] s_encodingUnicodeBE = "utf-16be"u8.ToArray();
private SupportedEncoding _encodingCode;
private Encoding? _encoding;
diff --git a/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/NamespaceHandlingTests.cs b/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/NamespaceHandlingTests.cs
index a1cfd7ec90b..cb6ebbe413a 100644
--- a/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/NamespaceHandlingTests.cs
+++ b/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/NamespaceHandlingTests.cs
@@ -758,7 +758,7 @@ namespace System.Xml.Tests
{
XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.NamespaceHandling = nsHandling;
- byte[] buffer = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+ byte[] buffer = "abc"u8.ToArray();
using (XmlWriter w = CreateMemWriter(utils, wSettings))
{
@@ -780,7 +780,7 @@ namespace System.Xml.Tests
{
XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.NamespaceHandling = nsHandling;
- byte[] buffer = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+ byte[] buffer = "abc"u8.ToArray();
using (XmlWriter w = CreateMemWriter(utils, wSettings))
{
@@ -803,7 +803,7 @@ namespace System.Xml.Tests
XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.NamespaceHandling = nsHandling;
XmlWriter w = CreateMemWriter(utils, wSettings);
- byte[] buffer = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+ byte[] buffer = "abc"u8.ToArray();
w.WriteStartElement("A");
w.WriteAttributeString("xmlns", "p", null, "ns1");
diff --git a/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderReadTests.cs b/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderReadTests.cs
index c6907131729..8365c4cd27c 100644
--- a/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderReadTests.cs
+++ b/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderReadTests.cs
@@ -153,7 +153,7 @@ namespace System.Xml.Tests
[Fact]
public void NodeReaderReadContentAsBase64WithSimpleXml()
{
- byte[] byteData = Encoding.ASCII.GetBytes("hello world");
+ byte[] byteData = "hello world"u8.ToArray();
string xml = $"<root attr='{Convert.ToBase64String(byteData)}'><child /></root>"; //hello world encoded
XmlNodeReader nodeReader = NodeReaderTestHelper.CreateNodeReader(xml);
Assert.True(nodeReader.Read());
@@ -179,7 +179,7 @@ namespace System.Xml.Tests
[Fact]
public void NodeReaderReadContentAsBinHexWithSimpleXml()
{
- byte[] byteData = Encoding.ASCII.GetBytes("hello world");
+ byte[] byteData = "hello world"u8.ToArray();
string xml = $"<root attr='{BitConverter.ToString(byteData).Replace("-", "")}'><child /></root>";
XmlNodeReader nodeReader = NodeReaderTestHelper.CreateNodeReader(xml);
Assert.True(nodeReader.Read());
@@ -205,7 +205,7 @@ namespace System.Xml.Tests
[Fact]
public void NodeReaderReadElementContentAsBase64WithSimpleXml()
{
- byte[] byteData = Encoding.ASCII.GetBytes("hello world");
+ byte[] byteData = "hello world"u8.ToArray();
string xml = $"<root attr='val'>{Convert.ToBase64String(byteData)}</root>"; //hello world encoded
XmlNodeReader nodeReader = NodeReaderTestHelper.CreateNodeReader(xml);
Assert.True(nodeReader.Read());
@@ -229,7 +229,7 @@ namespace System.Xml.Tests
[Fact]
public void NodeReaderReadElementContentAsBinHexWithSimpleXml()
{
- byte[] byteData = Encoding.ASCII.GetBytes("hello world");
+ byte[] byteData = "hello world"u8.ToArray();
string xml = $"<root attr='val'>{BitConverter.ToString(byteData).Replace("-", "")}</root>";
XmlNodeReader nodeReader = NodeReaderTestHelper.CreateNodeReader(xml);
Assert.True(nodeReader.Read());
diff --git a/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverAddRemoveTests.cs b/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverAddRemoveTests.cs
index 1ca6c15354d..7c8afc8e343 100644
--- a/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverAddRemoveTests.cs
+++ b/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverAddRemoveTests.cs
@@ -40,7 +40,7 @@ namespace System.Xml.XmlResolver.Tests
{
var xmlResolver = new XmlPreloadedResolver(XmlKnownDtds.Xhtml10);
- byte[] data = Encoding.ASCII.GetBytes("hello world");
+ byte[] data = "hello world"u8.ToArray();
MemoryStream stream = new MemoryStream(data);
xmlResolver.Add(new Uri("-//Sample//URI//For Testing", UriKind.RelativeOrAbsolute), stream);
Stream result = xmlResolver.GetEntity(new Uri("-//Sample//URI//For Testing", UriKind.RelativeOrAbsolute),
@@ -70,7 +70,7 @@ namespace System.Xml.XmlResolver.Tests
public void XmlResolverRemoveWithValidData()
{
var xmlResolver = new XmlPreloadedResolver(XmlKnownDtds.Xhtml10);
- byte[] data = Encoding.ASCII.GetBytes("hello world");
+ byte[] data = "hello world"u8.ToArray();
MemoryStream stream = new MemoryStream(data);
xmlResolver.Add(new Uri("-//W3C//DTD XHTML 1.0 Transitional//EN", UriKind.RelativeOrAbsolute), stream);
xmlResolver.Remove(new Uri("-//W3C//DTD XHTML 1.0 Transitional//EN", UriKind.RelativeOrAbsolute));
diff --git a/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverGetEntity.cs b/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverGetEntity.cs
index 061d666ac60..b3cf95c6bff 100644
--- a/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverGetEntity.cs
+++ b/src/libraries/System.Private.Xml/tests/XmlResolver/System.Xml.XmlResolver.Tests/XmlPreloadedResolverGetEntity.cs
@@ -108,7 +108,7 @@ namespace System.Xml.XmlResolver.Tests
[Fact]
public void XmlResolverGetEntityAsyncWithValidUserSuppliedData()
{
- byte[] inpData = Encoding.ASCII.GetBytes("hello world");
+ byte[] inpData = "hello world"u8.ToArray();
var xmlResolver = new XmlPreloadedResolver(XmlKnownDtds.Xhtml10);
xmlResolver.Add(new Uri("-//W3C//DTD FAKE 1.0 Not Real//EN", UriKind.RelativeOrAbsolute), inpData);
Task<object> output = xmlResolver.GetEntityAsync(new Uri("-//W3C//DTD FAKE 1.0 Not Real//EN",
diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs
index f02b3e292b4..2ae28cfe7c9 100644
--- a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs
+++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs
@@ -126,7 +126,7 @@ namespace System.Reflection.Metadata.Tests
PEHeaders headers = new PEHeaders(new MemoryStream(peImage));
//find index for mscorlib
- int mscorlibIndex = IndexOf(peImage, Encoding.ASCII.GetBytes("mscorlib"), headers.MetadataStartOffset);
+ int mscorlibIndex = IndexOf(peImage, "mscorlib"u8.ToArray(), headers.MetadataStartOffset);
Assert.NotEqual(-1, mscorlibIndex);
//mutate mscorlib
peImage[mscorlibIndex + headers.MetadataStartOffset] = 0xFF;
@@ -145,7 +145,7 @@ namespace System.Reflection.Metadata.Tests
// mutate CLR to reach MetadataKind.WindowsMetadata
// find CLR
- int clrIndex = IndexOf(peImage, Encoding.ASCII.GetBytes("CLR"), headers.MetadataStartOffset);
+ int clrIndex = IndexOf(peImage, "CLR"u8.ToArray(), headers.MetadataStartOffset);
Assert.NotEqual(-1, clrIndex);
//find 5, This is the streamcount and is the last thing that should be read befor the test.
int fiveIndex = IndexOf(peImage, new byte[] {5}, headers.MetadataStartOffset + clrIndex);
@@ -435,7 +435,7 @@ namespace System.Reflection.Metadata.Tests
winrtDef.Attributes);
var strReader = reader.GetBlobReader(winrtDef.Name);
- Assert.Equal(Encoding.UTF8.GetBytes("Class1"), strReader.ReadBytes("Class1".Length));
+ Assert.Equal("Class1"u8.ToArray(), strReader.ReadBytes("Class1".Length));
Assert.Equal(0, strReader.RemainingBytes);
// .class /*02000003*/ private auto ansi import windowsruntime sealed beforefieldinit Lib.'<WinRT>Class1'
@@ -449,7 +449,7 @@ namespace System.Reflection.Metadata.Tests
clrDef.Attributes);
strReader = reader.GetBlobReader(clrDef.Name);
- Assert.Equal(Encoding.UTF8.GetBytes("<WinRT>Class1"), strReader.ReadBytes("<WinRT>Class1".Length));
+ Assert.Equal("<WinRT>Class1"u8.ToArray(), strReader.ReadBytes("<WinRT>Class1".Length));
Assert.Equal(0, strReader.RemainingBytes);
}
@@ -469,7 +469,7 @@ namespace System.Reflection.Metadata.Tests
winrtDef.Attributes);
var strReader = reader.GetBlobReader(winrtDef.Name);
- Assert.Equal(Encoding.UTF8.GetBytes("<CLR>Class1"), strReader.ReadBytes("<CLR>Class1".Length));
+ Assert.Equal("<CLR>Class1"u8.ToArray(), strReader.ReadBytes("<CLR>Class1".Length));
Assert.Equal(0, strReader.RemainingBytes);
// .class /*02000003*/ public auto ansi windowsruntime sealed beforefieldinit Lib.Class1
@@ -483,7 +483,7 @@ namespace System.Reflection.Metadata.Tests
clrDef.Attributes);
strReader = reader.GetBlobReader(clrDef.Name);
- Assert.Equal(Encoding.UTF8.GetBytes("Class1"), strReader.ReadBytes("Class1".Length));
+ Assert.Equal("Class1"u8.ToArray(), strReader.ReadBytes("Class1".Length));
Assert.Equal(0, strReader.RemainingBytes);
}
@@ -497,14 +497,14 @@ namespace System.Reflection.Metadata.Tests
Assert.Equal("System.Runtime.CompilerServices", reader.GetString(typeRef.Namespace));
var strReader = reader.GetBlobReader(typeRef.Namespace);
- Assert.Equal(Encoding.UTF8.GetBytes("System.Runtime.CompilerServices"), strReader.ReadBytes("System.Runtime.CompilerServices".Length));
+ Assert.Equal("System.Runtime.CompilerServices"u8.ToArray(), strReader.ReadBytes("System.Runtime.CompilerServices".Length));
Assert.Equal(0, strReader.RemainingBytes);
var dotTerminated = typeRef.Namespace.WithDotTermination();
Assert.Equal("System", reader.GetString(dotTerminated));
strReader = reader.GetBlobReader(dotTerminated);
- Assert.Equal(Encoding.UTF8.GetBytes("System"), strReader.ReadBytes("System".Length));
+ Assert.Equal("System"u8.ToArray(), strReader.ReadBytes("System".Length));
Assert.Equal(0, strReader.RemainingBytes);
}
diff --git a/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBinaryReaderTests.cs b/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBinaryReaderTests.cs
index 20f68af2878..640a5ecf713 100644
--- a/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBinaryReaderTests.cs
+++ b/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBinaryReaderTests.cs
@@ -31,7 +31,7 @@ namespace System.Reflection.PortableExecutable.Tests
[Fact]
public void ReadNullPaddedUTF8WorksWithNoNullPadding()
{
- var headerBytes = Encoding.UTF8.GetBytes(".abcdefg");
+ byte[] headerBytes = ".abcdefg"u8.ToArray();
var stream = new MemoryStream(headerBytes);
stream.Position = 0;
diff --git a/src/libraries/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs
index 096846d0ce4..710871e0c29 100644
--- a/src/libraries/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs
+++ b/src/libraries/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs
@@ -389,7 +389,7 @@ namespace System.Reflection.Metadata.Tests
Assert.Equal("", block.PeekUtf8NullTerminated(4, null, stringDecoder, out bytesRead));
Assert.Equal(0, bytesRead);
- byte[] helloPrefix = Encoding.UTF8.GetBytes("Hello");
+ byte[] helloPrefix = "Hello"u8.ToArray();
Assert.Equal("Hello\u0001", block.PeekUtf8NullTerminated(1, helloPrefix, stringDecoder, out bytesRead));
Assert.Equal(2, bytesRead);
diff --git a/src/libraries/System.Reflection.Metadata/tests/Utilities/MemoryBlockTests.cs b/src/libraries/System.Reflection.Metadata/tests/Utilities/MemoryBlockTests.cs
index 2fd01ef55a1..8f346defebe 100644
--- a/src/libraries/System.Reflection.Metadata/tests/Utilities/MemoryBlockTests.cs
+++ b/src/libraries/System.Reflection.Metadata/tests/Utilities/MemoryBlockTests.cs
@@ -20,20 +20,20 @@ namespace System.Reflection.Metadata.Tests
Assert.True(new MemoryBlock(heapPtr, heap.Length).Utf8NullTerminatedStringStartsWithAsciiPrefix(0, ""));
}
- fixed (byte* heapPtr = (heap = Encoding.UTF8.GetBytes("Hello World!\0")))
+ fixed (byte* heapPtr = (heap = "Hello World!\0"u8.ToArray()))
{
Assert.True(new MemoryBlock(heapPtr, heap.Length).Utf8NullTerminatedStringStartsWithAsciiPrefix("Hello ".Length, "World"));
Assert.False(new MemoryBlock(heapPtr, heap.Length).Utf8NullTerminatedStringStartsWithAsciiPrefix("Hello ".Length, "World?"));
}
- fixed (byte* heapPtr = (heap = Encoding.UTF8.GetBytes("x\0")))
+ fixed (byte* heapPtr = (heap = "x\0"u8.ToArray()))
{
Assert.False(new MemoryBlock(heapPtr, heap.Length).Utf8NullTerminatedStringStartsWithAsciiPrefix(0, "xyz"));
Assert.True(new MemoryBlock(heapPtr, heap.Length).Utf8NullTerminatedStringStartsWithAsciiPrefix(0, "x"));
}
// bad metadata (#String heap is not nul-terminated):
- fixed (byte* heapPtr = (heap = Encoding.UTF8.GetBytes("abcx")))
+ fixed (byte* heapPtr = (heap = "abcx"u8.ToArray()))
{
Assert.True(new MemoryBlock(heapPtr, heap.Length).Utf8NullTerminatedStringStartsWithAsciiPrefix(3, "x"));
Assert.False(new MemoryBlock(heapPtr, heap.Length).Utf8NullTerminatedStringStartsWithAsciiPrefix(3, "xyz"));
@@ -56,7 +56,7 @@ namespace System.Reflection.Metadata.Tests
Assert.Equal(s, Encoding.UTF8.GetString(buffer));
Assert.Equal(buffer.Length, bytesRead);
- s = new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, Encoding.UTF8.GetBytes("Hello"), decoder, out bytesRead);
+ s = new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, "Hello"u8.ToArray(), decoder, out bytesRead);
Assert.Equal("Hello\uFFFD", s);
Assert.Equal(s, "Hello" + Encoding.UTF8.GetString(buffer));
Assert.Equal(buffer.Length, bytesRead);
@@ -131,14 +131,14 @@ namespace System.Reflection.Metadata.Tests
}
);
- fixed (byte* fixedPtr = (buffer = Encoding.UTF8.GetBytes("Test")))
+ fixed (byte* fixedPtr = (buffer = "Test"u8.ToArray()))
{
ptr = fixedPtr;
Assert.Equal("Intercepted", new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, null, decoder, out bytesRead));
Assert.Equal(buffer.Length, bytesRead);
prefixed = true;
- Assert.Equal("Intercepted", new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, Encoding.UTF8.GetBytes("Prefix"), decoder, out bytesRead));
+ Assert.Equal("Intercepted", new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, "Prefix"u8.ToArray(), decoder, out bytesRead));
Assert.Equal(buffer.Length, bytesRead);
}
diff --git a/src/libraries/System.Reflection/tests/MethodInfoTests.cs b/src/libraries/System.Reflection/tests/MethodInfoTests.cs
index 0e6dbedc994..082542d9efd 100644
--- a/src/libraries/System.Reflection/tests/MethodInfoTests.cs
+++ b/src/libraries/System.Reflection/tests/MethodInfoTests.cs
@@ -772,6 +772,7 @@ namespace System.Reflection.Tests
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69919", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static void CallStackFrame_AggressiveInlining()
{
MethodInfo mi = typeof(System.Reflection.TestAssembly.ClassToInvoke).GetMethod(nameof(System.Reflection.TestAssembly.ClassToInvoke.CallMe_AggressiveInlining),
diff --git a/src/libraries/System.Resources.Extensions/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Resources.Extensions/src/ILLink/ILLink.Suppressions.xml
index 226b6912368..42ebf43eee0 100644
--- a/src/libraries/System.Resources.Extensions/src/ILLink/ILLink.Suppressions.xml
+++ b/src/libraries/System.Resources.Extensions/src/ILLink/ILLink.Suppressions.xml
@@ -27,7 +27,7 @@
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
- <argument>IL2062</argument>
+ <argument>IL2067</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Resources.Extensions.PreserializedResourceWriter.AddResource(System.String,System.String,System.String)</property>
</attribute>
diff --git a/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj b/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
index 1e78f153394..3e3e2937781 100644
--- a/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
+++ b/src/libraries/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
@@ -82,6 +82,7 @@
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetHostName.cs" Condition="'$(TargetPlatformIdentifier)' == 'Unix' or '$(TargetPlatformIdentifier)' == 'Browser'" Link="Common\Interop\Unix\System.Native\Interop.GetHostName.cs" />
<Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs" Link="Common\Interop\Unix\Interop.Libraries.cs" />
+ <Compile Include="$(CommonTestPath)System\Diagnostics\DebuggerAttributes.cs" Link="Common\System\Diagnostics\DebuggerAttributes.cs" />
<Compile Include="$(CommonTestPath)System\IO\PathFeatures.cs" Link="Common\System\IO\PathFeatures.cs" />
<Compile Include="$(CommonTestPath)System\ShouldNotBeInvokedException.cs" Link="Common\System\ShouldNotBeInvokedException.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\ByteUtils.cs" Link="Common\System\Security\Cryptography\ByteUtils.cs" />
diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64CharArray.cs b/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64CharArray.cs
index d888e140c4a..c3169476f26 100644
--- a/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64CharArray.cs
+++ b/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64CharArray.cs
@@ -21,7 +21,7 @@ namespace System.Tests
public static void ShortInputArray()
{
// Regression test for bug where a short input array caused an exception to be thrown
- byte[] inputBuffer = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+ byte[] inputBuffer = "abc"u8.ToArray();
char[] ouputBuffer = new char[4];
Convert.ToBase64CharArray(inputBuffer, 0, 3, ouputBuffer, 0);
Convert.ToBase64CharArray(inputBuffer, 0, 2, ouputBuffer, 0);
diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Diagnostics/Stopwatch.cs b/src/libraries/System.Runtime.Extensions/tests/System/Diagnostics/Stopwatch.cs
index 02226d4abe9..273358d1a9f 100644
--- a/src/libraries/System.Runtime.Extensions/tests/System/Diagnostics/Stopwatch.cs
+++ b/src/libraries/System.Runtime.Extensions/tests/System/Diagnostics/Stopwatch.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Reflection;
using System.Threading;
using Xunit;
@@ -95,6 +96,27 @@ namespace System.Diagnostics.Tests
}
}
+ [Fact]
+ public static void DebuggerAttributesValid()
+ {
+ DebuggerAttributes.ValidateDebuggerDisplayReferences(new Stopwatch());
+
+ Stopwatch watch = new Stopwatch();
+ Assert.Equal("00:00:00 (IsRunning = False)", GetDebuggerDisplayProperty(watch));
+ watch.Start();
+ Thread.Sleep(10);
+ Assert.Contains("(IsRunning = True)", GetDebuggerDisplayProperty(watch));
+ Assert.DoesNotContain("00:00:00 ", GetDebuggerDisplayProperty(watch));
+ watch.Stop();
+ Assert.Contains("(IsRunning = False)", GetDebuggerDisplayProperty(watch));
+ Assert.DoesNotContain("00:00:00 ", GetDebuggerDisplayProperty(watch));
+
+ static string GetDebuggerDisplayProperty(Stopwatch value)
+ {
+ return (string)typeof(Stopwatch).GetProperty("DebuggerDisplay", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(value);
+ }
+ }
+
[OuterLoop("Sleeps for relatively long periods of time")]
[Fact]
public static void ElapsedMilliseconds_WithinExpectedWindow()
diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Net/WebUtility.cs b/src/libraries/System.Runtime.Extensions/tests/System/Net/WebUtility.cs
index 5a9bbab770e..a6c0efcfd9b 100644
--- a/src/libraries/System.Runtime.Extensions/tests/System/Net/WebUtility.cs
+++ b/src/libraries/System.Runtime.Extensions/tests/System/Net/WebUtility.cs
@@ -437,7 +437,7 @@ namespace System.Net.Tests
// prevent problems where the input array is changed if
// the output one is modified.
- byte[] input = Encoding.UTF8.GetBytes("Dont.Need.Encoding");
+ byte[] input = "Dont.Need.Encoding"u8.ToArray();
byte[] output = WebUtility.UrlEncodeToBytes(input, 0, input.Length);
Assert.NotSame(input, output);
}
@@ -445,7 +445,7 @@ namespace System.Net.Tests
[Fact]
public static void UrlDecodeToBytes_NoDecodingNeeded_ReturnsNewClonedArray()
{
- byte[] input = Encoding.UTF8.GetBytes("Dont.Need.Decoding");
+ byte[] input = "Dont.Need.Decoding"u8.ToArray();
byte[] output = WebUtility.UrlDecodeToBytes(input, 0, input.Length);
Assert.NotSame(input, output);
}
diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTestTypes/SampleTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTestTypes/SampleTypes.cs
index 81d2acff15d..56af61b4e3e 100644
--- a/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTestTypes/SampleTypes.cs
+++ b/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTestTypes/SampleTypes.cs
@@ -4147,7 +4147,7 @@ namespace SerializationTestTypes
public class IReadWriteXmlWriteBinHex_EqualityDefined : IXmlSerializable
{
- private byte[] _bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ private byte[] _bits = "hello world"u8.ToArray();
public System.Xml.Schema.XmlSchema GetSchema()
{
@@ -4176,7 +4176,7 @@ namespace SerializationTestTypes
public virtual void WriteXml(System.Xml.XmlWriter writer)
{
- byte[] bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ byte[] bits = "hello world"u8.ToArray();
writer.WriteBinHex(bits, 0, bits.Length);
}
@@ -4202,7 +4202,7 @@ namespace SerializationTestTypes
internal class PrivateIXmlSerializables : IXmlSerializable
{
- private byte[] _bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ private byte[] _bits = "hello world"u8.ToArray();
public System.Xml.Schema.XmlSchema GetSchema()
{
@@ -4231,7 +4231,7 @@ namespace SerializationTestTypes
public virtual void WriteXml(System.Xml.XmlWriter writer)
{
- byte[] bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ byte[] bits = "hello world"u8.ToArray();
writer.WriteBinHex(bits, 0, bits.Length);
}
}
@@ -4241,7 +4241,7 @@ namespace SerializationTestTypes
private PrivateDefaultCtorIXmlSerializables() { }
public PrivateDefaultCtorIXmlSerializables(bool init) { }
- private byte[] _bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ private byte[] _bits = "hello world"u8.ToArray();
public System.Xml.Schema.XmlSchema GetSchema()
{
@@ -4270,7 +4270,7 @@ namespace SerializationTestTypes
public virtual void WriteXml(System.Xml.XmlWriter writer)
{
- byte[] bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ byte[] bits = "hello world"u8.ToArray();
writer.WriteBinHex(bits, 0, bits.Length);
}
}
@@ -4278,7 +4278,7 @@ namespace SerializationTestTypes
[XmlSchemaProvider("MySchema")]
public class PublicIXmlSerializablesWithPublicSchemaProvider : IXmlSerializable
{
- private byte[] _bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ private byte[] _bits = "hello world"u8.ToArray();
public System.Xml.Schema.XmlSchema GetSchema()
{
@@ -4312,7 +4312,7 @@ namespace SerializationTestTypes
public virtual void WriteXml(System.Xml.XmlWriter writer)
{
- byte[] bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ byte[] bits = "hello world"u8.ToArray();
writer.WriteBinHex(bits, 0, bits.Length);
}
}
@@ -4320,7 +4320,7 @@ namespace SerializationTestTypes
[XmlSchemaProvider("MySchema")]
public class PublicExplicitIXmlSerializablesWithPublicSchemaProvider : IXmlSerializable
{
- private byte[] _bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ private byte[] _bits = "hello world"u8.ToArray();
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
@@ -4354,7 +4354,7 @@ namespace SerializationTestTypes
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
{
- byte[] bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ byte[] bits = "hello world"u8.ToArray();
writer.WriteBinHex(bits, 0, bits.Length);
}
}
@@ -4362,7 +4362,7 @@ namespace SerializationTestTypes
[XmlSchemaProvider("MySchema")]
public class PublicIXmlSerializablesWithPrivateSchemaProvider : IXmlSerializable
{
- private byte[] _bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ private byte[] _bits = "hello world"u8.ToArray();
public System.Xml.Schema.XmlSchema GetSchema()
{
@@ -4396,7 +4396,7 @@ namespace SerializationTestTypes
public virtual void WriteXml(System.Xml.XmlWriter writer)
{
- byte[] bits = System.Text.Encoding.UTF8.GetBytes("hello world");
+ byte[] bits = "hello world"u8.ToArray();
writer.WriteBinHex(bits, 0, bits.Length);
}
}
diff --git a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs
index d67357b9e27..deb55e01d9b 100644
--- a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs
+++ b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs
@@ -17,8 +17,7 @@ namespace System.Reflection.Tests
private static readonly NullabilityInfoContext nullabilityContext = new NullabilityInfoContext();
private static readonly Type testType = typeof(TypeWithNotNullContext);
private static readonly Type genericType = typeof(GenericTest<TypeWithNotNullContext>);
- private static readonly Type stringType = typeof(string);
- private static readonly BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
+ private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
public static IEnumerable<object[]> FieldTestData()
{
@@ -705,7 +704,7 @@ namespace System.Reflection.Tests
[MemberData(nameof(StringTypeTestData))]
public void NullablePublicOnlyStringTypeTest(string methodName, NullabilityState param1State, NullabilityState param2State, NullabilityState param3State, Type[] types)
{
- ParameterInfo[] parameters = stringType.GetMethod(methodName, flags, types)!.GetParameters();
+ ParameterInfo[] parameters = typeof(string).GetMethod(methodName, flags, types)!.GetParameters();
NullabilityInfo param1 = nullabilityContext.Create(parameters[0]);
NullabilityInfo param2 = nullabilityContext.Create(parameters[1]);
NullabilityInfo param3 = nullabilityContext.Create(parameters[2]);
diff --git a/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs b/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs
index 54a86110f40..6636bf09eeb 100644
--- a/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs
+++ b/src/libraries/System.Runtime/tests/System/Text/ASCIIUtilityTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -427,9 +428,10 @@ namespace System.Text.Tests
}
}
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
private static Type GetAsciiUtilityType()
{
- return typeof(object).Assembly.GetType("System.Text.ASCIIUtility");
+ return Type.GetType("System.Text.ASCIIUtility, System.Private.CoreLib");
}
private sealed class UnsafeLazyDelegate<TDelegate> where TDelegate : Delegate
diff --git a/src/libraries/System.Runtime/tests/System/Text/Latin1UtilityTests.cs b/src/libraries/System.Runtime/tests/System/Text/Latin1UtilityTests.cs
index c447431b5db..8320ab8f320 100644
--- a/src/libraries/System.Runtime/tests/System/Text/Latin1UtilityTests.cs
+++ b/src/libraries/System.Runtime/tests/System/Text/Latin1UtilityTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -325,9 +326,10 @@ namespace System.Text.Tests
}
}
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
private static Type GetLatin1UtilityType()
{
- return typeof(object).Assembly.GetType("System.Text.Latin1Utility");
+ return Type.GetType("System.Text.Latin1Utility, System.Private.CoreLib");
}
private sealed class UnsafeLazyDelegate<TDelegate> where TDelegate : class
diff --git a/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs b/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs
index 23f37e4949a..63dfa4b34d5 100644
--- a/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs
+++ b/src/libraries/System.Runtime/tests/System/Text/StringBuilderTests.cs
@@ -724,12 +724,14 @@ namespace System.Text.Tests
yield return new object[] { "Hello", null, ", Foo {0,3}", new object[] { "B" }, "Hello, Foo B" }; // Value's length < minimum length (so prepend whitespace)
yield return new object[] { "Hello", null, ", Foo {0, 3}", new object[] { "B" }, "Hello, Foo B" }; // Same as above, but verify AppendFormat ignores whitespace
yield return new object[] { "Hello", null, ", Foo {0,0}", new object[] { "Bar" }, "Hello, Foo Bar" }; // Minimum length is 0
+ yield return new object[] { "Hello", null, ", Foo {0, 2 }", new object[] { "Bar" }, "Hello, Foo Bar" }; // whitespace before and after length
// Length is negative
yield return new object[] { "Hello", null, ", Foo {0,-2}", new object[] { "Bar" }, "Hello, Foo Bar" }; // Value's length > |minimum length| (so don't prepend whitespace)
yield return new object[] { "Hello", null, ", Foo {0,-3}", new object[] { "B" }, "Hello, Foo B " }; // Value's length < |minimum length| (so append whitespace)
yield return new object[] { "Hello", null, ", Foo {0, -3}", new object[] { "B" }, "Hello, Foo B " }; // Same as above, but verify AppendFormat ignores whitespace
yield return new object[] { "Hello", null, ", Foo {0,0}", new object[] { "Bar" }, "Hello, Foo Bar" }; // Minimum length is 0
+ yield return new object[] { "Hello", null, ", Foo {0, -2 }", new object[] { "Bar" }, "Hello, Foo Bar" }; // whitespace before and after length
yield return new object[] { "Hello", null, ", Foo {0:D6}", new object[] { 1 }, "Hello, Foo 000001" }; // Custom format
yield return new object[] { "Hello", null, ", Foo {0 :D6}", new object[] { 1 }, "Hello, Foo 000001" }; // Custom format with ignored whitespace
@@ -915,6 +917,19 @@ namespace System.Text.Tests
Assert.Throws<FormatException>(() => builder.AppendFormat("{0:{", new string[10])); // Format with custom format contains unescaped {
Assert.Throws<FormatException>(() => builder.AppendFormat("{0:{}", new string[10])); // Format with custom format contains unescaped {
+
+ Assert.Throws<FormatException>(() => builder.AppendFormat("{0}", new TooManyCharsWrittenSpanFormattable())); // ISpanFormattable that returns more characters than it actually wrote
+ }
+
+ private struct TooManyCharsWrittenSpanFormattable : ISpanFormattable
+ {
+ public string ToString(string format, IFormatProvider formatProvider) => "abc";
+ public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
+ {
+ "abc".TryCopyTo(destination);
+ charsWritten = 1_000_000;
+ return true;
+ }
}
[Fact]
diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs
index d9c07161add..9229fd32126 100644
--- a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs
+++ b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf16UtilityTests.ValidateChars.cs
@@ -248,7 +248,7 @@ namespace System.Text.Unicode.Tests
{
return new Lazy<GetPointerToFirstInvalidCharDel>(() =>
{
- Type utf16UtilityType = typeof(Utf8).Assembly.GetType("System.Text.Unicode.Utf16Utility");
+ Type utf16UtilityType = Type.GetType("System.Text.Unicode.Utf16Utility, System.Private.CoreLib");
if (utf16UtilityType is null)
{
diff --git a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs
index 3668d191bf6..db701828ab6 100644
--- a/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs
+++ b/src/libraries/System.Runtime/tests/System/Text/Unicode/Utf8UtilityTests.ValidateBytes.cs
@@ -396,7 +396,7 @@ namespace System.Text.Unicode.Tests
{
return new Lazy<GetPointerToFirstInvalidByteDel>(() =>
{
- Type utf8UtilityType = typeof(Utf8).Assembly.GetType("System.Text.Unicode.Utf8Utility");
+ Type utf8UtilityType = Type.GetType("System.Text.Unicode.Utf8Utility, System.Private.CoreLib");
if (utf8UtilityType is null)
{
diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs
index b28ad1d9882..5d04aa8638f 100644
--- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs
+++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs
@@ -2882,21 +2882,28 @@ namespace System.Tests
Assert.Equal(TimeSpan.FromHours(12), fijiTZ.GetUtcOffset(utcDT));
Assert.False(fijiTZ.IsDaylightSavingTime(utcDT));
- utcDT = new DateTime(2022, 10, 1, 10, 0, 0, DateTimeKind.Utc);
- Assert.Equal(TimeSpan.FromHours(12), fijiTZ.GetUtcOffset(utcDT));
- Assert.False(fijiTZ.IsDaylightSavingTime(utcDT));
+ TimeZoneInfo.AdjustmentRule [] rules = fijiTZ.GetAdjustmentRules();
- utcDT = new DateTime(2022, 12, 31, 11, 0, 0, DateTimeKind.Utc);
- Assert.Equal(TimeSpan.FromHours(13), fijiTZ.GetUtcOffset(utcDT));
- Assert.True(fijiTZ.IsDaylightSavingTime(utcDT));
+ // Some machines got some weird TZ data which not including all supported years' rules
+ // Avoid the test failures in such case.
+ if (rules.Length > 0 && rules[rules.Length - 1].DateStart.Year >= 2023)
+ {
+ utcDT = new DateTime(2022, 10, 1, 10, 0, 0, DateTimeKind.Utc);
+ Assert.Equal(TimeSpan.FromHours(12), fijiTZ.GetUtcOffset(utcDT));
+ Assert.False(fijiTZ.IsDaylightSavingTime(utcDT));
- utcDT = new DateTime(2023, 1, 1, 10, 0, 0, DateTimeKind.Utc);
- Assert.Equal(TimeSpan.FromHours(13), fijiTZ.GetUtcOffset(utcDT));
- Assert.True(fijiTZ.IsDaylightSavingTime(utcDT));
+ utcDT = new DateTime(2022, 12, 31, 11, 0, 0, DateTimeKind.Utc);
+ Assert.Equal(TimeSpan.FromHours(13), fijiTZ.GetUtcOffset(utcDT));
+ Assert.True(fijiTZ.IsDaylightSavingTime(utcDT));
- utcDT = new DateTime(2023, 2, 1, 0, 0, 0, DateTimeKind.Utc);
- Assert.Equal(TimeSpan.FromHours(12), fijiTZ.GetUtcOffset(utcDT));
- Assert.False(fijiTZ.IsDaylightSavingTime(utcDT));
+ utcDT = new DateTime(2023, 1, 1, 10, 0, 0, DateTimeKind.Utc);
+ Assert.Equal(TimeSpan.FromHours(13), fijiTZ.GetUtcOffset(utcDT));
+ Assert.True(fijiTZ.IsDaylightSavingTime(utcDT));
+
+ utcDT = new DateTime(2023, 2, 1, 0, 0, 0, DateTimeKind.Utc);
+ Assert.Equal(TimeSpan.FromHours(12), fijiTZ.GetUtcOffset(utcDT));
+ Assert.False(fijiTZ.IsDaylightSavingTime(utcDT));
+ }
}
[Fact]
@@ -2939,6 +2946,13 @@ namespace System.Tests
Assert.Equal(tzCollection.Count, tzDisplayNames.Count);
}
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Android | TestPlatforms.iOS | TestPlatforms.tvOS)]
+ public static void LocalTzIsNotUtc()
+ {
+ Assert.NotEqual(TimeZoneInfo.Utc.StandardName, TimeZoneInfo.Local.StandardName);
+ }
+
private static bool IsEnglishUILanguage => CultureInfo.CurrentUICulture.Name.Length == 0 || CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "en";
private static bool IsEnglishUILanguageAndRemoteExecutorSupported => IsEnglishUILanguage && RemoteExecutor.IsSupported;
diff --git a/src/libraries/System.Runtime/tests/default.rd.xml b/src/libraries/System.Runtime/tests/default.rd.xml
index 72b0a4a6095..b100128a1bd 100644
--- a/src/libraries/System.Runtime/tests/default.rd.xml
+++ b/src/libraries/System.Runtime/tests/default.rd.xml
@@ -499,7 +499,8 @@
<GenericArgument Name="System.Runtime.CompilerServices.Tests.RuntimeHelpersTests+TestStruct, System.Runtime.Tests" />
</Method>
</Type>
-
+ <Type Name="System.Int128" Dynamic="Required All" />
+ <Type Name="System.Half" Dynamic="Required All" />
</Assembly>
</Application>
</Directives>
diff --git a/src/libraries/System.Security.Cryptography.Cose/tests/CoseTestHelpers.cs b/src/libraries/System.Security.Cryptography.Cose/tests/CoseTestHelpers.cs
index 80d4eac5790..278e41276b4 100644
--- a/src/libraries/System.Security.Cryptography.Cose/tests/CoseTestHelpers.cs
+++ b/src/libraries/System.Security.Cryptography.Cose/tests/CoseTestHelpers.cs
@@ -21,7 +21,7 @@ namespace System.Security.Cryptography.Cose.Tests
internal const int KnownHeaderIV = 5;
internal const int KnownHeaderPartialIV = 6;
internal const int KnownHeaderCounterSignature = 7;
- internal static readonly byte[] s_sampleContent = Encoding.UTF8.GetBytes("This is the content.");
+ internal static readonly byte[] s_sampleContent = "This is the content."u8.ToArray();
internal const string ContentTypeDummyValue = "application/cose; cose-type=\"cose-sign1\"";
internal const string NullCborHex = "F6";
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs
index 850232f8fe2..30effc124e4 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs
@@ -16,7 +16,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
public static void BuildExpectedRequest_FromData(bool viaSpan)
{
Rfc3161TimestampRequest request = Rfc3161TimestampRequest.CreateFromData(
- System.Text.Encoding.ASCII.GetBytes("Hello, world!!"),
+ "Hello, world!!"u8,
HashAlgorithmName.SHA256,
requestSignerCertificates: true);
@@ -489,6 +489,12 @@ namespace System.Security.Cryptography.Pkcs.Tests
nonce: nonce,
requestSignerCertificates: expectedStatus != Rfc3161RequestResponseStatus.UnexpectedCertificates);
+ if (!SignatureSupport.SupportsRsaSha1Signatures &&
+ expectedStatus != Rfc3161RequestResponseStatus.RequestFailed)
+ {
+ expectedStatus = Rfc3161RequestResponseStatus.DoesNotParse;
+ }
+
ProcessResponse(expectedStatus, request, inputBytes, Padding.Length / 2);
}
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs
index dba1da30509..61ed97aa0fc 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs
@@ -100,7 +100,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
"D50DF295F1DB078C84EECBCB30F1018E939B1FEA8615B31F39F87F02EF816EFF" +
"FE80A39C0857ECA510882DD2D66D49B743F0E7FF8DBEE4650449");
- data.MessageContent = Encoding.ASCII.GetBytes("This is a test.\n");
+ data.MessageContent = "This is a test.\n"u8.ToArray();
data.TokenInfoBytes = data.FullTokenBytes.Slice(64, 412);
data.PolicyId = "1.2.3.4.1";
@@ -283,7 +283,7 @@ DgUIrLjqguolBSdvPJ2io9O0rTi7+IQr2jb8JEgpH1WNwC3R4A==");
"FD6B6AB4F89DC6750F14EC2E0134BA61B4D0B2C1FB2F60F622379249CE6381AF" +
"667900B17A7BB6AE");
- data.MessageContent = Encoding.ASCII.GetBytes("Hello, world!");
+ data.MessageContent = "Hello, world!"u8.ToArray();
data.EmbeddedSigningCertificate = data.FullTokenBytes.Slice(1659, 1359);
@@ -422,7 +422,7 @@ DgUIrLjqguolBSdvPJ2io9O0rTi7+IQr2jb8JEgpH1WNwC3R4A==");
"76252A2F4605B97BD3C299D1CD79929273BB86E7DF9E113C92802380ED6D4041" +
"9DA4C01214D4FA24");
- data.MessageContent = Encoding.UTF8.GetBytes("My TST signer attributes are sorted incorrectly.");
+ data.MessageContent = "My TST signer attributes are sorted incorrectly."u8.ToArray();
data.EmbeddedSigningCertificate = data.FullTokenBytes.Slice(188, 1670);
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs
index 49b6b8f0c58..7c570de2ca6 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs
@@ -85,10 +85,22 @@ namespace System.Security.Cryptography.Pkcs.Tests
using (var signerCert = new X509Certificate2(testData.ExternalCertificateBytes))
{
- // Assert.NoThrow
- signedCms.CheckSignature(
- new X509Certificate2Collection(signerCert),
- true);
+ if (!SignatureSupport.SupportsRsaSha1Signatures &&
+ signedCms.SignerInfos[0].SignatureAlgorithm.Value == Oids.Rsa &&
+ signedCms.SignerInfos[0].DigestAlgorithm.Value == Oids.Sha1)
+ {
+ Assert.ThrowsAny<CryptographicException>(() => signedCms.CheckSignature(
+ new X509Certificate2Collection(signerCert),
+ true));
+ return;
+ }
+ else
+ {
+ // Assert.NoThrow
+ signedCms.CheckSignature(
+ new X509Certificate2Collection(signerCert),
+ true);
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignatureSupport.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignatureSupport.cs
new file mode 100644
index 00000000000..ee31485341c
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignatureSupport.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Xml;
+using Xunit;
+
+namespace System.Security.Cryptography.Pkcs.Tests
+{
+ public class SignatureSupport
+ {
+ public static bool SupportsRsaSha1Signatures { get; } =
+ System.Security.Cryptography.Tests.SignatureSupport.CanProduceSha1Signature(RSA.Create());
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs
index c89cfa54bb8..c33e25746f0 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs
@@ -187,7 +187,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
() => new SignedCms(SubjectIdentifierType.SubjectKeyIdentifier, null, true));
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void CheckSignature_ExtraStore_IsAdditional()
{
SignedCms cms = new SignedCms();
@@ -200,7 +200,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(new X509Certificate2Collection(), true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void Decode_IgnoresExtraData()
{
byte[] basis = SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber;
@@ -1132,7 +1132,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void UntrustedCertFails_WhenTrustChecked()
{
SignedCms cms = new SignedCms();
@@ -1441,7 +1441,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
Assert.Equal(contentHex, signedCms.ContentInfo.Content.ByteArrayToHex());
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void CheckSignedEncrypted_IssuerSerial_FromNetFx()
{
CheckSignedEncrypted(
@@ -1449,7 +1449,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
SubjectIdentifierType.IssuerAndSerialNumber);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void CheckSignedEncrypted_SKID_FromNetFx()
{
CheckSignedEncrypted(
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs
index de363e38738..255bc691b72 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs
@@ -239,7 +239,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
}
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void AddCertificate()
{
SignedCms cms = new SignedCms();
@@ -258,7 +258,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
}
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void AddCertificateWithPrivateKey()
{
SignedCms cms = new SignedCms();
@@ -323,7 +323,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
}
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void RemoveAllCertsAddBackSignerCert()
{
SignedCms cms = new SignedCms();
@@ -509,17 +509,24 @@ namespace System.Security.Cryptography.Pkcs.Tests
}
signer.DigestAlgorithm = new Oid(digestOid, null);
- cms.ComputeSignature(signer);
- cmsBytes = cms.Encode();
+ if (!SignatureSupport.SupportsRsaSha1Signatures &&
+ digestOid == Oids.Sha1)
+ {
+ Assert.ThrowsAny<CryptographicException>(() => cms.ComputeSignature(signer));
+ }
+ else
+ {
+ cms.ComputeSignature(signer);
+ cmsBytes = cms.Encode();
+ cms = new SignedCms();
+ cms.Decode(cmsBytes);
+ cms.CheckSignature(true); // Assert.NoThrow
+ Assert.Single(cms.SignerInfos);
+
+ SignerInfo signerInfo = cms.SignerInfos[0];
+ Assert.Equal(Oids.RsaPss, signerInfo.SignatureAlgorithm.Value);
+ }
}
-
- cms = new SignedCms();
- cms.Decode(cmsBytes);
- cms.CheckSignature(true); // Assert.NoThrow
- Assert.Single(cms.SignerInfos);
-
- SignerInfo signerInfo = cms.SignerInfos[0];
- Assert.Equal(Oids.RsaPss, signerInfo.SignatureAlgorithm.Value);
}
[Fact]
@@ -610,7 +617,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
CmsSigner signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, pubCert, key)
{
IncludeOption = X509IncludeOption.EndCertOnly,
- DigestAlgorithm = new Oid(Oids.Sha1, Oids.Sha1)
+ DigestAlgorithm = key is DSA ? new Oid(Oids.Sha1, Oids.Sha1) : new Oid(Oids.Sha256, Oids.Sha256)
};
cms.ComputeSignature(signer);
@@ -637,13 +644,13 @@ namespace System.Security.Cryptography.Pkcs.Tests
CmsSigner cmsSigner = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, pubCert, key)
{
IncludeOption = X509IncludeOption.EndCertOnly,
- DigestAlgorithm = new Oid(Oids.Sha1, Oids.Sha1)
+ DigestAlgorithm = key is DSA ? new Oid(Oids.Sha1, Oids.Sha1) : new Oid(Oids.Sha256, Oids.Sha256)
};
CmsSigner cmsCounterSigner = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, counterSignerPubCert, counterSignerKey)
{
IncludeOption = X509IncludeOption.EndCertOnly,
- DigestAlgorithm = new Oid(Oids.Sha1, Oids.Sha1)
+ DigestAlgorithm = counterSignerKey is DSA ? new Oid(Oids.Sha1, Oids.Sha1) : new Oid(Oids.Sha256, Oids.Sha256)
};
cms.ComputeSignature(cmsSigner);
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs
index 8dc711c7df2..8918d7adbb6 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs
@@ -136,7 +136,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
Assert.Throws<CryptographicException>(() => cms.CheckSignature(true));
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void ReadRsaPkcs1SimpleDocument()
{
SignedCms cms = new SignedCms();
@@ -204,7 +204,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void ReadRsaPkcs1CounterSigned()
{
SignedCms cms = new SignedCms();
@@ -285,7 +285,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckHash();
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void CheckNoSignatureDocument()
{
SignedCms cms = new SignedCms();
@@ -405,7 +405,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
Assert.Throws<CryptographicException>(() => cms.CheckSignature(true));
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void NonEmbeddedCertificate()
{
SignedCms cms = new SignedCms();
@@ -518,7 +518,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
}
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void ReadRsaPkcs1DoubleCounterSigned()
{
SignedCms cms = new SignedCms();
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs
index 9c558870210..bf584e4ab24 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs
@@ -183,7 +183,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
() => signer.CheckSignature(null, false));
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void CheckSignature_ExtraStore_IsAdditional()
{
SignedCms cms = new SignedCms();
@@ -212,7 +212,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
signer.CheckSignature(true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void CheckSignature_SHA1WithRSA()
{
SignedCms cms = new SignedCms();
@@ -296,7 +296,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
signer.CheckSignature(true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "NetFx bug in matching logic")]
public static void RemoveCounterSignature_MatchesIssuerAndSerialNumber()
{
@@ -327,7 +327,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckHash();
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "NetFx bug in matching logic")]
public static void RemoveCounterSignature_MatchesSubjectKeyIdentifier()
{
@@ -360,7 +360,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckHash();
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "NetFx bug in matching logic")]
public static void RemoveCounterSignature_MatchesNoSignature()
{
@@ -392,7 +392,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "NetFx bug in matching logic")]
public static void RemoveCounterSignature_UsesLiveState()
{
@@ -567,7 +567,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
() => signer.RemoveCounterSignature(0));
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void AddCounterSigner_DuplicateCert_RSA()
{
SignedCms cms = new SignedCms();
@@ -613,7 +613,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(true);
}
- [Theory]
+ [ConditionalTheory(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[InlineData(SubjectIdentifierType.IssuerAndSerialNumber)]
[InlineData(SubjectIdentifierType.SubjectKeyIdentifier)]
public static void AddCounterSigner_RSA(SubjectIdentifierType identifierType)
@@ -698,7 +698,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[SkipOnPlatform(PlatformSupport.MobileAppleCrypto, "DSA is not available")]
public static void AddCounterSigner_DSA()
{
@@ -758,7 +758,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(true);
}
- [Theory]
+ [ConditionalTheory(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
[InlineData(SubjectIdentifierType.IssuerAndSerialNumber, Oids.Sha1)]
[InlineData(SubjectIdentifierType.SubjectKeyIdentifier, Oids.Sha1)]
@@ -829,7 +829,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
cms.CheckSignature(true);
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void AddFirstCounterSigner_NoSignature_NoPrivateKey()
{
SignedCms cms = new SignedCms();
@@ -862,7 +862,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
}
}
- [Fact]
+ [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
public static void AddFirstCounterSigner_NoSignature()
{
SignedCms cms = new SignedCms();
@@ -912,7 +912,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
}
}
- [Theory]
+ [ConditionalTheory(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
[InlineData(false)]
[InlineData(true)]
public static void AddSecondCounterSignature_NoSignature_WithCert(bool addExtraCert)
@@ -920,7 +920,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
AddSecondCounterSignature_NoSignature(withCertificate: true, addExtraCert);
}
- [Theory]
+ [ConditionalTheory(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))]
// On .NET Framework it will prompt for the counter-signer's certificate if it's null,
// even if the signature type is NoSignature, so don't run the test there.
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj b/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj
index cde9e145b7a..06c202b569e 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj
+++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj
@@ -8,6 +8,8 @@
Link="CommonTest\System\Security\Cryptography\ByteUtils.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\PlatformSupport.cs"
Link="CommonTest\System\Security\Cryptography\PlatformSupport.cs" />
+ <Compile Include="$(CommonTestPath)System\Security\Cryptography\SignatureSupport.cs"
+ Link="CommonTest\System\Security\Cryptography\SignatureSupport.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Certificates.cs" />
<Compile Include="CertLoader.cs" />
@@ -27,6 +29,7 @@
<Compile Include="Oids.cs" />
<Compile Include="Pkcs9AttributeTests.cs" />
<Compile Include="RecipientInfoCollectionTests.cs" />
+ <Compile Include="SignatureSupport.cs" />
<Compile Include="SignedCms\CmsSignerTests.cs" />
<Compile Include="SignedCms\CounterSigningDerOrder.cs" />
<Compile Include="SignedCms\SignedCmsTests.cs" />
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PublicKeyTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PublicKeyTests.cs
index b4a4487a1ce..745049b3c78 100644
--- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PublicKeyTests.cs
+++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PublicKeyTests.cs
@@ -347,7 +347,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
0x11, 0xE0, 0x6E, 0xD2, 0x22, 0x75, 0xE7, 0x7C,
};
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello");
+ byte[] helloBytes = "Hello"u8.ToArray();
using (var cert = new X509Certificate2(TestData.Rsa384CertificatePemBytes))
using (RSA rsa = cert.GetRSAPublicKey())
@@ -360,7 +360,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
public static void TestKey_ECDsabrainpool_PublicKey(byte[] curveData, byte[] notUsed)
{
_ = notUsed;
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello");
+ byte[] helloBytes = "Hello"u8.ToArray();
try
{
@@ -386,7 +386,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
[Fact]
public static void TestECDsaPublicKey()
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello");
+ byte[] helloBytes = "Hello"u8.ToArray();
using (var cert = new X509Certificate2(TestData.ECDsa384Certificate))
using (ECDsa publicKey = cert.GetECDsaPublicKey())
@@ -439,7 +439,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
0x08, 0xC5, 0xAA, 0xA6, 0xE5, 0xFD, 0xD0, 0x96,
};
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello");
+ byte[] helloBytes = "Hello"u8.ToArray();
using (var cert = new X509Certificate2(TestData.ECDsa384Certificate))
using (ECDsa publicKey = cert.GetECDsaPublicKey())
@@ -476,7 +476,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
[Theory, MemberData(nameof(BrainpoolCurves))]
public static void TestECDsaPublicKey_BrainpoolP160r1_ValidatesSignature(byte[] curveData, byte[] existingSignature)
{
- byte[] helloBytes = Encoding.ASCII.GetBytes("Hello");
+ byte[] helloBytes = "Hello"u8.ToArray();
try
{
diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs b/src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs
index 5e11d908899..5af72f7c03d 100644
--- a/src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs
@@ -611,7 +611,7 @@ namespace System.Security.Cryptography.Xml.Tests
[Fact]
public void EncryptKey_RSA_UseOAEP()
{
- byte[] data = Encoding.ASCII.GetBytes("12345678");
+ byte[] data = "12345678"u8.ToArray();
using (RSA rsa = RSA.Create())
{
byte[] encryptedData = EncryptedXml.EncryptKey(data, rsa, true);
@@ -852,7 +852,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (TripleDES tripleDES = TripleDES.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("123456781234567812345678");
+ byte[] key = "123456781234567812345678"u8.ToArray();
byte[] encryptedKey = EncryptedXml.EncryptKey(key, tripleDES);
@@ -866,7 +866,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (Aes aes = Aes.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("123456781234567812345678");
+ byte[] key = "123456781234567812345678"u8.ToArray();
byte[] encryptedKey = EncryptedXml.EncryptKey(key, aes);
@@ -880,7 +880,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (Aes aes = Aes.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("12345678");
+ byte[] key = "12345678"u8.ToArray();
byte[] encryptedKey = EncryptedXml.EncryptKey(key, aes);
@@ -894,7 +894,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (Aes aes = Aes.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("1234567");
+ byte[] key = "1234567"u8.ToArray();
Assert.Throws<CryptographicException>(() => EncryptedXml.EncryptKey(key, aes));
}
@@ -905,7 +905,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (TripleDES tripleDES = TripleDES.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("123");
+ byte[] key = "123"u8.ToArray();
Assert.Throws<CryptographicException>(() => EncryptedXml.DecryptKey(key, tripleDES));
}
@@ -916,7 +916,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (TripleDES tripleDES = TripleDES.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("123456781234567812345678");
+ byte[] key = "123456781234567812345678"u8.ToArray();
byte[] encryptedKey = EncryptedXml.EncryptKey(key, tripleDES);
encryptedKey[0] ^= 0xFF;
@@ -930,7 +930,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (Aes aes = Aes.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("123");
+ byte[] key = "123"u8.ToArray();
Assert.Throws<CryptographicException>(() => EncryptedXml.DecryptKey(key, aes));
}
@@ -941,7 +941,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (Aes aes = Aes.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("123456781234567812345678");
+ byte[] key = "123456781234567812345678"u8.ToArray();
byte[] encryptedKey = EncryptedXml.EncryptKey(key, aes);
encryptedKey[0] ^= 0xFF;
@@ -955,7 +955,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
using (Aes aes = Aes.Create())
{
- byte[] key = Encoding.ASCII.GetBytes("12345678");
+ byte[] key = "12345678"u8.ToArray();
byte[] encryptedKey = EncryptedXml.EncryptKey(key, aes);
encryptedKey[0] ^= 0xFF;
diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs b/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
index 1265c37bc42..ac5d3560a32 100644
--- a/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
@@ -1447,7 +1447,7 @@ namespace System.Security.Cryptography.Xml.Tests
";
SignedXml sign = GetSignedXml(string.Format(xml, bits));
// only multiple of 8 bits are supported
- sign.CheckSignature(new HMACSHA1(Encoding.ASCII.GetBytes("secret")));
+ sign.CheckSignature(new HMACSHA1("secret"u8.ToArray()));
}
for (int i = 1; i < 160; i++)
@@ -1483,10 +1483,10 @@ namespace System.Security.Cryptography.Xml.Tests
";
SignedXml sign = GetSignedXml(xml);
- CheckErratum(sign, new HMACSHA1(Encoding.ASCII.GetBytes("no clue")), "1");
+ CheckErratum(sign, new HMACSHA1("no clue"u8.ToArray()), "1");
CheckErratum(sign, new HMACSHA1(Encoding.ASCII.GetBytes("")), "2");
- CheckErratum(sign, new HMACSHA1(Encoding.ASCII.GetBytes("oops")), "3");
- CheckErratum(sign, new HMACSHA1(Encoding.ASCII.GetBytes("secret")), "4");
+ CheckErratum(sign, new HMACSHA1("oops"u8.ToArray()), "3");
+ CheckErratum(sign, new HMACSHA1("secret"u8.ToArray()), "4");
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/20429")]
@@ -1496,7 +1496,7 @@ namespace System.Security.Cryptography.Xml.Tests
// 72 is a multiple of 8 but smaller than the minimum of 80 bits
string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#hmac-sha1""><HMACOutputLength>72</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>2dimB+P5Aw5K</SignatureValue><Object Id=""object"">some other text</Object></Signature>";
SignedXml sign = GetSignedXml(xml);
- CheckErratum(sign, new HMACSHA1(Encoding.ASCII.GetBytes("secret")), "72");
+ CheckErratum(sign, new HMACSHA1("secret"u8.ToArray()), "72");
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/20429")]
@@ -1506,7 +1506,7 @@ namespace System.Security.Cryptography.Xml.Tests
// 80 bits is the minimum (and the half-size of HMACSHA1)
string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#hmac-sha1""><HMACOutputLength>80</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>jVQPtLj61zNYjw==</SignatureValue><Object Id=""object"">some other text</Object></Signature>";
SignedXml sign = GetSignedXml(xml);
- Assert.True(sign.CheckSignature(new HMACSHA1(Encoding.ASCII.GetBytes("secret"))));
+ Assert.True(sign.CheckSignature(new HMACSHA1("secret"u8.ToArray())));
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/20429")]
@@ -1516,7 +1516,7 @@ namespace System.Security.Cryptography.Xml.Tests
// 80bits is smaller than the half-size of HMACSHA256
string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#hmac-sha256""><HMACOutputLength>80</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>vPtw7zKVV/JwQg==</SignatureValue><Object Id=""object"">some other text</Object></Signature>";
SignedXml sign = GetSignedXml(xml);
- CheckErratum(sign, new HMACSHA256(Encoding.ASCII.GetBytes("secret")), "80");
+ CheckErratum(sign, new HMACSHA256("secret"u8.ToArray()), "80");
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/20429")]
@@ -1526,7 +1526,7 @@ namespace System.Security.Cryptography.Xml.Tests
// 128 is the half-size of HMACSHA256
string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#hmac-sha256""><HMACOutputLength>128</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>aegpvkAwOL8gN/CjSnW6qw==</SignatureValue><Object Id=""object"">some other text</Object></Signature>";
SignedXml sign = GetSignedXml(xml);
- Assert.True(sign.CheckSignature(new HMACSHA256(Encoding.ASCII.GetBytes("secret"))));
+ Assert.True(sign.CheckSignature(new HMACSHA256("secret"u8.ToArray())));
}
[Fact]
@@ -1534,7 +1534,7 @@ namespace System.Security.Cryptography.Xml.Tests
{
string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#hmac-sha1"" /><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>7/XTsHaBSOnJ/jXD5v0zL6VKYsk=</DigestValue></Reference></SignedInfo><SignatureValue>a0goL9esBUKPqtFYgpp2KST4huk=</SignatureValue><Object Id=""object"">some text</Object></Signature>";
SignedXml sign = GetSignedXml(xml);
- Assert.True(sign.CheckSignature(new HMACSHA1(Encoding.ASCII.GetBytes("secret"))));
+ Assert.True(sign.CheckSignature(new HMACSHA1("secret"u8.ToArray())));
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/20429")]
@@ -1559,7 +1559,7 @@ namespace System.Security.Cryptography.Xml.Tests
</Signature>
";
SignedXml sign = GetSignedXml(xml);
- Assert.Throws<CryptographicException>(() => sign.CheckSignature(new HMACSHA1(Encoding.ASCII.GetBytes("no clue"))));
+ Assert.Throws<CryptographicException>(() => sign.CheckSignature(new HMACSHA1("no clue"u8.ToArray())));
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/20429")]
@@ -1584,7 +1584,7 @@ namespace System.Security.Cryptography.Xml.Tests
</Signature>
";
SignedXml sign = GetSignedXml(xml);
- Assert.Throws<FormatException>(() => sign.CheckSignature(new HMACSHA1(Encoding.ASCII.GetBytes("no clue"))));
+ Assert.Throws<FormatException>(() => sign.CheckSignature(new HMACSHA1("no clue"u8.ToArray())));
}
[Fact]
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.Pem.iOS.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.Pem.iOS.cs
index 6862508a784..a22e8b3ff0d 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.Pem.iOS.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.Pem.iOS.cs
@@ -10,9 +10,6 @@ namespace System.Security.Cryptography.X509Certificates
{
internal sealed partial class AppleCertificatePal : ICertificatePal
{
- // Byte representation of "-----BEGIN "
- private static ReadOnlySpan<byte> PemBegin => new byte[] { 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20 };
-
internal delegate bool DerCallback(ReadOnlySpan<byte> derData, X509ContentType contentType);
internal static bool TryDecodePem(ReadOnlySpan<byte> rawData, DerCallback derCallback)
@@ -27,7 +24,7 @@ namespace System.Security.Cryptography.X509Certificates
// Look for the PEM marker. This doesn't guarantee it will be a valid PEM since we don't check whether
// the marker is at the beginning of line or whether the line is a complete marker. It's just a quick
// check to avoid conversion from bytes to characters if the content is DER encoded.
- if (rawData.IndexOf(PemBegin) < 0)
+ if (rawData.IndexOf("-----BEGIN "u8) < 0)
{
return false;
}
diff --git a/src/libraries/System.Security.Cryptography/tests/Base64TransformsTests.cs b/src/libraries/System.Security.Cryptography/tests/Base64TransformsTests.cs
index 72ee58f6031..704e2ba5e5e 100644
--- a/src/libraries/System.Security.Cryptography/tests/Base64TransformsTests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/Base64TransformsTests.cs
@@ -56,7 +56,7 @@ namespace System.Security.Cryptography.Tests
[Fact]
public void InvalidInput_ToBase64Transform()
{
- byte[] data_3bytes = Text.Encoding.ASCII.GetBytes("aaa");
+ byte[] data_3bytes = "aaa"u8.ToArray();
ICryptoTransform transform = new ToBase64Transform();
AssertExtensions.Throws<ArgumentNullException>("inputBuffer", () => transform.TransformBlock(null, 0, 0, null, 0));
@@ -77,7 +77,7 @@ namespace System.Security.Cryptography.Tests
[Fact]
public void InvalidInput_FromBase64Transform()
{
- byte[] data_4bytes = Text.Encoding.ASCII.GetBytes("aaaa");
+ byte[] data_4bytes = "aaaa"u8.ToArray();
ICryptoTransform transform = new FromBase64Transform();
AssertExtensions.Throws<ArgumentNullException>("inputBuffer", () => transform.TransformBlock(null, 0, 0, null, 0));
diff --git a/src/libraries/System.Security.Cryptography/tests/CryptoStream.cs b/src/libraries/System.Security.Cryptography/tests/CryptoStream.cs
index 68e210472d4..6e877fbf5a0 100644
--- a/src/libraries/System.Security.Cryptography/tests/CryptoStream.cs
+++ b/src/libraries/System.Security.Cryptography/tests/CryptoStream.cs
@@ -304,7 +304,7 @@ namespace System.Security.Cryptography.Tests
var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write, leaveOpen: true))
{
- cryptoStream.Write(Encoding.ASCII.GetBytes("Sample string that's bigger than cryptoAlg.BlockSize"));
+ cryptoStream.Write("Sample string that's bigger than cryptoAlg.BlockSize"u8);
cryptoStream.FlushFinalBlock();
}
diff --git a/src/libraries/System.Security.Cryptography/tests/Rfc2898OneShotTests.cs b/src/libraries/System.Security.Cryptography/tests/Rfc2898OneShotTests.cs
index cd92dc99b57..ab413da8b0f 100644
--- a/src/libraries/System.Security.Cryptography/tests/Rfc2898OneShotTests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/Rfc2898OneShotTests.cs
@@ -289,7 +289,7 @@ namespace System.Security.Cryptography
string password = "password";
int iterations = 16777216;
byte[] expected = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984".HexToByteArray();
- byte[] salt = Encoding.UTF8.GetBytes("salt");
+ ReadOnlySpan<byte> salt = "salt"u8;
byte[] actual = Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, HashAlgorithmName.SHA1, expected.Length);
Assert.Equal(expected, actual);
}
diff --git a/src/libraries/System.Security.Cryptography/tests/TripleDesTests.cs b/src/libraries/System.Security.Cryptography/tests/TripleDesTests.cs
index 64b9c402a5d..f12e0b1cf51 100644
--- a/src/libraries/System.Security.Cryptography/tests/TripleDesTests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/TripleDesTests.cs
@@ -63,7 +63,7 @@ namespace System.Security.Cryptography.Tests
[Fact]
public static void TripleDesCreate()
{
- byte[] inputBytes = Encoding.ASCII.GetBytes("This is a secret message and is a sentence that is longer than a block, it ensures that multi-block functions work.");
+ byte[] inputBytes = "This is a secret message and is a sentence that is longer than a block, it ensures that multi-block functions work."u8.ToArray();
TripleDES tripleDes = TripleDES.Create();
byte[] encryptedBytes;
diff --git a/src/libraries/System.Text.Encoding.Extensions/tests/Fallback.cs b/src/libraries/System.Text.Encoding.Extensions/tests/Fallback.cs
index 3dc2f53edb0..c744b4b5b2d 100644
--- a/src/libraries/System.Text.Encoding.Extensions/tests/Fallback.cs
+++ b/src/libraries/System.Text.Encoding.Extensions/tests/Fallback.cs
@@ -30,7 +30,7 @@ namespace EncodingTests
// Test when the fallback will not occur
encodedBytes = new byte[asciiEncoding.GetByteCount(s_asciiInputStringWinNoFallback)];
numberOfEncodedBytes = asciiEncoding.GetBytes(s_asciiInputStringWinNoFallback, 0, s_asciiInputStringWinNoFallback.Length, encodedBytes, 0);
- Assert.Equal(encodedBytes, new byte[] { (byte)'a', (byte)'b', (byte)'c' });
+ Assert.Equal("abc"u8.ToArray(), encodedBytes);
decodedString = asciiEncoding.GetString(encodedBytes);
Assert.Equal(decodedString, s_asciiInputStringWinNoFallback);
}
diff --git a/src/libraries/System.Text.Encodings.Web/tests/TextEncoderTests.cs b/src/libraries/System.Text.Encodings.Web/tests/TextEncoderTests.cs
index cb26b483e7c..78295e065fc 100644
--- a/src/libraries/System.Text.Encodings.Web/tests/TextEncoderTests.cs
+++ b/src/libraries/System.Text.Encodings.Web/tests/TextEncoderTests.cs
@@ -150,7 +150,7 @@ namespace System.Text.Encodings.Web.Tests
Assert.Equal(OperationStatus.Done, encoder.EncodeUtf8(aggregateInputBytesSoFar.ToArray(), destination, out bytesConsumed, out bytesWritten, isFinalBlock: true));
Assert.Equal(aggregateInputBytesSoFar.Count, bytesConsumed);
Assert.Equal(expectedOutputBytesSoFar.Count + "[FFFD]".Length, bytesWritten);
- Assert.Equal(expectedOutputBytesSoFar.Concat(Encoding.UTF8.GetBytes("[FFFD]")).ToArray(), new Span<byte>(destination, 0, expectedOutputBytesSoFar.Count + "[FFFD]".Length).ToArray());
+ Assert.Equal(expectedOutputBytesSoFar.Concat("[FFFD]"u8.ToArray()), new Span<byte>(destination, 0, expectedOutputBytesSoFar.Count + "[FFFD]".Length).ToArray());
}
// Consume the remainder of this entry and make sure it escaped properly (if needed).
@@ -222,7 +222,7 @@ namespace System.Text.Encodings.Web.Tests
{
// Arrange
- byte[] inputBytes = Encoding.UTF8.GetBytes("\U00000040\U00000400\U00004000\U00040000"); // code units of different lengths
+ byte[] inputBytes = "\U00000040\U00000400\U00004000\U00040000"u8.ToArray(); // code units of different lengths
var encoder = new ConfigurableScalarTextEncoder(_ => true /* allow everything */);
// Act
@@ -239,7 +239,7 @@ namespace System.Text.Encodings.Web.Tests
{
// Arrange
- byte[] inputBytes = Encoding.UTF8.GetBytes("\U00000040\U00000400\U00004000\U00040000"); // code units of different lengths
+ byte[] inputBytes = "\U00000040\U00000400\U00004000\U00040000"u8.ToArray(); // code units of different lengths
var encoder = new ConfigurableScalarTextEncoder(codePoint => codePoint != 0x4000 /* disallow U+4000, allow all else */);
// Act
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TimeOnlyConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TimeOnlyConverter.cs
index 3e66dbb937b..ac0e8ce37fe 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TimeOnlyConverter.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TimeOnlyConverter.cs
@@ -3,30 +3,72 @@
using System.Buffers.Text;
using System.Diagnostics;
-using System.Globalization;
namespace System.Text.Json.Serialization.Converters
{
internal sealed class TimeOnlyConverter : JsonConverter<TimeOnly>
{
- private static readonly TimeSpanConverter s_timeSpanConverter = new TimeSpanConverter();
- private static readonly TimeSpan s_timeOnlyMaxValue = TimeOnly.MaxValue.ToTimeSpan();
+ private const int MinimumTimeOnlyFormatLength = 8; // hh:mm:ss
+ private const int MaximumTimeOnlyFormatLength = 16; // hh:mm:ss.fffffff
+ private const int MaximumEscapedTimeOnlyFormatLength = JsonConstants.MaxExpansionFactorWhileEscaping * MaximumTimeOnlyFormatLength;
public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
- TimeSpan timespan = s_timeSpanConverter.Read(ref reader, typeToConvert, options);
+ if (reader.TokenType != JsonTokenType.String)
+ {
+ ThrowHelper.ThrowInvalidOperationException_ExpectedString(reader.TokenType);
+ }
- if (timespan < TimeSpan.Zero || timespan > s_timeOnlyMaxValue)
+ if (!JsonHelpers.IsInRangeInclusive(reader.ValueLength, MinimumTimeOnlyFormatLength, MaximumEscapedTimeOnlyFormatLength))
{
- ThrowHelper.ThrowJsonException();
+ ThrowHelper.ThrowFormatException(DataType.TimeOnly);
}
+ ReadOnlySpan<byte> source = stackalloc byte[0];
+ if (!reader.HasValueSequence && !reader.ValueIsEscaped)
+ {
+ source = reader.ValueSpan;
+ }
+ else
+ {
+ Span<byte> stackSpan = stackalloc byte[MaximumEscapedTimeOnlyFormatLength];
+ int bytesWritten = reader.CopyString(stackSpan);
+ source = stackSpan.Slice(0, bytesWritten);
+ }
+
+ byte firstChar = source[0];
+ int firstSeparator = source.IndexOfAny((byte)'.', (byte)':');
+ if (!JsonHelpers.IsDigit(firstChar) || firstSeparator < 0 || source[firstSeparator] == (byte)'.')
+ {
+ // Note: Utf8Parser.TryParse permits leading whitespace, negative values
+ // and numbers of days so we need to exclude these cases here.
+ ThrowHelper.ThrowFormatException(DataType.TimeOnly);
+ }
+
+ bool result = Utf8Parser.TryParse(source, out TimeSpan timespan, out int bytesConsumed, 'c');
+
+ // Note: Utf8Parser.TryParse will return true for invalid input so
+ // long as it starts with an integer. Example: "2021-06-18" or
+ // "1$$$$$$$$$$". We need to check bytesConsumed to know if the
+ // entire source was actually valid.
+
+ if (!result || source.Length != bytesConsumed)
+ {
+ ThrowHelper.ThrowFormatException(DataType.TimeOnly);
+ }
+
+ Debug.Assert(TimeOnly.MinValue.ToTimeSpan() <= timespan && timespan <= TimeOnly.MaxValue.ToTimeSpan());
return TimeOnly.FromTimeSpan(timespan);
}
public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options)
{
- s_timeSpanConverter.Write(writer, value.ToTimeSpan(), options);
+ Span<byte> output = stackalloc byte[MaximumTimeOnlyFormatLength];
+
+ bool result = Utf8Formatter.TryFormat(value.ToTimeSpan(), output, out int bytesWritten, 'c');
+ Debug.Assert(result);
+
+ writer.WriteStringValue(output.Slice(0, bytesWritten));
}
}
}
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs
index 53aa3580f44..05f5707890e 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs
@@ -11,17 +11,10 @@ namespace System.Text.Json
{
public static partial class JsonSerializer
{
- internal static readonly byte[] s_idPropertyName
- = new byte[] { (byte)'$', (byte)'i', (byte)'d' };
-
- internal static readonly byte[] s_refPropertyName
- = new byte[] { (byte)'$', (byte)'r', (byte)'e', (byte)'f' };
-
- internal static readonly byte[] s_typePropertyName
- = new byte[] { (byte)'$', (byte)'t', (byte)'y', (byte)'p', (byte)'e' };
-
- internal static readonly byte[] s_valuesPropertyName
- = new byte[] { (byte)'$', (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', (byte)'s' };
+ internal static readonly byte[] s_idPropertyName = "$id"u8.ToArray();
+ internal static readonly byte[] s_refPropertyName = "$ref"u8.ToArray();
+ internal static readonly byte[] s_typePropertyName = "$type"u8.ToArray();
+ internal static readonly byte[] s_valuesPropertyName = "$values"u8.ToArray();
internal static bool TryReadMetadata(JsonConverter converter, JsonTypeInfo jsonTypeInfo, ref Utf8JsonReader reader, ref ReadStack state)
{
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs
index 0e384360934..e7f151dc9df 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs
@@ -628,6 +628,7 @@ namespace System.Text.Json
case DataType.DateOnly:
case DataType.DateTime:
case DataType.DateTimeOffset:
+ case DataType.TimeOnly:
case DataType.TimeSpan:
case DataType.Guid:
case DataType.Version:
@@ -723,6 +724,7 @@ namespace System.Text.Json
DateOnly,
DateTime,
DateTimeOffset,
+ TimeOnly,
TimeSpan,
Base64String,
Guid,
diff --git a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Stream.cs b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Stream.cs
index cb99feac24a..5c96e06c1f2 100644
--- a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Stream.cs
+++ b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Stream.cs
@@ -148,7 +148,7 @@ namespace System.Text.Json.Serialization.Tests
await Assert.ThrowsAsync<NotSupportedException>(async () => await StreamingSerializer.DeserializeWrapper<T>(stream, options));
}
- using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes("{}")))
+ using (MemoryStream stream = new MemoryStream("{}"u8.ToArray()))
{
JsonSerializerOptions options = new JsonSerializerOptions
{
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonElementWriteTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonElementWriteTests.cs
index 2898ab9d862..77218b29b25 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonElementWriteTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonElementWriteTests.cs
@@ -78,7 +78,6 @@ namespace System.Text.Json.Tests
};
const string CharLabel = "char";
- byte[] byteUtf8 = Encoding.UTF8.GetBytes("byte");
using var writer = new Utf8JsonWriter(buffer, options);
if (skipValidation)
@@ -89,7 +88,7 @@ namespace System.Text.Json.Tests
val.WriteTo(writer);
writer.WritePropertyName(CharLabel.AsSpan());
val.WriteTo(writer);
- writer.WritePropertyName(byteUtf8);
+ writer.WritePropertyName("byte"u8);
val.WriteTo(writer);
writer.WritePropertyName(JsonEncodedText.Encode(CharLabel));
val.WriteTo(writer);
@@ -111,7 +110,7 @@ namespace System.Text.Json.Tests
{
Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName(CharLabel));
Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName(CharLabel.AsSpan()));
- Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName(byteUtf8));
+ Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName("byte"u8));
Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName(JsonEncodedText.Encode(CharLabel)));
writer.Flush();
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/ParseTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/ParseTests.cs
index 5c6022f503f..44139de12a5 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/ParseTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/ParseTests.cs
@@ -138,7 +138,7 @@ namespace System.Text.Json.Nodes.Tests
Assert.Null(JsonSerializer.Deserialize<JsonNode>("null"));
Assert.Null(JsonNode.Parse("null"));
- using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes("null")))
+ using (MemoryStream stream = new MemoryStream("null"u8.ToArray()))
{
Assert.Null(JsonNode.Parse(stream));
}
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonReaderStateAndOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonReaderStateAndOptionsTests.cs
index 182691e52f3..997371e7bcb 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonReaderStateAndOptionsTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonReaderStateAndOptionsTests.cs
@@ -103,7 +103,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void ZeroMaxDepthDefaultsTo64()
{
- byte[] dataUtf8 = Encoding.UTF8.GetBytes("{}");
+ byte[] dataUtf8 = "{}"u8.ToArray();
ReadOnlyMemory<byte> dataMemory = dataUtf8;
var firstSegment = new BufferSegment<byte>(dataMemory.Slice(0, 1));
@@ -134,7 +134,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void MaxDepthIsHonored()
{
- byte[] dataUtf8 = Encoding.UTF8.GetBytes("{}");
+ byte[] dataUtf8 = "{}"u8.ToArray();
ReadOnlyMemory<byte> dataMemory = dataUtf8;
var firstSegment = new BufferSegment<byte>(dataMemory.Slice(0, 1));
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/NewtonsoftTests/CustomObjectConverterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/NewtonsoftTests/CustomObjectConverterTests.cs
index 3531efddf16..887910ac5a3 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/NewtonsoftTests/CustomObjectConverterTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/NewtonsoftTests/CustomObjectConverterTests.cs
@@ -138,7 +138,7 @@ namespace System.Text.Json.Tests
Assert.Null(byteArrayClass.NullByteArray);
}
- private static readonly byte[] s_testData = Encoding.UTF8.GetBytes("This is some test data!!!");
+ private static readonly byte[] s_testData = "This is some test data!!!"u8.ToArray();
[Fact]
public void AssertShouldSerializeTest()
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Array.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Array.ReadTests.cs
index 913c9196a08..115e91c909d 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Array.ReadTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Array.ReadTests.cs
@@ -154,7 +154,7 @@ namespace System.Text.Json.Serialization.Tests
var options = new JsonSerializerOptions();
options.ReadCommentHandling = JsonCommentHandling.Skip;
- int[][] i = JsonSerializer.Deserialize<int[][]>(Encoding.UTF8.GetBytes("[[1,2] // Inline [\n,[3, /* Multi\n]] Line*/4]]"), options);
+ int[][] i = JsonSerializer.Deserialize<int[][]>("[[1,2] // Inline [\n,[3, /* Multi\n]] Line*/4]]"u8, options);
Assert.Equal(1, i[0][0]);
Assert.Equal(2, i[0][1]);
Assert.Equal(3, i[1][0]);
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Null.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Null.ReadTests.cs
index 1f8bb6b6753..7a5b8746b03 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Null.ReadTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Null.ReadTests.cs
@@ -188,7 +188,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static async Task ParseNullStringShouldThrowJsonExceptionAsync()
{
- using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("null")))
+ using (var stream = new MemoryStream("null"u8.ToArray()))
{
await Assert.ThrowsAsync<JsonException>(async () => await JsonSerializer.DeserializeAsync<SimpleStruct>(stream));
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ReadValueTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ReadValueTests.cs
index e7eb6f5b314..78cd158163c 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ReadValueTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ReadValueTests.cs
@@ -61,7 +61,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void ReaderOptionsWinMaxDepth()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[[]]");
+ byte[] utf8 = "[[]]"u8.ToArray();
var readerOptions = new JsonReaderOptions
{
@@ -114,7 +114,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void ReaderOptionsWinTrailingCommas()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[1, 2, 3,]");
+ byte[] utf8 = "[1, 2, 3,]"u8.ToArray();
var serializerOptions = new JsonSerializerOptions
{
@@ -151,7 +151,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void ReaderOptionsWinComments()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[1, 2, /* some comment */ 3]");
+ byte[] utf8 = "[1, 2, /* some comment */ 3]"u8.ToArray();
var serializerOptions = new JsonSerializerOptions
{
@@ -175,7 +175,7 @@ namespace System.Text.Json.Serialization.Tests
ReadAndVerify(utf8, serializerOptions: null, readerOptions, utf8.Length);
ReadAndVerify(utf8, serializerOptions, readerOptions, utf8.Length);
- byte[] utf8_CommentsAfter = Encoding.UTF8.GetBytes("[1, 2, 3]/* some comment */");
+ byte[] utf8_CommentsAfter = "[1, 2, 3]/* some comment */"u8.ToArray();
ReadAndVerify(utf8_CommentsAfter, serializerOptions, readerOptions: default, expectedLength: "[1, 2, 3]".Length);
ReadAndVerify(utf8_CommentsAfter, serializerOptions, readerOptions, expectedLength: "[1, 2, 3]".Length);
@@ -193,7 +193,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void OnInvalidReaderIsRestored()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[1, 2, 3}");
+ byte[] utf8 = "[1, 2, 3}"u8.ToArray();
var reader = new Utf8JsonReader(utf8, isFinalBlock: true, state: default);
reader.Read();
@@ -213,7 +213,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void DataRemaining()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("{\"Foo\":\"abc\", \"Bar\":123}");
+ byte[] utf8 = "{\"Foo\":\"abc\", \"Bar\":123}"u8.ToArray();
var reader = new Utf8JsonReader(utf8, isFinalBlock: true, state: default);
reader.Read();
@@ -233,7 +233,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void ReadPropertyName()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("{\"Foo\":[1, 2, 3]}");
+ byte[] utf8 = "{\"Foo\":[1, 2, 3]}"u8.ToArray();
var reader = new Utf8JsonReader(utf8, isFinalBlock: true, state: default);
reader.Read();
@@ -265,7 +265,7 @@ namespace System.Text.Json.Serialization.Tests
[InlineData(false)]
public static void ReadObjectMultiSegment(bool isFinalBlock)
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[1, 2, {\"Foo\":[1, 2, 3]}]");
+ byte[] utf8 = "[1, 2, {\"Foo\":[1, 2, 3]}]"u8.ToArray();
ReadOnlySequence<byte> sequence = JsonTestHelper.CreateSegments(utf8);
var reader = new Utf8JsonReader(sequence, isFinalBlock, state: default);
@@ -292,7 +292,7 @@ namespace System.Text.Json.Serialization.Tests
public static void NotEnoughData(bool isFinalBlock)
{
{
- byte[] utf8 = Encoding.UTF8.GetBytes("\"start of string");
+ byte[] utf8 = "\"start of string"u8.ToArray();
var reader = new Utf8JsonReader(utf8, isFinalBlock, state: default);
Assert.Equal(0, reader.BytesConsumed);
@@ -310,7 +310,7 @@ namespace System.Text.Json.Serialization.Tests
}
{
- byte[] utf8 = Encoding.UTF8.GetBytes("{");
+ byte[] utf8 = "{"u8.ToArray();
var reader = new Utf8JsonReader(utf8, isFinalBlock, state: default);
reader.Read();
@@ -333,7 +333,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void EndObjectOrArrayIsInvalid()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[{}]");
+ byte[] utf8 = "[{}]"u8.ToArray();
var reader = new Utf8JsonReader(utf8, isFinalBlock: true, state: default);
reader.Read();
@@ -575,7 +575,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void ReadPartial()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[1, 2, 3]");
+ byte[] utf8 = "[1, 2, 3]"u8.ToArray();
var reader = new Utf8JsonReader(utf8, isFinalBlock: true, state: default);
reader.Read();
int[] array = JsonSerializer.Deserialize<int[]>(ref reader);
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SpanTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SpanTests.cs
index c01ce57372c..d19f790523b 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SpanTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SpanTests.cs
@@ -60,8 +60,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public static void ParseUntyped()
{
- byte[] bytes = Encoding.UTF8.GetBytes("42");
- object obj = JsonSerializer.Deserialize(bytes, typeof(object));
+ object obj = JsonSerializer.Deserialize("42"u8, typeof(object));
Assert.IsType<JsonElement>(obj);
JsonElement element = (JsonElement)obj;
Assert.Equal(JsonValueKind.Number, element.ValueKind);
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.ReadTests.cs
index 5112265009e..10bb1edc191 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.ReadTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.ReadTests.cs
@@ -69,7 +69,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public async Task ReadPrimitivesWithTrailingTriviaAsync()
{
- using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(" 1\t// Comment\r\n/* Multi\r\nLine */")))
+ using (MemoryStream stream = new MemoryStream(" 1\t// Comment\r\n/* Multi\r\nLine */"u8.ToArray()))
{
JsonSerializerOptions options = new JsonSerializerOptions
{
@@ -85,7 +85,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public async Task ReadReferenceTypeCollectionPassingNullValueAsync()
{
- using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes("null")))
+ using (MemoryStream stream = new MemoryStream("null"u8.ToArray()))
{
IList<object> referenceTypeCollection = await Serializer.DeserializeWrapper<IList<object>>(stream);
Assert.Null(referenceTypeCollection);
@@ -95,7 +95,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public async Task ReadValueTypeCollectionPassingNullValueAsync()
{
- using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes("null")))
+ using (MemoryStream stream = new MemoryStream("null"u8.ToArray()))
{
IList<int> valueTypeCollection = await Serializer.DeserializeWrapper<IList<int>>(stream);
Assert.Null(valueTypeCollection);
@@ -164,8 +164,7 @@ namespace System.Text.Json.Serialization.Tests
static Stream CreateStream(int count)
{
- byte[] objBytes = Encoding.UTF8.GetBytes(
- @"{""Test"":{},""Test2"":[],""Test3"":{""Value"":{}},""PersonType"":0,""Id"":2}");
+ byte[] objBytes = @"{""Test"":{},""Test2"":[],""Test3"":{""Value"":{}},""PersonType"":0,""Id"":2}"u8.ToArray();
byte[] utf8Bom = Encoding.UTF8.GetPreamble();
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs
index 257d354ef2f..031454bf99e 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs
@@ -670,8 +670,11 @@ namespace System.Text.Json.Serialization.Tests
[InlineData("\\u0032\\u0034\\u003A\\u0030\\u0030\\u003A\\u0030\\u0030")]
[InlineData("00:60:00")]
[InlineData("00:00:60")]
+ [InlineData("-00:00:00")]
[InlineData("00:00:00.00000009")]
[InlineData("900000000.00:00:00")]
+ [InlineData("1.00:00:00")]
+ [InlineData("0.00:00:00")]
[InlineData("1:00:00")] // 'g' Format
[InlineData("1:2:00:00")] // 'g' Format
[InlineData("+00:00:00")]
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.WriteTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.WriteTests.cs
index 257ec5b069e..af83df3f969 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.WriteTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.WriteTests.cs
@@ -49,7 +49,7 @@ namespace System.Text.Json.Serialization.Tests
{
Span<byte> json = JsonSerializer.SerializeToUtf8Bytes(1);
- Assert.Equal(Encoding.UTF8.GetBytes("1"), json.ToArray());
+ Assert.Equal("1"u8.ToArray(), json.ToArray());
}
{
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/WriteValueTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/WriteValueTests.cs
index 66b89f1c151..2491f20d734 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/WriteValueTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/WriteValueTests.cs
@@ -67,7 +67,7 @@ namespace System.Text.Json.Serialization.Tests
[Fact]
public async static void NullValueWithNullableSuccess()
{
- byte[] nullUtf8Literal = Encoding.UTF8.GetBytes("null");
+ byte[] nullUtf8Literal = "null"u8.ToArray();
var stream = new MemoryStream();
Utf8JsonWriter writer = new Utf8JsonWriter(stream);
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.MultiSegment.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.MultiSegment.cs
index 331b174a52e..0a1d2a41149 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.MultiSegment.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.MultiSegment.cs
@@ -15,7 +15,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void InitialStateMultiSegment()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("1");
+ byte[] utf8 = "1"u8.ToArray();
ReadOnlySequence<byte> sequence = JsonTestHelper.GetSequence(utf8, 1);
var json = new Utf8JsonReader(sequence, isFinalBlock: true, state: default);
@@ -395,7 +395,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void InitialStateSimpleCtorMultiSegment()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("1");
+ byte[] utf8 = "1"u8.ToArray();
ReadOnlySequence<byte> sequence = JsonTestHelper.GetSequence(utf8, 1);
var json = new Utf8JsonReader(sequence);
@@ -420,7 +420,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void StateRecoveryMultiSegment()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[1]");
+ byte[] utf8 = "[1]"u8.ToArray();
ReadOnlySequence<byte> sequence = JsonTestHelper.GetSequence(utf8, 1);
var json = new Utf8JsonReader(sequence, isFinalBlock: false, state: default);
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.ValueTextEquals.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.ValueTextEquals.cs
index 69df6ce2621..ac092e7f439 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.ValueTextEquals.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.ValueTextEquals.cs
@@ -13,39 +13,32 @@ namespace System.Text.Json.Tests
[Fact]
public static void TestTextEqualsBasic()
{
- byte[] connectionId = Encoding.UTF8.GetBytes("connectionId");
- byte[] availableTransports = Encoding.UTF8.GetBytes("availableTransports");
- byte[] value123 = Encoding.UTF8.GetBytes("123");
- byte[] embeddedQuotes = Encoding.UTF8.GetBytes("My name is \"Ahson\"");
bool foundId = false;
bool foundTransports = false;
bool foundValue = false;
bool foundArrayValue = false;
- string jsonString = "{\"conne\\u0063tionId\":\"123\",\"availableTransports\":[\"My name is \\\"Ahson\\\"\"]}";
- byte[] utf8Data = Encoding.UTF8.GetBytes(jsonString);
-
- var json = new Utf8JsonReader(utf8Data, isFinalBlock: true, state: default);
+ var json = new Utf8JsonReader("{\"conne\\u0063tionId\":\"123\",\"availableTransports\":[\"My name is \\\"Ahson\\\"\"]}"u8, isFinalBlock: true, state: default);
while (json.Read())
{
if (json.TokenType == JsonTokenType.PropertyName)
{
- if (json.ValueTextEquals(connectionId) && json.ValueTextEquals("connectionId".AsSpan()))
+ if (json.ValueTextEquals("connectionId"u8) && json.ValueTextEquals("connectionId".AsSpan()))
{
foundId = true;
}
- else if (json.ValueTextEquals(availableTransports) && json.ValueTextEquals("availableTransports".AsSpan()))
+ else if (json.ValueTextEquals("availableTransports"u8) && json.ValueTextEquals("availableTransports".AsSpan()))
{
foundTransports = true;
}
}
else if (json.TokenType == JsonTokenType.String)
{
- if (json.ValueTextEquals(value123) && json.ValueTextEquals("123".AsSpan()))
+ if (json.ValueTextEquals("123"u8) && json.ValueTextEquals("123".AsSpan()))
{
foundValue = true;
}
- else if (json.ValueTextEquals(embeddedQuotes) && json.ValueTextEquals("My name is \"Ahson\"".AsSpan()))
+ else if (json.ValueTextEquals("My name is \"Ahson\""u8) && json.ValueTextEquals("My name is \"Ahson\"".AsSpan()))
{
foundArrayValue = true;
}
@@ -549,9 +542,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void TestTextEqualsMismatchMultiSegment()
{
- string jsonString = "\"Hi, \\\"Ahson\\\"!\"";
- byte[] lookup = Encoding.UTF8.GetBytes("Hello, \"Ahson\"");
- byte[] utf8Data = Encoding.UTF8.GetBytes(jsonString);
+ byte[] utf8Data = "\"Hi, \\\"Ahson\\\"!\""u8.ToArray();
bool found = false;
// Segment 1: "Hi, \"A
@@ -563,7 +554,7 @@ namespace System.Text.Json.Tests
{
if (json.TokenType == JsonTokenType.String)
{
- if (json.ValueTextEquals(lookup) ||
+ if (json.ValueTextEquals("Hello, \"Ahson\""u8) ||
json.ValueTextEquals("Hello, \"Ahson\"".AsSpan()) ||
json.ValueTextEquals("Hello, \"Ahson\""))
{
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs
index 43f896e83c6..0be0fc7dcb1 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs
@@ -114,7 +114,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void InitialState()
{
- var json = new Utf8JsonReader(Encoding.UTF8.GetBytes("1"), isFinalBlock: true, state: default);
+ var json = new Utf8JsonReader("1"u8, isFinalBlock: true, state: default);
Assert.Equal(0, json.BytesConsumed);
Assert.Equal(0, json.TokenStartIndex);
@@ -138,7 +138,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void InitialStateSimpleCtor()
{
- var json = new Utf8JsonReader(Encoding.UTF8.GetBytes("1"));
+ var json = new Utf8JsonReader("1"u8);
Assert.Equal(0, json.BytesConsumed);
Assert.Equal(0, json.TokenStartIndex);
@@ -162,7 +162,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void StateRecovery()
{
- byte[] utf8 = Encoding.UTF8.GetBytes("[1]");
+ ReadOnlySpan<byte> utf8 = "[1]"u8;
var json = new Utf8JsonReader(utf8, isFinalBlock: false, state: default);
Assert.Equal(0, json.BytesConsumed);
@@ -199,7 +199,7 @@ namespace System.Text.Json.Tests
JsonReaderState state = json.CurrentState;
- json = new Utf8JsonReader(utf8.AsSpan((int)json.BytesConsumed), isFinalBlock: true, state);
+ json = new Utf8JsonReader(utf8.Slice((int)json.BytesConsumed), isFinalBlock: true, state);
Assert.Equal(0, json.BytesConsumed); // Not retained
Assert.Equal(0, json.TokenStartIndex); // Not retained
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs
index eb59af3510c..5272c1bb561 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs
@@ -57,13 +57,13 @@ namespace System.Text.Json.Tests
Action<byte[]> validate;
validate = (data) => Assert.Equal(123456789, JsonSerializer.Deserialize<long>(data));
- yield return new object[] { Encoding.UTF8.GetBytes("123456789"), validate };
+ yield return new object[] { "123456789"u8.ToArray(), validate };
validate = (data) => Assert.Equal(1234.56789, JsonSerializer.Deserialize<double>(data));
- yield return new object[] { Encoding.UTF8.GetBytes("1234.56789"), validate };
+ yield return new object[] { "1234.56789"u8.ToArray(), validate };
validate = (data) => Assert.Equal(1234.56789, JsonSerializer.Deserialize<double>(data));
- yield return new object[] { Encoding.UTF8.GetBytes(" 1234.56789 "), validate };
+ yield return new object[] { " 1234.56789 "u8.ToArray(), validate };
validate = (data) => Assert.Equal(@"Hello", JsonSerializer.Deserialize<string>(data));
yield return new object[] { Encoding.UTF8.GetBytes(@"""Hello"""), validate };
@@ -110,7 +110,7 @@ namespace System.Text.Json.Tests
};
yield return new object[] { json, validate };
- json = Encoding.UTF8.GetBytes("[ 1, 1,1,1,1 ] ");
+ json = "[ 1, 1,1,1,1 ] "u8.ToArray();
validate = (data) =>
{
foreach (int val in JsonSerializer.Deserialize<int[]>(data))
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 4ce5bc05542..732677fe017 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
@@ -530,7 +530,7 @@ namespace System.Text.Json.Tests
// Account for the fact that an encoder might write a literal replacement character or its
// escaped representation, and both forms are equally valid.
- if (span.StartsWith(new byte[] { 0xEF, 0xBF, 0xBD })) { return true; } // literal U+FFFD (as UTF-8)
+ if (span.StartsWith("\uFFFD"u8)) { return true; }
if (span.Length >= 6)
{
if (span[0] == (byte)'\\' && span[1] == (byte)'u'
@@ -1416,7 +1416,7 @@ namespace System.Text.Json.Tests
var output = new FixedSizedBufferWriter(InitialGrowthSize);
var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
- byte[] utf8String = Encoding.UTF8.GetBytes("this is a string long enough to overflow the buffer and cause an exception to be thrown.");
+ byte[] utf8String = "this is a string long enough to overflow the buffer and cause an exception to be thrown."u8.ToArray();
using var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -1436,7 +1436,7 @@ namespace System.Text.Json.Tests
await using var jsonUtf8 = new Utf8JsonWriter(stream, options);
- byte[] utf8String = Encoding.UTF8.GetBytes("some string 1234");
+ byte[] utf8String = "some string 1234"u8.ToArray();
jsonUtf8.WriteStartArray();
for (int i = 0; i < 10_000; i++)
@@ -2316,14 +2316,14 @@ namespace System.Text.Json.Tests
jsonUtf8.WritePropertyName("test name");
jsonUtf8.WritePropertyName(JsonEncodedText.Encode("test name"));
jsonUtf8.WritePropertyName("test name".AsSpan());
- jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes("test name"));
+ jsonUtf8.WritePropertyName("test name"u8.ToArray());
}
else
{
Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName(JsonEncodedText.Encode("test name")));
Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name".AsSpan()));
- Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes("test name")));
+ Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"u8.ToArray()));
}
}
@@ -2833,7 +2833,7 @@ namespace System.Text.Json.Tests
using var jsonUtf8 = new Utf8JsonWriter(output, options);
jsonUtf8.WriteStartObject();
- jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes("foo1"));
+ jsonUtf8.WritePropertyName("foo1"u8);
jsonUtf8.WriteStringValue("bar1");
jsonUtf8.WritePropertyName("foo2");
jsonUtf8.WriteStringValue("bar2");
@@ -2895,9 +2895,9 @@ namespace System.Text.Json.Tests
jsonUtf8.WriteStartObject();
for (int i = 0; i < 999; i++)
{
- jsonUtf8.WriteStartObject(Encoding.UTF8.GetBytes("name"));
+ jsonUtf8.WriteStartObject("name"u8);
}
- Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteStartArray(Encoding.UTF8.GetBytes("name")));
+ Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteStartArray("name"u8));
}
using (var jsonUtf8 = new Utf8JsonWriter(output, options))
@@ -3107,7 +3107,7 @@ namespace System.Text.Json.Tests
using (var jsonUtf8 = new Utf8JsonWriter(output, options))
{
jsonUtf8.WriteStartObject();
- Assert.Throws<ArgumentException>(() => jsonUtf8.WriteBase64String(Encoding.UTF8.GetBytes("foo"), value));
+ Assert.Throws<ArgumentException>(() => jsonUtf8.WriteBase64String("foo"u8, value));
}
using (var jsonUtf8 = new Utf8JsonWriter(output, options))
@@ -3169,7 +3169,7 @@ namespace System.Text.Json.Tests
using (var jsonUtf8 = new Utf8JsonWriter(output, options))
{
jsonUtf8.WriteStartObject();
- jsonUtf8.WriteBase64String(Encoding.UTF8.GetBytes("foo"), value);
+ jsonUtf8.WriteBase64String("foo"u8, value);
jsonUtf8.WriteEndObject();
}
@@ -3231,7 +3231,7 @@ namespace System.Text.Json.Tests
using (var jsonUtf8 = new Utf8JsonWriter(output, options))
{
jsonUtf8.WriteStartObject();
- jsonUtf8.WriteBase64String(Encoding.UTF8.GetBytes("foo"), value);
+ jsonUtf8.WriteBase64String("foo"u8, value);
jsonUtf8.WriteEndObject();
}
JsonTestHelper.AssertContents(expectedJson, output);
@@ -3290,8 +3290,8 @@ namespace System.Text.Json.Tests
JsonEncodedText encodedPropertyName = JsonEncodedText.Encode(propertyName);
JsonEncodedText encodedValue = JsonEncodedText.Encode(value);
- byte[] utf8PropertyName = Encoding.UTF8.GetBytes("message");
- byte[] utf8Value = Encoding.UTF8.GetBytes("Hello, World!");
+ ReadOnlySpan<byte> utf8PropertyName = "message"u8;
+ ReadOnlySpan<byte> utf8Value = "Hello, World!"u8;
var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
@@ -4971,7 +4971,7 @@ namespace System.Text.Json.Tests
jsonUtf8.WriteStartArray("property name".AsSpan());
break;
case 2:
- jsonUtf8.WriteStartArray(Encoding.UTF8.GetBytes("property name"));
+ jsonUtf8.WriteStartArray("property name"u8);
break;
}
@@ -5060,7 +5060,7 @@ namespace System.Text.Json.Tests
jsonUtf8.WriteStartObject("property name".AsSpan());
break;
case 2:
- jsonUtf8.WriteStartObject(Encoding.UTF8.GetBytes("property name"));
+ jsonUtf8.WriteStartObject("property name"u8);
break;
}
@@ -5149,7 +5149,7 @@ namespace System.Text.Json.Tests
jsonUtf8.WriteStartArray("message".AsSpan());
break;
case 2:
- jsonUtf8.WriteStartArray(Encoding.UTF8.GetBytes("message"));
+ jsonUtf8.WriteStartArray("message"u8);
break;
}
@@ -5337,7 +5337,7 @@ namespace System.Text.Json.Tests
jsonUtf8.WriteNumber("message".AsSpan(), value);
break;
case 2:
- jsonUtf8.WriteNumber(Encoding.UTF8.GetBytes("message"), value);
+ jsonUtf8.WriteNumber("message"u8, value);
break;
case 3:
jsonUtf8.WritePropertyName("message");
@@ -5383,7 +5383,7 @@ namespace System.Text.Json.Tests
jsonUtf8.WriteNumber("message".AsSpan(), value);
break;
case 2:
- jsonUtf8.WriteNumber(Encoding.UTF8.GetBytes("message"), value);
+ jsonUtf8.WriteNumber("message"u8, value);
break;
case 3:
jsonUtf8.WritePropertyName("message");
@@ -5429,7 +5429,7 @@ namespace System.Text.Json.Tests
jsonUtf8.WriteNumber("message".AsSpan(), value);
break;
case 2:
- jsonUtf8.WriteNumber(Encoding.UTF8.GetBytes("message"), value);
+ jsonUtf8.WriteNumber("message"u8, value);
break;
case 3:
jsonUtf8.WritePropertyName("message");
@@ -6913,7 +6913,7 @@ namespace System.Text.Json.Tests
public static void WriteString_NullPropertyName_ReadOnlySpan_Byte()
{
WriteNullPropertyName_Simple(
- Encoding.UTF8.GetBytes("utf8"),
+ "utf8"u8.ToArray(),
"\"utf8\"",
(writer, name, value) => writer.WriteString(name, value),
(writer, name, value) => writer.WriteString(name, value),
@@ -7017,7 +7017,7 @@ namespace System.Text.Json.Tests
[Fact]
public static void WriteStringValue_ReadOnlySpanBytesProperty_NullString()
{
- byte[] propertyName = Encoding.UTF8.GetBytes("propUtf8");
+ byte[] propertyName = "propUtf8"u8.ToArray();
WriteNullValue_InObject(
"\"propUtf8\":\"\"",
diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs
index 9aced318a12..8e6b495931e 100644
--- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs
+++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs
@@ -3379,8 +3379,9 @@ namespace System.Text.RegularExpressions.Generator
// and thus it needs to be pushed on to the backtracking stack.
bool isInLoop = rm.Analysis.IsInLoop(node);
EmitStackPush(
- !isInLoop ? new[] { "pos" } :
- iterationMayBeEmpty ? new[] { "pos", iterationCount, startingPos!, sawEmpty! } :
+ !isInLoop ? (expressionHasCaptures ? new[] { "pos", "base.Crawlpos()" } : new[] { "pos" }) :
+ iterationMayBeEmpty ? (expressionHasCaptures ? new[] { "pos", iterationCount, startingPos!, sawEmpty!, "base.Crawlpos()" } : new[] { "pos", iterationCount, startingPos!, sawEmpty! }) :
+ expressionHasCaptures ? new[] { "pos", iterationCount, "base.Crawlpos()"} :
new[] { "pos", iterationCount });
string skipBacktrack = ReserveName("LazyLoopSkipBacktrack");
@@ -3395,6 +3396,10 @@ namespace System.Text.RegularExpressions.Generator
// We're backtracking. Check the timeout.
EmitTimeoutCheckIfNeeded(writer, rm);
+ if (expressionHasCaptures)
+ {
+ EmitUncaptureUntil(StackPop());
+ }
EmitStackPop(
!isInLoop ? new[] { "pos" } :
iterationMayBeEmpty ? new[] { sawEmpty!, startingPos!, iterationCount, "pos" } :
diff --git a/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx b/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx
index e2d170c5ab9..b4abcc3264b 100644
--- a/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx
+++ b/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx
@@ -261,6 +261,10 @@
<value>RegexOptions.NonBacktracking is not supported in conjunction with expressions containing: '{0}'.</value>
<comment>{Locked="RegexOptions.NonBacktracking"}</comment>
</data>
+ <data name="NotSupported_NonBacktrackingUnsafeSize" xml:space="preserve">
+ <value>The specified pattern with RegexOptions.NonBacktracking could result in an automata as large as '{0}' nodes, which is larger than the configured limit of '{1}'.</value>
+ <comment>{Locked="RegexOptions.NonBacktracking"}</comment>
+ </data>
<data name="ExpressionDescription_Backreference" xml:space="preserve">
<value>backreference (\\ number)</value>
</data>
diff --git a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj
index dc2c33f5cf8..952ab67d9f9 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj
+++ b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj
@@ -77,10 +77,11 @@
<Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexKind.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexInfo.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexMatcher.cs" />
- <Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexRunnerFactory.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexMatcher.Dgml.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexMatcher.Explore.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexMatcher.Sample.cs" />
+ <Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexRunnerFactory.cs" />
+ <Compile Include="System\Text\RegularExpressions\Symbolic\SymbolicRegexThresholds.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\UInt64Solver.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\UnicodeCategoryConditions.cs" />
<Compile Include="System\Text\RegularExpressions\Symbolic\UnicodeCategoryRanges.cs" />
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
index 134ac1cd2fc..943b0363ea2 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
@@ -3811,20 +3811,13 @@ namespace System.Text.RegularExpressions
Sub();
Stloc(iterationCount);
- if (expressionHasCaptures)
- {
- // capturepos = base.runstack[--stackpos];
- // while (base.Crawlpos() > capturepos) base.Uncapture();
- using RentedLocalBuilder poppedCrawlPos = RentInt32Local();
- EmitStackPop();
- Stloc(poppedCrawlPos);
- EmitUncaptureUntil(poppedCrawlPos);
- }
-
+ // poppedCrawlPos = base.runstack[--stackpos];
+ // while (base.Crawlpos() > poppedCrawlPos) base.Uncapture();
// sawEmpty = base.runstack[--stackpos];
// startingPos = base.runstack[--stackpos];
// pos = base.runstack[--stackpos];
// slice = inputSpan.Slice(pos);
+ EmitUncaptureUntilPopped();
if (iterationMayBeEmpty)
{
EmitStackPop();
@@ -3889,7 +3882,7 @@ namespace System.Text.RegularExpressions
// base.runstack[stackpos++] = startingPos;
// base.runstack[stackpos++] = sawEmpty;
bool isInLoop = analysis.IsInLoop(node);
- EmitStackResizeIfNeeded(1 + (isInLoop ? 1 + (iterationMayBeEmpty ? 2 : 0) : 0));
+ EmitStackResizeIfNeeded(1 + (isInLoop ? 1 + (iterationMayBeEmpty ? 2 : 0) : 0) + (expressionHasCaptures ? 1 : 0));
EmitStackPush(() => Ldloc(pos));
if (isInLoop)
{
@@ -3900,6 +3893,10 @@ namespace System.Text.RegularExpressions
EmitStackPush(() => Ldloc(sawEmpty!));
}
}
+ if (expressionHasCaptures)
+ {
+ EmitStackPush(() => { Ldthis(); Call(s_crawlposMethod); });
+ }
Label skipBacktrack = DefineLabel();
BrFar(skipBacktrack);
@@ -3912,6 +3909,10 @@ namespace System.Text.RegularExpressions
// We're backtracking. Check the timeout.
EmitTimeoutCheckIfNeeded();
+ // int poppedCrawlPos = base.runstack[--stackpos];
+ // while (base.Crawlpos() > poppedCrawlPos) base.Uncapture();
+ EmitUncaptureUntilPopped();
+
if (isInLoop)
{
// sawEmpty = base.runstack[--stackpos];
@@ -4749,24 +4750,20 @@ namespace System.Text.RegularExpressions
BltFar(originalDoneLabel);
// pos = base.runstack[--stackpos];
+ // slice = inputSpan.Slice(pos);
// startingPos = base.runstack[--stackpos];
+ // int poppedCrawlPos = base.runstack[--stackpos];
+ // while (base.Crawlpos() > poppedCrawlPos) base.Uncapture();
EmitStackPop();
Stloc(pos);
+ SliceInputSpan();
if (startingPos is not null)
{
EmitStackPop();
Stloc(startingPos);
}
- if (expressionHasCaptures)
- {
- // int poppedCrawlPos = base.runstack[--stackpos];
- // while (base.Crawlpos() > poppedCrawlPos) base.Uncapture();
- using RentedLocalBuilder poppedCrawlPos = RentInt32Local();
- EmitStackPop();
- Stloc(poppedCrawlPos);
- EmitUncaptureUntil(poppedCrawlPos);
- }
- SliceInputSpan();
+ EmitUncaptureUntilPopped();
+
// If there's a required minimum iteration count, validate now that we've processed enough iterations.
if (minIterations > 0)
@@ -4891,6 +4888,23 @@ namespace System.Text.RegularExpressions
}
}
+ // <summary>
+ // If the expression contains captures, pops a crawl position from the stack and uncaptures
+ // until that position is reached.
+ // </summary>
+ void EmitUncaptureUntilPopped()
+ {
+ if (expressionHasCaptures)
+ {
+ // poppedCrawlPos = base.runstack[--stackpos];
+ // while (base.Crawlpos() > poppedCrawlPos) base.Uncapture();
+ using RentedLocalBuilder poppedCrawlPos = RentInt32Local();
+ EmitStackPop();
+ Stloc(poppedCrawlPos);
+ EmitUncaptureUntil(poppedCrawlPos);
+ }
+ }
+
void EmitStackResizeIfNeeded(int count)
{
Debug.Assert(count >= 1);
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/DfaMatchingState.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/DfaMatchingState.cs
index 9b315652bba..30c907fc938 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/DfaMatchingState.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/DfaMatchingState.cs
@@ -23,8 +23,6 @@ namespace System.Text.RegularExpressions.Symbolic
internal int Id { get; set; }
- internal bool IsInitialState { get; set; }
-
/// <summary>This is a deadend state</summary>
internal bool IsDeadend => Node.IsNothing;
@@ -130,7 +128,7 @@ namespace System.Text.RegularExpressions.Symbolic
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal bool IsNullable(uint nextCharKind)
+ internal bool IsNullableFor(uint nextCharKind)
{
Debug.Assert(nextCharKind is 0 or CharKind.BeginningEnd or CharKind.Newline or CharKind.WordLetter or CharKind.NewLineS);
uint context = CharKind.Context(PrevCharKind, nextCharKind);
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexBuilder.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexBuilder.cs
index 4a6db4bd746..363ab761acc 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexBuilder.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexBuilder.cs
@@ -114,13 +114,54 @@ namespace System.Text.RegularExpressions.Symbolic
/// </summary>
internal DfaMatchingState<TSet>[]? _stateArray;
internal DfaMatchingState<TSet>[]? _capturingStateArray;
+
+ /// <summary>
+ /// Maps state IDs to context-independent information for all states in <see cref="_stateArray"/>.
+ /// </summary>
+ internal byte[]? _stateInfo;
+
+ // Bit masks for decoding elements of _stateInfo
+ private const int isInitialMask = 0b0001;
+ private const int isDeadendMask = 0b0010;
+ private const int isNullableMask = 0b0100;
+ private const int canBeNullableMask = 0b1000;
+
+ /// <summary>Assign the context-independent information for the given state.</summary>
+ internal void SetStateInfo(int stateId, bool isInitial, bool isDeadend, bool isNullable, bool canBeNullable)
+ {
+ Debug.Assert(_stateInfo is not null);
+ byte info = 0;
+ if (isInitial)
+ info |= isInitialMask;
+ if (isDeadend)
+ info |= isDeadendMask;
+ if (isNullable)
+ info |= isNullableMask;
+ if (canBeNullable)
+ info |= canBeNullableMask;
+ _stateInfo[stateId] = info;
+ }
+
+ /// <summary>Get context-independent information for the given state.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal (bool IsInitial, bool IsDeadend, bool IsNullable, bool CanBeNullable) GetStateInfo(int stateId)
+ {
+ Debug.Assert(_stateInfo is not null);
+ byte info = _stateInfo[stateId];
+ return (
+ (info & isInitialMask) != 0,
+ (info & isDeadendMask) != 0,
+ (info & isNullableMask) != 0,
+ (info & canBeNullableMask) != 0);
+ }
+
/// <remarks>
/// For these "delta" arrays, technically Volatile.Read should be used to read out an element,
/// but in practice that's not needed on the runtimes in use (though that needs to be documented
/// via https://github.com/dotnet/runtime/issues/63474), and use of Volatile.Read is
/// contributing non-trivial overhead (https://github.com/dotnet/runtime/issues/65789).
/// </remarks>
- internal DfaMatchingState<TSet>?[]? _delta;
+ internal int[]? _delta;
internal List<(DfaMatchingState<TSet>, DerivativeEffect[])>?[]? _capturingDelta;
private const int InitialStateLimit = 1024;
@@ -170,10 +211,11 @@ namespace System.Text.RegularExpressions.Symbolic
{
_stateArray = new DfaMatchingState<TSet>[InitialStateLimit];
_capturingStateArray = new DfaMatchingState<TSet>[InitialStateLimit];
+ _stateInfo = new byte[InitialStateLimit];
// the extra +1 slot with id minterms.Length is reserved for \Z (last occurrence of \n)
_mintermsLog = BitOperations.Log2((uint)_minterms.Length) + 1;
- _delta = new DfaMatchingState<TSet>[InitialStateLimit << _mintermsLog];
+ _delta = new int[InitialStateLimit << _mintermsLog];
_capturingDelta = new List<(DfaMatchingState<TSet>, DerivativeEffect[])>[InitialStateLimit << _mintermsLog];
}
@@ -208,10 +250,10 @@ namespace System.Text.RegularExpressions.Symbolic
}
/// <summary>Returns the span from <see cref="_delta"/> that may contain transitions for the given state</summary>
- internal Span<DfaMatchingState<TSet>?> GetDeltasFor(DfaMatchingState<TSet> state)
+ internal Span<int> GetDeltasFor(DfaMatchingState<TSet> state)
{
if (_delta is null || _minterms is null)
- return Span<DfaMatchingState<TSet>?>.Empty;
+ return Span<int>.Empty;
int numMinterms = state.StartsWithLineAnchor ? _minterms.Length + 1 : _minterms.Length;
return _delta.AsSpan(state.Id << _mintermsLog, numMinterms);
}
@@ -453,8 +495,9 @@ namespace System.Text.RegularExpressions.Symbolic
/// <param name="node">the pattern that this state will represent</param>
/// <param name="prevCharKind">the kind of the character that led to this state</param>
/// <param name="capturing">whether to use the separate space of states with capturing transitions or not</param>
+ /// <param name="isInitialState">whether to mark the state as an initial state or not</param>
/// <returns></returns>
- public DfaMatchingState<TSet> CreateState(SymbolicRegexNode<TSet> node, uint prevCharKind, bool capturing = false)
+ public DfaMatchingState<TSet> CreateState(SymbolicRegexNode<TSet> node, uint prevCharKind, bool capturing = false, bool isInitialState = false)
{
//first prune the anchors in the node
TSet wlbSet = _wordLetterForBoundariesSet;
@@ -469,21 +512,21 @@ namespace System.Text.RegularExpressions.Symbolic
var s = new DfaMatchingState<TSet>(pruned_node, prevCharKind);
if (!(capturing ? _capturingStateCache : _stateCache).TryGetValue(s, out DfaMatchingState<TSet>? state))
{
- state = MakeNewState(s, capturing);
+ state = MakeNewState(s, capturing, isInitialState);
}
return state;
}
- private DfaMatchingState<TSet> MakeNewState(DfaMatchingState<TSet> state, bool capturing)
+ private DfaMatchingState<TSet> MakeNewState(DfaMatchingState<TSet> state, bool capturing, bool isInitialState)
{
lock (this)
{
HashSet<DfaMatchingState<TSet>> cache = capturing ? _capturingStateCache : _stateCache;
+ cache.Add(state); // Add to cache first to make 1 the first state ID
state.Id = cache.Count;
- cache.Add(state);
- Debug.Assert(_stateArray is not null && _capturingStateArray is not null);
+ Debug.Assert(_stateArray is not null && _capturingStateArray is not null && _stateInfo is not null);
const int GrowthSize = 1024;
if (capturing)
@@ -503,8 +546,10 @@ namespace System.Text.RegularExpressions.Symbolic
int newsize = _stateArray.Length + GrowthSize;
Array.Resize(ref _stateArray, newsize);
Array.Resize(ref _delta, newsize << _mintermsLog);
+ Array.Resize(ref _stateInfo, newsize);
}
_stateArray[state.Id] = state;
+ SetStateInfo(state.Id, isInitialState, state.IsDeadend, state.Node.IsNullable, state.Node.CanBeNullable);
}
return state;
}
@@ -549,13 +594,20 @@ namespace System.Text.RegularExpressions.Symbolic
}
}
- /// <summary>Gets the core state corresponding to the NFA state</summary>
- public DfaMatchingState<TSet> GetCoreState(int nfaStateId)
+ /// <summary>Gets the core state Id corresponding to the NFA state</summary>
+ public int GetCoreStateId(int nfaStateId)
{
Debug.Assert(_stateArray is not null);
Debug.Assert(nfaStateId < _nfaStateArray.Length);
Debug.Assert(_nfaStateArray[nfaStateId] < _stateArray.Length);
- return _stateArray[_nfaStateArray[nfaStateId]];
+ return _nfaStateArray[nfaStateId];
+ }
+
+ /// <summary>Gets the core state corresponding to the NFA state</summary>
+ public DfaMatchingState<TSet> GetCoreState(int nfaStateId)
+ {
+ Debug.Assert(_stateArray is not null);
+ return _stateArray[GetCoreStateId(nfaStateId)];
}
/// <summary>Critical region for defining a new core transition</summary>
@@ -570,23 +622,23 @@ namespace System.Text.RegularExpressions.Symbolic
public bool TryCreateNewTransition(
DfaMatchingState<TSet> sourceState, int mintermId, int offset, bool checkThreshold, [NotNullWhen(true)] out DfaMatchingState<TSet>? nextState)
{
- Debug.Assert(_delta is not null);
+ Debug.Assert(_delta is not null && _stateArray is not null);
lock (this)
{
Debug.Assert(offset < _delta.Length);
// check if meanwhile delta[offset] has become defined possibly by another thread
- DfaMatchingState<TSet>? targetState = _delta[offset];
+ DfaMatchingState<TSet>? targetState = _stateArray[_delta[offset]];
if (targetState is null)
{
- if (checkThreshold && _stateCache.Count >= SymbolicRegexMatcher<TSet>.NfaThreshold)
+ if (checkThreshold && _stateCache.Count >= SymbolicRegexThresholds.NfaThreshold)
{
nextState = null;
return false;
}
targetState = sourceState.Next(GetMinterm(mintermId));
- Volatile.Write(ref _delta[offset], targetState);
+ Volatile.Write(ref _delta[offset], targetState.Id);
}
nextState = targetState;
@@ -597,7 +649,7 @@ namespace System.Text.RegularExpressions.Symbolic
/// <summary>Gets or creates a new NFA transition.</summary>
public int[] CreateNewNfaTransition(int nfaStateId, int mintermId, int nfaOffset)
{
- Debug.Assert(_delta is not null);
+ Debug.Assert(_delta is not null && _stateArray is not null);
lock (this)
{
Debug.Assert(nfaOffset < _nfaDelta.Length);
@@ -609,7 +661,9 @@ namespace System.Text.RegularExpressions.Symbolic
// Create the underlying transition from the core state corresponding to the nfa state
DfaMatchingState<TSet> coreState = GetCoreState(nfaStateId);
int coreOffset = (coreState.Id << _mintermsLog) | mintermId;
- DfaMatchingState<TSet>? coreTarget = _delta[coreOffset] ?? CreateNewTransition(coreState, mintermId, coreOffset);
+ int coreTargetId = _delta[coreOffset];
+ DfaMatchingState<TSet>? coreTarget = coreTargetId > 0 ?
+ _stateArray[coreTargetId] : CreateNewTransition(coreState, mintermId, coreOffset);
SymbolicRegexNode<TSet> node = coreTarget.Node.Kind == SymbolicRegexNodeKind.DisableBacktrackingSimulation ?
coreTarget.Node._left! : coreTarget.Node;
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Dgml.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Dgml.cs
index 8a5dad8d85c..a756f2a4a8d 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Dgml.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Dgml.cs
@@ -29,7 +29,7 @@ namespace System.Text.RegularExpressions.Symbolic
foreach (DfaMatchingState<TSet> state in _builder._stateCache)
{
writer.WriteLine(" <Node Id=\"{0}\" Label=\"{0}\" Category=\"State\" Group=\"Collapsed\" StateInfo=\"{1}\">", state.Id, state.DgmlView);
- if (state.IsInitialState)
+ if (_builder.GetStateInfo(state.Id).IsInitial)
{
writer.WriteLine(" <Category Ref=\"InitialState\" />");
}
@@ -143,16 +143,17 @@ namespace System.Text.RegularExpressions.Symbolic
foreach (DfaMatchingState<TSet> source in builder._stateCache)
{
// Get the span of entries in delta that gives the transitions for the different minterms
- Span<DfaMatchingState<TSet>?> deltas = builder.GetDeltasFor(source);
+ Span<int> deltas = builder.GetDeltasFor(source);
Span<int[]?> nfaDeltas = builder.GetNfaDeltasFor(source);
Debug.Assert(deltas.Length == builder._minterms.Length);
for (int i = 0; i < deltas.Length; ++i)
{
- // null entries are transitions not explored yet, so skip them
- if (deltas[i] is DfaMatchingState<TSet> target)
+ // negative entries are transitions not explored yet, so skip them
+ int targetId = deltas[i];
+ if (targetId >= 0)
{
// Get or create the data for this (source,destination) state ID pair
- (int Source, int Target) key = (source.Id, target.Id);
+ (int Source, int Target) key = (source.Id, targetId);
if (!result.TryGetValue(key, out (TSet Rule, List<int> NfaTargets) entry))
{
entry = (builder._solver.Empty, new List<int>());
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Sample.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Sample.cs
index 509a5b8516a..99ca9c4501a 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Sample.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.Sample.cs
@@ -83,25 +83,25 @@ namespace System.Text.RegularExpressions.Symbolic
{
// Unconditionally final state or end of the input due to \Z anchor for example
if (NfaStateHandler.IsNullable(ref statesWrapper) ||
- NfaStateHandler.IsNullable(ref statesWrapper, CharKind.BeginningEnd))
+ NfaStateHandler.IsNullableFor(_builder, ref statesWrapper, CharKind.BeginningEnd))
{
possibleEndings.Add("");
}
// End of line due to end-of-line anchor
- if (NfaStateHandler.IsNullable(ref statesWrapper, CharKind.Newline))
+ if (NfaStateHandler.IsNullableFor(_builder, ref statesWrapper, CharKind.Newline))
{
possibleEndings.Add("\n");
}
// Related to wordborder due to \b or \B
- if (NfaStateHandler.IsNullable(ref statesWrapper, CharKind.WordLetter))
+ if (NfaStateHandler.IsNullableFor(_builder, ref statesWrapper, CharKind.WordLetter))
{
possibleEndings.Add(ChooseChar(random, asciiWordCharacters, ascii, charSetSolver).ToString());
}
// Related to wordborder due to \b or \B
- if (NfaStateHandler.IsNullable(ref statesWrapper, CharKind.General))
+ if (NfaStateHandler.IsNullableFor(_builder, ref statesWrapper, CharKind.General))
{
possibleEndings.Add(ChooseChar(random, asciiNonWordCharacters, ascii, charSetSolver).ToString());
}
@@ -125,7 +125,7 @@ namespace System.Text.RegularExpressions.Symbolic
}
// Shuffle the minterms, including the last end-of-line marker if appropriate
- int[] mintermIds = NfaStateHandler.StartsWithLineAnchor(ref statesWrapper) ?
+ int[] mintermIds = NfaStateHandler.StartsWithLineAnchor(_builder, ref statesWrapper) ?
Shuffle(random, mintermIdsWithZ) :
Shuffle(random, mintermIdsWithoutZ);
foreach (int mintermId in mintermIds)
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.cs
index 4109865c7ff..12e4c83c72a 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexMatcher.cs
@@ -30,23 +30,6 @@ namespace System.Text.RegularExpressions.Symbolic
/// <typeparam name="TSet">Character set type.</typeparam>
internal sealed partial class SymbolicRegexMatcher<TSet> : SymbolicRegexMatcher where TSet : IComparable<TSet>, IEquatable<TSet>
{
- /// <summary>Maximum number of built states before switching over to NFA mode.</summary>
- /// <remarks>
- /// By default, all matching starts out using DFAs, where every state transitions to one and only one
- /// state for any minterm (each character maps to one minterm). Some regular expressions, however, can result
- /// in really, really large DFA state graphs, much too big to actually store. Instead of failing when we
- /// encounter such state graphs, at some point we instead switch from processing as a DFA to processing as
- /// an NFA. As an NFA, we instead track all of the states we're in at any given point, and transitioning
- /// from one "state" to the next really means for every constituent state that composes our current "state",
- /// we find all possible states that transitioning out of each of them could result in, and the union of
- /// all of those is our new "state". This constant represents the size of the graph after which we start
- /// processing as an NFA instead of as a DFA. This processing doesn't change immediately, however. All
- /// processing starts out in DFA mode, even if we've previously triggered NFA mode for the same regex.
- /// We switch over into NFA mode the first time a given traversal (match operation) results in us needing
- /// to create a new node and the graph is already or newly beyond this threshold.
- /// </remarks>
- internal const int NfaThreshold = 10_000;
-
/// <summary>Sentinel value used internally by the matcher to indicate no match exists.</summary>
private const int NoMatchExists = -2;
@@ -209,8 +192,7 @@ namespace System.Text.RegularExpressions.Symbolic
// but observe that the behavior from the state may ultimately depend on the previous
// input char e.g. possibly causing nullability of \b or \B or of a start-of-line anchor,
// in that sense there can be several "versions" (not more than StateCount) of the initial state.
- DfaMatchingState<TSet> state = _builder.CreateState(_dotStarredPattern, i, capturing: false);
- state.IsInitialState = true;
+ DfaMatchingState<TSet> state = _builder.CreateState(_dotStarredPattern, i, capturing: false, isInitialState: true);
dotstarredInitialStates[i] = state;
}
_dotstarredInitialStates = dotstarredInitialStates;
@@ -272,7 +254,7 @@ namespace System.Text.RegularExpressions.Symbolic
int c = input[i];
// Find the minterm, handling the special case for the last \n for states that start with a relevant anchor
- int mintermId = c == '\n' && i == input.Length - 1 && TStateHandler.StartsWithLineAnchor(ref state) ?
+ int mintermId = c == '\n' && i == input.Length - 1 && TStateHandler.StartsWithLineAnchor(builder, ref state) ?
builder._minterms!.Length : // mintermId = minterms.Length represents an \n at the very end of input
_mintermClassifier.GetMintermID(c);
@@ -332,7 +314,14 @@ namespace System.Text.RegularExpressions.Symbolic
// As an example, consider the pattern a{1,3}(b*) run against an input of aacaaaabbbc: phase 1 will find
// the position of the last b: aacaaaabbbc. It additionally records the position of the first a after
// the c as the low boundary for the starting position.
- int matchEnd = FindEndPosition(input, startat, timeoutOccursAt, mode, out int matchStartLowBoundary, out int matchStartLengthMarker, perThreadData);
+ int matchStartLowBoundary, matchStartLengthMarker;
+ int matchEnd = (_findOpts is not null, _pattern._info.ContainsSomeAnchor) switch
+ {
+ (true, true) => FindEndPosition<InitialStateFindOptimizationsHandler, FullNullabilityHandler>(input, startat, timeoutOccursAt, mode, out matchStartLowBoundary, out matchStartLengthMarker, perThreadData),
+ (true, false) => FindEndPosition<InitialStateFindOptimizationsHandler, NoAnchorsNullabilityHandler>(input, startat, timeoutOccursAt, mode, out matchStartLowBoundary, out matchStartLengthMarker, perThreadData),
+ (false, true) => FindEndPosition<NoOptimizationsInitialStateHandler, FullNullabilityHandler>(input, startat, timeoutOccursAt, mode, out matchStartLowBoundary, out matchStartLengthMarker, perThreadData),
+ (false, false) => FindEndPosition<NoOptimizationsInitialStateHandler, NoAnchorsNullabilityHandler>(input, startat, timeoutOccursAt, mode, out matchStartLowBoundary, out matchStartLengthMarker, perThreadData),
+ };
// If there wasn't a match, we're done.
if (matchEnd == NoMatchExists)
@@ -366,8 +355,9 @@ namespace System.Text.RegularExpressions.Symbolic
{
Debug.Assert(matchEnd >= startat - 1);
matchStart = matchEnd < startat ?
- startat :
- FindStartPosition(input, matchEnd, matchStartLowBoundary, perThreadData);
+ startat : _pattern._info.ContainsSomeAnchor ?
+ FindStartPosition<FullNullabilityHandler>(input, matchEnd, matchStartLowBoundary, perThreadData) :
+ FindStartPosition<NoAnchorsNullabilityHandler>(input, matchEnd, matchStartLowBoundary, perThreadData);
}
// Phase 3:
@@ -388,47 +378,30 @@ namespace System.Text.RegularExpressions.Symbolic
/// <summary>Performs the initial Phase 1 match to find the end position of the match, or first final state if this is an isMatch call.</summary>
/// <param name="input">The input text.</param>
- /// <param name="i">The starting position in <paramref name="input"/>.</param>
+ /// <param name="pos">The starting position in <paramref name="input"/>.</param>
/// <param name="timeoutOccursAt">The time at which timeout occurs, if timeouts are being checked.</param>
/// <param name="mode">The mode of execution based on the regex operation being performed.</param>
- /// <param name="initialStateIndex">The last position the initial state of <see cref="_dotStarredPattern"/> was visited before the end position was found.</param>
+ /// <param name="initialStatePos">The last position the initial state of <see cref="_dotStarredPattern"/> was visited before the end position was found.</param>
/// <param name="matchLength">Length of the match if there's a match; otherwise, -1.</param>
/// <param name="perThreadData">Per thread data reused between calls.</param>
/// <returns>
/// A one-past-the-end index into input for the preferred match, or first final state position if isMatch is true, or NoMatchExists if no match exists.
/// </returns>
- private int FindEndPosition(ReadOnlySpan<char> input, int i, long timeoutOccursAt, RegexRunnerMode mode, out int initialStateIndex, out int matchLength, PerThreadData perThreadData)
+ private int FindEndPosition<TFindOptimizationsHandler, TNullabilityHandler>(ReadOnlySpan<char> input, int pos, long timeoutOccursAt, RegexRunnerMode mode, out int initialStatePos, out int matchLength, PerThreadData perThreadData)
+ where TFindOptimizationsHandler : struct, IInitialStateHandler
+ where TNullabilityHandler : struct, INullabilityHandler
{
- int endPosition = NoMatchExists;
+ initialStatePos = pos;
+ int initialStatePosCandidate = pos;
- matchLength = -1;
- initialStateIndex = i;
- int initialStateIndexCandidate = i;
+ var currentState = new CurrentState(_dotstarredInitialStates[GetCharKind(input, pos - 1)]);
+ SymbolicRegexBuilder<TSet> builder = _builder;
- var currentState = new CurrentState(_dotstarredInitialStates[GetCharKind(input, i - 1)]);
- SymbolicRegexBuilder<TSet> builder = _pattern._builder;
+ int endPos = NoMatchExists;
+ int endStateId = -1;
while (true)
{
- if (currentState.DfaState is { IsInitialState: true })
- {
- if (_findOpts is RegexFindOptimizations findOpts)
- {
- // Find the first position i that matches with some likely character.
- if (!findOpts.TryFindNextStartingPosition(input, ref i, 0))
- {
- // no match was found
- break;
- }
- }
-
- initialStateIndexCandidate = i;
-
- // Update the starting state based on where TryFindNextStartingPosition moved us to.
- // As with the initial starting state, if it's a dead end, no match exists.
- currentState = new CurrentState(_dotstarredInitialStates[GetCharKind(input, i - 1)]);
- }
-
// Now run the DFA or NFA traversal from the current point using the current state. If timeouts are being checked,
// we need to pop out of the inner loop every now and then to do the timeout check in this outer loop. Note that
// the timeout exists not to provide perfect guarantees around execution time but rather as a mitigation against
@@ -436,48 +409,34 @@ namespace System.Text.RegularExpressions.Symbolic
// still check the timeout now and again to provide some semblance of the behavior a developer experiences with
// the backtracking engines. We can, however, choose a large number here, since it's not actually needed for security.
const int CharsPerTimeoutCheck = 1_000;
- ReadOnlySpan<char> inputForInnerLoop = _checkTimeout && input.Length - i > CharsPerTimeoutCheck ?
- input.Slice(0, i + CharsPerTimeoutCheck) :
+ ReadOnlySpan<char> inputForInnerLoop = _checkTimeout && input.Length - pos > CharsPerTimeoutCheck ?
+ input.Slice(0, pos + CharsPerTimeoutCheck) :
input;
- int newEndPosition;
- int findResult = currentState.NfaState is not null ?
- FindEndPositionDeltas<NfaStateHandler>(builder, inputForInnerLoop, mode, ref i, ref currentState, ref matchLength, out newEndPosition) :
- FindEndPositionDeltas<DfaStateHandler>(builder, inputForInnerLoop, mode, ref i, ref currentState, ref matchLength, out newEndPosition);
-
- // If a new end position was found, commit to the matching initial state index
- if (newEndPosition != -1)
- {
- endPosition = newEndPosition;
- initialStateIndex = initialStateIndexCandidate;
- }
+ bool done = currentState.NfaState is not null ?
+ FindEndPositionDeltas<NfaStateHandler, TFindOptimizationsHandler, TNullabilityHandler>(builder, input, mode, ref pos, ref currentState, ref endPos, ref endStateId, ref initialStatePos, ref initialStatePosCandidate) :
+ FindEndPositionDeltas<DfaStateHandler, TFindOptimizationsHandler, TNullabilityHandler>(builder, input, mode, ref pos, ref currentState, ref endPos, ref endStateId, ref initialStatePos, ref initialStatePosCandidate);
- // If we reached the end of input or a deadend state, we're done.
- if (findResult > 0)
+ // If the inner loop indicates that the search finished (for example due to reaching a deadend state) or
+ // there is no more input available, then the whole search is done.
+ if (done || pos >= input.Length)
{
break;
}
- // The search did not finish, so we either hit an initial state (in which case we want to loop around to apply our initial
- // state processing logic and optimizations), or failed to transition (which should only happen if we were in DFA mode and
- // need to switch over to NFA mode). If we exited because we hit an initial state, find result will be 0, otherwise -1.
- if (findResult < 0)
+ // The search did not finish, so we either failed to transition (which should only happen if we were in DFA mode and
+ // need to switch over to NFA mode) or ran out of input in the inner loop. Check if the inner loop still had more
+ // input available.
+ if (pos < inputForInnerLoop.Length)
{
- if (i >= input.Length)
- {
- // We ran out of input.
- break;
- }
-
- if (i < inputForInnerLoop.Length)
- {
- // We failed to transition. Upgrade to DFA mode.
- Debug.Assert(i < inputForInnerLoop.Length);
- Debug.Assert(currentState.DfaState is not null);
- NfaMatchingState nfaState = perThreadData.NfaState;
- nfaState.InitializeFrom(currentState.DfaState);
- currentState = new CurrentState(nfaState);
- }
+ // Because there was still more input available, a failure to transition in DFA mode must be the cause
+ // of the early exit. Upgrade to NFA mode.
+ Debug.Assert(pos < inputForInnerLoop.Length);
+ DfaMatchingState<TSet>? dfaState = currentState.DfaState(_builder);
+ Debug.Assert(dfaState is not null);
+ NfaMatchingState nfaState = perThreadData.NfaState;
+ nfaState.InitializeFrom(dfaState);
+ currentState = new CurrentState(nfaState);
}
// Check for a timeout before continuing.
@@ -487,19 +446,22 @@ namespace System.Text.RegularExpressions.Symbolic
}
}
- return endPosition;
+ // Check whether there's a fixed-length marker for the current state. If there is, we can
+ // use that length to optimize subsequent matching phases.
+ matchLength = endStateId > 0 ? _builder._stateArray![endStateId].FixedLength(GetCharKind(input, endPos)) : -1;
+ return endPos;
}
/// <summary>
/// Workhorse inner loop for <see cref="FindEndPosition"/>. Consumes the <paramref name="input"/> character by character,
- /// starting at <paramref name="i"/>, for each character transitioning from one state in the DFA or NFA graph to the next state,
+ /// starting at <paramref name="posRef"/>, for each character transitioning from one state in the DFA or NFA graph to the next state,
/// lazily building out the graph as needed.
/// </summary>
/// <remarks>
/// The <typeparamref name="TStateHandler"/> supplies the actual transitioning logic, controlling whether processing is
- /// performed in DFA mode or in NFA mode. However, it expects <paramref name="currentState"/> to be configured to match,
- /// so for example if <typeparamref name="TStateHandler"/> is a <see cref="DfaStateHandler"/>, it expects the <paramref name="currentState"/>'s
- /// <see cref="CurrentState.DfaState"/> to be non-null and its <see cref="CurrentState.NfaState"/> to be null; vice versa for
+ /// performed in DFA mode or in NFA mode. However, it expects <paramref name="stateRef"/> to be configured to match,
+ /// so for example if <typeparamref name="TStateHandler"/> is a <see cref="DfaStateHandler"/>, it expects the <paramref name="stateRef"/>'s
+ /// <see cref="CurrentState.DfaStateId"/> to be non-negative and its <see cref="CurrentState.NfaState"/> to be null; vice versa for
/// <see cref="NfaStateHandler"/>.
/// </remarks>
/// <returns>
@@ -507,64 +469,76 @@ namespace System.Text.RegularExpressions.Symbolic
/// 0 if iteration completed because we reached an initial state.
/// A negative value if iteration completed because we ran out of input or we failed to transition.
/// </returns>
- private int FindEndPositionDeltas<TStateHandler>(SymbolicRegexBuilder<TSet> builder, ReadOnlySpan<char> input, RegexRunnerMode mode, ref int i, ref CurrentState currentState, ref int matchLength, out int endPosition)
+ private bool FindEndPositionDeltas<TStateHandler, TFindOptimizationsHandler, TNullabilityHandler>(SymbolicRegexBuilder<TSet> builder, ReadOnlySpan<char> input, RegexRunnerMode mode,
+ ref int posRef, ref CurrentState stateRef, ref int endPosRef, ref int endStateIdRef, ref int initialStatePosRef, ref int initialStatePosCandidateRef)
where TStateHandler : struct, IStateHandler
+ where TFindOptimizationsHandler : struct, IInitialStateHandler
+ where TNullabilityHandler : struct, INullabilityHandler
{
// To avoid frequent reads/writes to ref and out values, make and operate on local copies, which we then copy back once before returning.
- int pos = i;
- CurrentState state = currentState;
- int endPos = -1;
+ int pos = posRef;
+ CurrentState state = stateRef;
+ int endPos = endPosRef;
+ int endStateId = endStateIdRef;
+ int initialStatePos = initialStatePosRef;
+ int initialStatePosCandidate = initialStatePosCandidateRef;
try
{
// Loop through each character in the input, transitioning from state to state for each.
while (true)
{
+ (bool isInitial, bool isDeadend, bool isNullable, bool canBeNullable) = TStateHandler.GetStateInfo(builder, ref state);
+ // Check if currentState represents an initial state. If it does, call into any possible find optimizations
+ // to hopefully more quickly find the next possible starting location.
+ if (isInitial)
+ {
+ if (!TFindOptimizationsHandler.TryFindNextStartingPosition(this, input, ref state, ref pos))
+ {
+ return true;
+ }
+ initialStatePosCandidate = pos;
+ }
+
+ // If the state is a dead end, such that we can't transition anywhere else, end the search.
+ if (isDeadend)
+ {
+ return true;
+ }
+
// If the state is nullable for the next character, meaning it accepts the empty string,
// we found a potential end state.
- if (TStateHandler.IsNullable(ref state, GetCharKind(input, pos)))
+ if (TNullabilityHandler.IsNullableAt<TStateHandler>(this, ref state, input, pos, isNullable, canBeNullable))
{
- // Check whether there's a fixed-length marker for the current state. If there is, we can
- // use that length to optimize subsequent matching phases.
- matchLength = TStateHandler.FixedLength(ref state, GetCharKind(input, pos));
endPos = pos;
+ endStateId = TStateHandler.ExtractNullableCoreStateId(this, ref state, input, pos);
+ initialStatePos = initialStatePosCandidate;
// A match is known to exist. If that's all we need to know, we're done.
if (mode == RegexRunnerMode.ExistenceRequired)
{
- return 1;
+ return true;
}
}
- // If the state is a dead end, such that we can't transition anywhere else, end the search.
- if (TStateHandler.IsDeadend(ref state))
- {
- return 1;
- }
-
// If there is more input available try to transition with the next character.
if ((uint)pos >= (uint)input.Length || !TryTakeTransition<TStateHandler>(builder, input, pos, ref state))
{
- return -1;
+ return false;
}
// We successfully transitioned, so update our current input index to match.
pos++;
-
- // Now that currentState and our position are coherent, check if currentState represents an initial state.
- // If it does, we exit out in order to allow our find optimizations to kick in to hopefully more quickly
- // find the next possible starting location.
- if (TStateHandler.IsInitialState(ref state))
- {
- return 0;
- }
}
}
finally
{
- // Write back the local copies of the ref and out values.
- currentState = state;
- i = pos;
- endPosition = endPos;
+ // Write back the local copies of the ref values.
+ posRef = pos;
+ stateRef = state;
+ endPosRef = endPos;
+ endStateIdRef = endStateId;
+ initialStatePosRef = initialStatePos;
+ initialStatePosCandidateRef = initialStatePosCandidate;
}
}
@@ -581,7 +555,8 @@ namespace System.Text.RegularExpressions.Symbolic
/// <param name="matchStartBoundary">The initial starting location discovered in phase 1, a point we must not walk earlier than.</param>
/// <param name="perThreadData">Per thread data reused between calls.</param>
/// <returns>The found starting position for the match.</returns>
- private int FindStartPosition(ReadOnlySpan<char> input, int i, int matchStartBoundary, PerThreadData perThreadData)
+ private int FindStartPosition<TNullabilityHandler>(ReadOnlySpan<char> input, int i, int matchStartBoundary, PerThreadData perThreadData)
+ where TNullabilityHandler : struct, INullabilityHandler
{
Debug.Assert(i >= 0, $"{nameof(i)} == {i}");
Debug.Assert(matchStartBoundary >= 0 && matchStartBoundary <= input.Length, $"{nameof(matchStartBoundary)} == {matchStartBoundary}");
@@ -594,13 +569,13 @@ namespace System.Text.RegularExpressions.Symbolic
int lastStart = -1; // invalid sentinel value
// Walk backwards to the furthest accepting state of the reverse pattern but no earlier than matchStartBoundary.
- SymbolicRegexBuilder<TSet> builder = currentState.DfaState!.Node._builder;
+ SymbolicRegexBuilder<TSet> builder = _builder;
while (true)
{
// Run the DFA or NFA traversal backwards from the current point using the current state.
bool done = currentState.NfaState is not null ?
- FindStartPositionDeltas<NfaStateHandler>(builder, input, ref i, matchStartBoundary, ref currentState, ref lastStart) :
- FindStartPositionDeltas<DfaStateHandler>(builder, input, ref i, matchStartBoundary, ref currentState, ref lastStart);
+ FindStartPositionDeltas<NfaStateHandler, TNullabilityHandler>(builder, input, ref i, matchStartBoundary, ref currentState, ref lastStart) :
+ FindStartPositionDeltas<DfaStateHandler, TNullabilityHandler>(builder, input, ref i, matchStartBoundary, ref currentState, ref lastStart);
// If we found the starting position, we're done.
if (done)
@@ -612,9 +587,10 @@ namespace System.Text.RegularExpressions.Symbolic
// if we were unable to transition, which should only happen if we were in DFA mode and exceeded our graph size.
// Upgrade to NFA mode and continue.
Debug.Assert(i >= matchStartBoundary);
- Debug.Assert(currentState.DfaState is not null);
+ DfaMatchingState<TSet>? dfaState = currentState.DfaState(_builder);
+ Debug.Assert(dfaState is not null);
NfaMatchingState nfaState = perThreadData.NfaState;
- nfaState.InitializeFrom(currentState.DfaState);
+ nfaState.InitializeFrom(dfaState);
currentState = new CurrentState(nfaState);
}
@@ -627,8 +603,9 @@ namespace System.Text.RegularExpressions.Symbolic
/// starting at <paramref name="i"/>, for each character transitioning from one state in the DFA or NFA graph to the next state,
/// lazily building out the graph as needed.
/// </summary>
- private bool FindStartPositionDeltas<TStateHandler>(SymbolicRegexBuilder<TSet> builder, ReadOnlySpan<char> input, ref int i, int startThreshold, ref CurrentState currentState, ref int lastStart)
+ private bool FindStartPositionDeltas<TStateHandler, TNullabilityHandler>(SymbolicRegexBuilder<TSet> builder, ReadOnlySpan<char> input, ref int i, int startThreshold, ref CurrentState currentState, ref int lastStart)
where TStateHandler : struct, IStateHandler
+ where TNullabilityHandler : struct, INullabilityHandler
{
// To avoid frequent reads/writes to ref values, make and operate on local copies, which we then copy back once before returning.
int pos = i;
@@ -638,14 +615,18 @@ namespace System.Text.RegularExpressions.Symbolic
// Loop backwards through each character in the input, transitioning from state to state for each.
while (true)
{
+ (bool isInitial, bool isDeadend, bool isNullable, bool canBeNullable) = TStateHandler.GetStateInfo(builder, ref state);
+
// If the state accepts the empty string, we found a valid starting position. Record it and keep going,
// since we're looking for the earliest one to occur within bounds.
- if (TStateHandler.IsNullable(ref state, GetCharKind(input, pos - 1)))
+ if (TNullabilityHandler.IsNullableAt<TStateHandler>(this, ref state, input, pos - 1, isNullable, canBeNullable))
+ {
lastStart = pos;
+ }
// If we are past the start threshold or if the state is a dead end, bail; we should have already
// found a valid starting location.
- if (pos <= startThreshold || TStateHandler.IsDeadend(ref state))
+ if (pos <= startThreshold || isDeadend)
{
Debug.Assert(lastStart != -1);
return true;
@@ -653,8 +634,10 @@ namespace System.Text.RegularExpressions.Symbolic
// Try to transition with the next character, the one before the current position.
if (!TryTakeTransition<TStateHandler>(builder, input, pos - 1, ref state))
+ {
// Return false to indicate the search didn't finish.
return false;
+ }
// Since we successfully transitioned, update our current index to match the fact that we consumed the previous character in the input.
pos--;
@@ -738,7 +721,7 @@ namespace System.Text.RegularExpressions.Symbolic
Registers newRegisters = j != transitions.Count - 1 ? sourceRegisters.Clone() : sourceRegisters;
newRegisters.ApplyEffects(effects, i);
next.Update(index, targetState.Id, newRegisters);
- if (targetState.IsNullable(GetCharKind(input, i + 1)))
+ if (targetState.IsNullableFor(GetCharKind(input, i + 1)))
{
// No lower priority transitions from this or other source states are taken because the
// backtracking engines would return the match ending here.
@@ -762,7 +745,7 @@ namespace System.Text.RegularExpressions.Symbolic
foreach (var (endStateId, endRegisters) in current.Values)
{
DfaMatchingState<TSet> endState = _builder._capturingStateArray[endStateId];
- if (endState.IsNullable(GetCharKind(input, iEnd)))
+ if (endState.IsNullableFor(GetCharKind(input, iEnd)))
{
// Apply effects for finishing at the stored end state
endState.Node.ApplyEffects((effect, args) => args.Registers.ApplyEffect(effect, args.Pos),
@@ -952,90 +935,105 @@ namespace System.Text.RegularExpressions.Symbolic
/// <summary>Initializes the state as a DFA state.</summary>
public CurrentState(DfaMatchingState<TSet> dfaState)
{
- DfaState = dfaState;
+ DfaStateId = dfaState.Id;
NfaState = null;
}
/// <summary>Initializes the state as an NFA state.</summary>
public CurrentState(NfaMatchingState nfaState)
{
- DfaState = null;
+ DfaStateId = -1;
NfaState = nfaState;
}
/// <summary>The DFA state.</summary>
- public DfaMatchingState<TSet>? DfaState;
+ public int DfaStateId;
/// <summary>The NFA state.</summary>
public NfaMatchingState? NfaState;
+
+ public DfaMatchingState<TSet>? DfaState(SymbolicRegexBuilder<TSet> builder) => DfaStateId > 0 ? builder._stateArray![DfaStateId] : null;
}
/// <summary>Represents a set of routines for operating over a <see cref="CurrentState"/>.</summary>
private interface IStateHandler
{
- public static abstract bool StartsWithLineAnchor(ref CurrentState state);
- public static abstract bool IsNullable(ref CurrentState state, uint nextCharKind);
- public static abstract bool IsDeadend(ref CurrentState state);
- public static abstract int FixedLength(ref CurrentState state, uint nextCharKind);
- public static abstract bool IsInitialState(ref CurrentState state);
+ public static abstract bool StartsWithLineAnchor(SymbolicRegexBuilder<TSet> builder, ref CurrentState state);
+ public static abstract bool IsNullableFor(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, uint nextCharKind);
+ public static abstract int ExtractNullableCoreStateId(SymbolicRegexMatcher<TSet> matcher, ref CurrentState state, ReadOnlySpan<char> input, int pos);
+ public static abstract int FixedLength(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, uint nextCharKind);
public static abstract bool TakeTransition(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, int mintermId);
+ public static abstract (bool IsInitial, bool IsDeadend, bool IsNullable, bool CanBeNullable) GetStateInfo(SymbolicRegexBuilder<TSet> builder, ref CurrentState state);
}
/// <summary>An <see cref="IStateHandler"/> for operating over <see cref="CurrentState"/> instances configured as DFA states.</summary>
private readonly struct DfaStateHandler : IStateHandler
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool StartsWithLineAnchor(ref CurrentState state) => state.DfaState!.StartsWithLineAnchor;
+ public static bool StartsWithLineAnchor(SymbolicRegexBuilder<TSet> builder, ref CurrentState state) => state.DfaState(builder)!.StartsWithLineAnchor;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsNullable(ref CurrentState state, uint nextCharKind) => state.DfaState!.IsNullable(nextCharKind);
+ public static bool IsNullableFor(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, uint nextCharKind) => state.DfaState(builder)!.IsNullableFor(nextCharKind);
- /// <summary>Gets whether this is a dead-end state, meaning there are no transitions possible out of the state.</summary>
+ /// <summary>Gets the preferred DFA state for nullability. In DFA mode this is just the state itself.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsDeadend(ref CurrentState state) => state.DfaState!.IsDeadend;
+ public static int ExtractNullableCoreStateId(SymbolicRegexMatcher<TSet> matcher, ref CurrentState state, ReadOnlySpan<char> input, int pos) => state.DfaStateId;
/// <summary>Gets the length of any fixed-length marker that exists for this state, or -1 if there is none.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int FixedLength(ref CurrentState state, uint nextCharKind) => state.DfaState!.FixedLength(nextCharKind);
-
- /// <summary>Gets whether this is an initial state.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsInitialState(ref CurrentState state) => state.DfaState!.IsInitialState;
+ public static int FixedLength(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, uint nextCharKind) => state.DfaState(builder)!.FixedLength(nextCharKind);
/// <summary>Take the transition to the next DFA state.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TakeTransition(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, int mintermId)
{
- Debug.Assert(state.DfaState is not null, $"Expected non-null {nameof(state.DfaState)}.");
+ Debug.Assert(state.DfaStateId > 0, $"Expected non-zero {nameof(state.DfaStateId)}.");
Debug.Assert(state.NfaState is null, $"Expected null {nameof(state.NfaState)}.");
Debug.Assert(builder._delta is not null);
- // Get the current state.
- DfaMatchingState<TSet> dfaMatchingState = state.DfaState!;
-
// Use the mintermId for the character being read to look up which state to transition to.
// If that state has already been materialized, move to it, and we're done. If that state
// hasn't been materialized, try to create it; if we can, move to it, and we're done.
- int dfaOffset = (dfaMatchingState.Id << builder._mintermsLog) | mintermId;
- DfaMatchingState<TSet>? nextState = builder._delta[dfaOffset];
- if (nextState is not null || builder.TryCreateNewTransition(dfaMatchingState, mintermId, dfaOffset, checkThreshold: true, out nextState))
+ int dfaOffset = (state.DfaStateId << builder._mintermsLog) | mintermId;
+ int nextStateId = builder._delta[dfaOffset];
+ if (nextStateId > 0)
+ {
+ // There was an existing DFA transition to some state. Move to it and
+ // return that we're still operating as a DFA and can keep going.
+ state.DfaStateId = nextStateId;
+ return true;
+ }
+ if (builder.TryCreateNewTransition(state.DfaState(builder)!, mintermId, dfaOffset, checkThreshold: true, out DfaMatchingState<TSet>? nextState))
{
- // There was an existing state for this transition or we were able to create one. Move to it and
+ // We were able to create a new DFA transition to some state. Move to it and
// return that we're still operating as a DFA and can keep going.
- state.DfaState = nextState;
+ state.DfaStateId = nextState.Id;
return true;
}
return false;
}
+
+ /// <summary>
+ /// Gets context independent state information:
+ /// - whether this is an initial state
+ /// - whether this is a dead-end state, meaning there are no transitions possible out of the state
+ /// - whether this state is unconditionally nullable
+ /// - whether this state may be contextually nullable
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static (bool IsInitial, bool IsDeadend, bool IsNullable, bool CanBeNullable) GetStateInfo(SymbolicRegexBuilder<TSet> builder, ref CurrentState state)
+ {
+ Debug.Assert(state.DfaStateId > 0);
+ return builder.GetStateInfo(state.DfaStateId);
+ }
}
/// <summary>An <see cref="IStateHandler"/> for operating over <see cref="CurrentState"/> instances configured as NFA states.</summary>
private readonly struct NfaStateHandler : IStateHandler
{
/// <summary>Check if any underlying core state starts with a line anchor.</summary>
- public static bool StartsWithLineAnchor(ref CurrentState state)
+ public static bool StartsWithLineAnchor(SymbolicRegexBuilder<TSet> builder, ref CurrentState state)
{
- SymbolicRegexBuilder<TSet> builder = state.NfaState!.Builder;
foreach (ref KeyValuePair<int, int> nfaState in CollectionsMarshal.AsSpan(state.NfaState!.NfaStateSet.Values))
{
if (builder.GetCoreState(nfaState.Key).StartsWithLineAnchor)
@@ -1047,13 +1045,12 @@ namespace System.Text.RegularExpressions.Symbolic
return false;
}
- /// <summary>Check if any underlying core state is nullable.</summary>
- public static bool IsNullable(ref CurrentState state, uint nextCharKind)
+ /// <summary>Check if any underlying core state is nullable in the context of the next character kind.</summary>
+ public static bool IsNullableFor(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, uint nextCharKind)
{
- SymbolicRegexBuilder<TSet> builder = state.NfaState!.Builder;
foreach (ref KeyValuePair<int, int> nfaState in CollectionsMarshal.AsSpan(state.NfaState!.NfaStateSet.Values))
{
- if (builder.GetCoreState(nfaState.Key).IsNullable(nextCharKind))
+ if (builder.GetCoreState(nfaState.Key).IsNullableFor(nextCharKind))
{
return true;
}
@@ -1062,22 +1059,41 @@ namespace System.Text.RegularExpressions.Symbolic
return false;
}
- /// <summary>Gets whether this is a dead-end state, meaning there are no transitions possible out of the state.</summary>
- /// <remarks>In NFA mode, an empty set of states means that it is a dead end.</remarks>
- public static bool IsDeadend(ref CurrentState state) => state.NfaState!.NfaStateSet.Count == 0;
+ /// <summary>Gets the preferred DFA state for nullability. In DFA mode this is just the state itself.</summary>
+ public static int ExtractNullableCoreStateId(SymbolicRegexMatcher<TSet> matcher, ref CurrentState state, ReadOnlySpan<char> input, int pos)
+ {
+ uint nextCharKind = matcher.GetCharKind(input, pos);
+ foreach (ref KeyValuePair<int, int> nfaState in CollectionsMarshal.AsSpan(state.NfaState!.NfaStateSet.Values))
+ {
+ DfaMatchingState<TSet> coreState = matcher._builder.GetCoreState(nfaState.Key);
+ if (coreState.IsNullableFor(nextCharKind))
+ {
+ return coreState.Id;
+ }
+ }
+ Debug.Fail("ExtractNullableCoreStateId should only be called in nullable state/context.");
+ return -1;
+ }
/// <summary>Gets the length of any fixed-length marker that exists for this state, or -1 if there is none.</summary>
- /// <summary>In NFA mode, there are no fixed-length markers.</summary>
- public static int FixedLength(ref CurrentState state, uint nextCharKind) => -1;
-
- /// <summary>Gets whether this is an initial state.</summary>
- /// <summary>In NFA mode, no set of states qualifies as an initial state.</summary>
- public static bool IsInitialState(ref CurrentState state) => false;
+ public static int FixedLength(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, uint nextCharKind)
+ {
+ foreach (ref KeyValuePair<int, int> nfaState in CollectionsMarshal.AsSpan(state.NfaState!.NfaStateSet.Values))
+ {
+ DfaMatchingState<TSet> coreState = builder.GetCoreState(nfaState.Key);
+ if (coreState.IsNullableFor(nextCharKind))
+ {
+ return coreState.FixedLength(nextCharKind);
+ }
+ }
+ Debug.Fail("FixedLength should only be called in nullable state/context.");
+ return -1;
+ }
/// <summary>Take the transition to the next NFA state.</summary>
public static bool TakeTransition(SymbolicRegexBuilder<TSet> builder, ref CurrentState state, int mintermId)
{
- Debug.Assert(state.DfaState is null, $"Expected null {nameof(state.DfaState)}.");
+ Debug.Assert(state.DfaStateId < 0, $"Expected negative {nameof(state.DfaStateId)}.");
Debug.Assert(state.NfaState is not null, $"Expected non-null {nameof(state.NfaState)}.");
NfaMatchingState nfaState = state.NfaState!;
@@ -1127,11 +1143,57 @@ namespace System.Text.RegularExpressions.Symbolic
}
}
+ /// <summary>
+ /// Gets context independent state information:
+ /// - whether this is an initial state
+ /// - whether this is a dead-end state, meaning there are no transitions possible out of the state
+ /// - whether this state is unconditionally nullable
+ /// - whether this state may be contextually nullable
+ /// </summary>
+ /// <remarks>
+ /// In NFA mode:
+ /// - an empty set of states means that it is a dead end
+ /// - no set of states qualifies as an initial state. This could be made more accurate, but with that the
+ /// matching logic would need to be updated to handle the fact that <see cref="InitialStateFindOptimizationsHandler"/>
+ /// can transition back to a DFA state.
+ /// </remarks>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static (bool IsInitial, bool IsDeadend, bool IsNullable, bool CanBeNullable) GetStateInfo(SymbolicRegexBuilder<TSet> builder, ref CurrentState state) =>
+ (false, state.NfaState!.NfaStateSet.Count == 0, IsNullable(builder, ref state), CanBeNullable(builder, ref state));
+
+ /// <summary>Check if any underlying core state is unconditionally nullable.</summary>
+ private static bool IsNullable(SymbolicRegexBuilder<TSet> builder, ref CurrentState state)
+ {
+ foreach (ref KeyValuePair<int, int> nfaState in CollectionsMarshal.AsSpan(state.NfaState!.NfaStateSet.Values))
+ {
+ if (builder.GetStateInfo(builder.GetCoreStateId(nfaState.Key)).IsNullable)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>Check if any underlying core state can be nullable in some context.</summary>
+ private static bool CanBeNullable(SymbolicRegexBuilder<TSet> builder, ref CurrentState state)
+ {
+ foreach (ref KeyValuePair<int, int> nfaState in CollectionsMarshal.AsSpan(state.NfaState!.NfaStateSet.Values))
+ {
+ if (builder.GetStateInfo(builder.GetCoreStateId(nfaState.Key)).CanBeNullable)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
#if DEBUG
/// <summary>Undo a previous call to <see cref="TakeTransition"/>.</summary>
public static void UndoTransition(ref CurrentState state)
{
- Debug.Assert(state.DfaState is null, $"Expected null {nameof(state.DfaState)}.");
+ Debug.Assert(state.DfaStateId < 0, $"Expected negative {nameof(state.DfaState)}.");
Debug.Assert(state.NfaState is not null, $"Expected non-null {nameof(state.NfaState)}.");
NfaMatchingState nfaState = state.NfaState!;
@@ -1177,5 +1239,84 @@ namespace System.Text.RegularExpressions.Symbolic
}
#endif
}
+
+ /// <summary>
+ /// Interface for optimizations to accelerate search from initial states.
+ /// </summary>
+ private interface IInitialStateHandler
+ {
+ public static abstract bool TryFindNextStartingPosition(SymbolicRegexMatcher<TSet> matcher, ReadOnlySpan<char> input, ref CurrentState state, ref int pos);
+ }
+
+ /// <summary>
+ /// No-op handler for when there are no initial state optimizations to apply.
+ /// </summary>
+ private readonly struct NoOptimizationsInitialStateHandler : IInitialStateHandler
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool TryFindNextStartingPosition(SymbolicRegexMatcher<TSet> matcher, ReadOnlySpan<char> input, ref CurrentState state, ref int pos)
+ {
+ // return true to indicate that the current position is a possible starting position
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Handler for when a <see cref="RegexFindOptimizations"/> instance is available.
+ /// </summary>
+ private readonly struct InitialStateFindOptimizationsHandler : IInitialStateHandler
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool TryFindNextStartingPosition(SymbolicRegexMatcher<TSet> matcher, ReadOnlySpan<char> input, ref CurrentState state, ref int pos)
+ {
+ // Find the first position that matches with some likely character.
+ if (!matcher._findOpts!.TryFindNextStartingPosition(input, ref pos, 0))
+ {
+ // No match exists
+ return false;
+ }
+
+ // Update the starting state based on where TryFindNextStartingPosition moved us to.
+ // As with the initial starting state, if it's a dead end, no match exists.
+ state = new CurrentState(matcher._dotstarredInitialStates[matcher.GetCharKind(input, pos - 1)]);
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Interface for evaluating nullability of states.
+ /// </summary>
+ private interface INullabilityHandler
+ {
+ public static abstract bool IsNullableAt<TStateHandler>(SymbolicRegexMatcher<TSet> matcher, ref CurrentState state, ReadOnlySpan<char> input, int pos, bool isNullable, bool canBeNullable)
+ where TStateHandler : struct, IStateHandler;
+ }
+
+ /// <summary>
+ /// Specialized nullability handler for patterns without any anchors.
+ /// </summary>
+ private readonly struct NoAnchorsNullabilityHandler : INullabilityHandler
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsNullableAt<TStateHandler>(SymbolicRegexMatcher<TSet> matcher, ref CurrentState state, ReadOnlySpan<char> input, int pos, bool isNullable, bool canBeNullable)
+ where TStateHandler : struct, IStateHandler
+ {
+ Debug.Assert(!matcher._pattern._info.ContainsSomeAnchor);
+ return isNullable;
+ }
+ }
+
+ /// <summary>
+ /// Nullability handler that will work for any pattern.
+ /// </summary>
+ private readonly struct FullNullabilityHandler : INullabilityHandler
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsNullableAt<TStateHandler>(SymbolicRegexMatcher<TSet> matcher, ref CurrentState state, ReadOnlySpan<char> input, int pos, bool isNullable, bool canBeNullable)
+ where TStateHandler : struct, IStateHandler
+ {
+ return isNullable || (canBeNullable && TStateHandler.IsNullableFor(matcher._builder, ref state, matcher.GetCharKind(input, pos)));
+ }
+ }
}
}
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs
index 0be82814332..71d997982c3 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs
@@ -1288,7 +1288,8 @@ namespace System.Text.RegularExpressions.Symbolic
// so d(R{m,n}) = d(R)R{max(0,m-1),n-1}. Note that n is guaranteed to be greater than zero, since otherwise the
// loop would have been simplified to nothing, and int.MaxValue is treated as infinity.
int newupper = _upper == int.MaxValue ? int.MaxValue : _upper - 1;
- int newlower = _lower == 0 ? 0 : _lower - 1;
+ // do not decrement the lower bound if it equals int.MaxValue
+ int newlower = _lower == 0 || _lower == int.MaxValue ? _lower : _lower - 1;
// the continued loop becomes epsilon when newlower == newupper == 0
// in which case the returned concatenation will be just bodyDerivative
derivative = _builder.CreateConcat(bodyDerivative, _builder.CreateLoop(_left, IsLazy, newlower, newupper));
@@ -2212,5 +2213,95 @@ namespace System.Text.RegularExpressions.Symbolic
break;
}
}
+
+ /// <summary>
+ /// Let #(this) denote the number of singletons in this node.
+ /// Then the NFA size estimation in terms of state count
+ /// is #(this) if there are no anchors else <see cref="CharKind.CharKindCount"/>x#(this).
+ /// Add 1 for the initial state also.
+ /// </summary>
+ internal int EstimateNfaSize() => Times(_info.ContainsSomeAnchor ? CharKind.CharKindCount : 1, Sum(1, CountSingletons()));
+
+ /// <summary>
+ /// Count the number of Regex Singletons, if all loops with explicit counters
+ /// were eliminated from the node, i.e., as if the repetitions were explicitly unfolded.
+ /// </summary>
+ /// <remarks>
+ /// Let node.CountSingletons() be abbreviated by #(node).
+ /// Ex: #(a{6}) = 6*#(a) = 6
+ /// Ex: #(a+|()) = #(aa*) = 2
+ /// Ex: #(a{3,6}) = 6
+ /// Ex: #(a{6,}) = #(a{6}a*)= 7
+ /// </remarks>
+ internal int CountSingletons()
+ {
+ // Guard against stack overflow due to deep recursion
+ if (!StackHelper.TryEnsureSufficientExecutionStack())
+ {
+ return StackHelper.CallOnEmptyStack(CountSingletons);
+ }
+
+ switch (_kind)
+ {
+ case SymbolicRegexNodeKind.Singleton:
+ return 1;
+
+ case SymbolicRegexNodeKind.Concat:
+ case SymbolicRegexNodeKind.Alternate:
+ Debug.Assert(_left is not null && _right is not null);
+ // #(this) = #(_left) + #(_right)
+ return Sum(_left.CountSingletons(), _right.CountSingletons());
+
+ case SymbolicRegexNodeKind.Loop:
+ Debug.Assert(_left is not null && _right is null);
+ Debug.Assert(_lower >= 0 && _upper > 0 && _upper >= _lower);
+ if (_upper == int.MaxValue)
+ {
+ if (_lower == 0 || _lower == int.MaxValue)
+ {
+ // infinite loop has the same size as a *-loop
+ return _left.CountSingletons();
+ }
+
+ // the upper bound is not being used, so the lower must be non-zero
+ Debug.Assert(_lower > 0);
+
+ // The case is R{m,} with R = _left and m = _lower.
+ // #(this) = (m+1) x #(R)
+ // Ex: #((ab){4,}) = #((ab)(ab)(ab)(ab)(ab)*) = 5x2 = 10
+ return Times(_lower + 1, _left.CountSingletons());
+ }
+
+ // The general case with both upper and lower bounds is R{m,n} with m =_lower and n = _upper
+ // #(this) = n x #(R)
+ // Ex: #((ab){4,6}) = #((ab)(ab)(ab)(ab)(ab)?(ab)?) = 6x2 = 12
+ return Times(_upper, _left.CountSingletons());
+
+ case SymbolicRegexNodeKind.DisableBacktrackingSimulation:
+ case SymbolicRegexNodeKind.Effect:
+ Debug.Assert(_left is not null);
+ return _left.CountSingletons();
+
+ default:
+ Debug.Assert(_left is null && _right is null);
+ // All the other nodes contribute 0 to the overall count
+ // because they contain no children and therefore no singletons
+ return 0;
+ }
+ }
+
+ // In case of overflow in m+n, return int.MaxValue
+ private static int Sum(int m, int n)
+ {
+ Debug.Assert(m >= 0 && n >= 0);
+ return (int)Math.Min((long)m + n, int.MaxValue);
+ }
+
+ // In case of overflow in m*n return int.MaxValue
+ private static int Times(int m, int n)
+ {
+ Debug.Assert(m >= 0 && n >= 0);
+ return (int)Math.Min((long)m * n, int.MaxValue);
+ }
}
}
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexRunnerFactory.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexRunnerFactory.cs
index 282ae2be7bf..012390646ff 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexRunnerFactory.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexRunnerFactory.cs
@@ -22,6 +22,20 @@ namespace System.Text.RegularExpressions.Symbolic
var converter = new RegexNodeConverter(bddBuilder, regexTree.CaptureNumberSparseMapping);
SymbolicRegexNode<BDD> rootNode = converter.ConvertToSymbolicRegexNode(regexTree.Root);
+ // Determine if the root node is supported for safe handling
+ int threshold = SymbolicRegexThresholds.GetSymbolicRegexSafeSizeThreshold();
+ Debug.Assert(threshold > 0);
+
+ // Skip the threshold check if the threshold equals int.MaxValue
+ if (threshold != int.MaxValue)
+ {
+ int size = rootNode.EstimateNfaSize();
+ if (size > threshold)
+ {
+ throw new NotSupportedException(SR.Format(SR.NotSupported_NonBacktrackingUnsafeSize, size, threshold));
+ }
+ }
+
rootNode = rootNode.AddFixedLengthMarkers();
BDD[] minterms = rootNode.ComputeMinterms();
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexThresholds.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexThresholds.cs
new file mode 100644
index 00000000000..92d9236e3c9
--- /dev/null
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexThresholds.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.
+
+namespace System.Text.RegularExpressions.Symbolic
+{
+ /// <summary>
+ /// Contains configurations of various static threshold data related to symbolic regexes.
+ /// </summary>
+ internal static class SymbolicRegexThresholds
+ {
+ /// <summary>Maximum number of built states before switching over to NFA mode.</summary>
+ /// <remarks>
+ /// By default, all matching starts out using DFAs, where every state transitions to one and only one
+ /// state for any minterm (each character maps to one minterm). Some regular expressions, however, can result
+ /// in really, really large DFA state graphs, much too big to actually store. Instead of failing when we
+ /// encounter such state graphs, at some point we instead switch from processing as a DFA to processing as
+ /// an NFA. As an NFA, we instead track all of the states we're in at any given point, and transitioning
+ /// from one "state" to the next really means for every constituent state that composes our current "state",
+ /// we find all possible states that transitioning out of each of them could result in, and the union of
+ /// all of those is our new "state". This constant represents the size of the graph after which we start
+ /// processing as an NFA instead of as a DFA. This processing doesn't change immediately, however. All
+ /// processing starts out in DFA mode, even if we've previously triggered NFA mode for the same regex.
+ /// We switch over into NFA mode the first time a given traversal (match operation) results in us needing
+ /// to create a new node and the graph is already or newly beyond this threshold.
+ /// </remarks>
+ internal const int NfaThreshold = 10_000;
+
+ /// <summary>
+ /// Default maximum estimated safe expansion size of a <see cref="SymbolicRegexNode{TSet}"/> AST
+ /// after the AST has been anlayzed for safe handling.
+ /// <remarks>
+ /// If the AST exceeds this threshold then <see cref="NotSupportedException"/> is thrown.
+ /// This default value may be overridden with the AppContext data
+ /// whose name is given by <see cref="SymbolicRegexSafeSizeThreshold_ConfigKeyName"/>.
+ /// </remarks>
+ /// </summary>
+ internal const int DefaultSymbolicRegexSafeSizeThreshold = 1000;
+
+ ///<summary>The environment variable name for a value overriding the default value <see cref="DefaultSymbolicRegexSafeSizeThreshold"/></summary>
+ internal const string SymbolicRegexSafeSizeThreshold_ConfigKeyName = "REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE";
+
+ /// <summary>
+ /// Gets the value of the environment variable whose name is
+ /// given by <see cref="SymbolicRegexSafeSizeThreshold_ConfigKeyName"/>
+ /// or else returns <see cref="DefaultSymbolicRegexSafeSizeThreshold"/>
+ /// if the environment variable is undefined, incorrectly formated, or not a positive integer.
+ /// </summary>
+ /// <remarks>
+ /// The value is queried from <code>AppContext</code>
+ /// If the AppContext's data value for that key is
+ /// not a positive integer then <see cref="DefaultSymbolicRegexSafeSizeThreshold"/> is returned.
+ /// </remarks>
+ internal static int GetSymbolicRegexSafeSizeThreshold()
+ {
+ object? safeSizeThreshold = AppContext.GetData(SymbolicRegexSafeSizeThreshold_ConfigKeyName);
+
+ return (safeSizeThreshold is not int safeSizeThresholdInt || safeSizeThresholdInt <= 0) ?
+ DefaultSymbolicRegexSafeSizeThreshold :
+ safeSizeThresholdInt;
+ }
+ }
+}
diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs
index 670d4d96dac..74f952c41fc 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs
+++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.KnownPattern.Tests.cs
@@ -1378,12 +1378,6 @@ namespace System.Text.RegularExpressions.Tests
{
foreach (RegexEngine engine in RegexHelpers.AvailableEngines)
{
- if (engine != RegexEngine.Interpreter)
- {
- // [ActiveIssue("https://github.com/dotnet/runtime/issues/69381")]
- continue;
- }
-
if (RegexHelpers.IsNonBacktracking(engine))
{
// NonBacktracking doesn't support lookarounds or balancing groups
@@ -1413,6 +1407,7 @@ namespace System.Text.RegularExpressions.Tests
[Theory]
[MemberData(nameof(RecreationalRegex_Rectangle_MemberData))]
+ [OuterLoop("May take several seconds")]
public async Task RecreationalRegex_Rectangle(RegexEngine engine, string input, bool expectedMatch)
{
Regex r = await RegexHelpers.GetRegexAsync(engine, @"
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 a56770aa25d..b6dfca73b00 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
@@ -1025,7 +1025,15 @@ namespace System.Text.RegularExpressions.Tests
[MemberData(nameof(RegexHelpers.AvailableEngines_MemberData), MemberType = typeof(RegexHelpers))]
public async Task Match_VaryingLengthStrings_Huge(RegexEngine engine)
{
- await Match_VaryingLengthStrings(engine, RegexOptions.None, 100_000);
+ RegexHelpers.SetSafeSizeThreshold(100_002);
+ try
+ {
+ await Match_VaryingLengthStrings(engine, RegexOptions.None, 100_000);
+ }
+ finally
+ {
+ RegexHelpers.RestoreSafeSizeThresholdToDefault();
+ }
}
public static IEnumerable<object[]> Match_DeepNesting_MemberData()
@@ -1468,6 +1476,49 @@ namespace System.Text.RegularExpressions.Tests
}
};
+ // Validate captures after backtracking constructs are uncaptured when backtracking
+ foreach (string lazy in new[] { "", "?" })
+ {
+ yield return new object[]
+ {
+ engine,
+ $"^a+{lazy}(a)$", "aaaa", RegexOptions.None, 0, 4,
+ new CaptureData[]
+ {
+ new CaptureData("aaaa", 0, 4),
+ new CaptureData("a", 3, 1)
+ }
+ };
+
+ yield return new object[]
+ {
+ engine,
+ $"^(a)+{lazy}(a)$", "aaaa", RegexOptions.None, 0, 4,
+ new CaptureData[]
+ {
+ new CaptureData("aaaa", 0, 4),
+ new CaptureData("a", 2, 1, new CaptureData[]
+ {
+ new CaptureData("a", 0, 1),
+ new CaptureData("a", 1, 1),
+ new CaptureData("a", 2, 1),
+ }),
+ new CaptureData("a", 3, 1)
+ }
+ };
+ }
+ yield return new object[]
+ {
+ engine,
+ $"^(|a)aa(a)$", "aaaa", RegexOptions.None, 0, 4,
+ new CaptureData[]
+ {
+ new CaptureData("aaaa", 0, 4),
+ new CaptureData("a", 0, 1),
+ new CaptureData("a", 3, 1)
+ }
+ };
+
if (!RegexHelpers.IsNonBacktracking(engine))
{
// Zero-width positive lookahead assertion: Actual - "abc(?=XXX)\\w+"
@@ -1923,7 +1974,17 @@ namespace System.Text.RegularExpressions.Tests
string fullpattern = string.Concat(string.Concat(Enumerable.Repeat($"({pattern}", pattern_repetition).Concat(Enumerable.Repeat(")", pattern_repetition))), anchor);
string fullinput = string.Concat(Enumerable.Repeat(input, input_repetition));
- Regex re = await RegexHelpers.GetRegexAsync(engine, fullpattern);
+ RegexHelpers.SetSafeSizeThreshold(10_005);
+ Regex re;
+ try
+ {
+ re = await RegexHelpers.GetRegexAsync(engine, fullpattern);
+ }
+ finally
+ {
+ RegexHelpers.RestoreSafeSizeThresholdToDefault();
+ }
+
Assert.True(re.Match(fullinput).Success);
}
@@ -1945,7 +2006,17 @@ namespace System.Text.RegularExpressions.Tests
string fullpattern = string.Concat(Enumerable.Repeat(begin, pattern_repetition)) + inner + string.Concat(Enumerable.Repeat(end, pattern_repetition));
string fullinput = string.Concat(Enumerable.Repeat(input, input_repetition));
- var re = await RegexHelpers.GetRegexAsync(engine, fullpattern, options);
+ RegexHelpers.SetSafeSizeThreshold(int.MaxValue);
+ Regex re;
+ try
+ {
+ re = await RegexHelpers.GetRegexAsync(engine, fullpattern, options);
+ }
+ finally
+ {
+ RegexHelpers.RestoreSafeSizeThresholdToDefault();
+ }
+
Assert.True(re.Match(fullinput).Success);
}
diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Replace.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Replace.Tests.cs
index fcfe41f4d01..5959d5d8f0c 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Replace.Tests.cs
+++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Replace.Tests.cs
@@ -124,7 +124,17 @@ namespace System.Text.RegularExpressions.Tests
[MemberData(nameof(Replace_String_TestData))]
public async Task Replace(RegexEngine engine, string pattern, string input, string replacement, RegexOptions options, int count, int start, string expected)
{
- Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options);
+ // A few tests exceed the 1000 limit, they reach 6003
+ RegexHelpers.SetSafeSizeThreshold(6005);
+ Regex r;
+ try
+ {
+ r = await RegexHelpers.GetRegexAsync(engine, pattern, options);
+ }
+ finally
+ {
+ RegexHelpers.RestoreSafeSizeThresholdToDefault();
+ }
bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, start);
bool isDefaultCount = RegexHelpers.IsDefaultCount(input, options, count);
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 e94e9814073..9a571dcfc8b 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
@@ -154,6 +154,22 @@ namespace System.Text.RegularExpressions.Tests
RegexEngine.NonBacktrackingSourceGenerated => RegexOptionNonBacktracking | RegexOptions.Compiled,
_ => throw new ArgumentException($"Unknown engine: {engine}"),
};
+
+ /// <summary>Set the AppContext variable REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE to the given max value. Only used with Nonbacktracking engine.</summary>
+ public static void SetSafeSizeThreshold(int maxSize)
+ {
+#if NET7_0_OR_GREATER
+ AppContext.SetData("REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE", maxSize);
+#endif
+ }
+
+ /// <summary>Remove the AppContext variable REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE value. Only used with Nonbacktracking engine.</summary>
+ public static void RestoreSafeSizeThresholdToDefault()
+ {
+#if NET7_0_OR_GREATER
+ AppContext.SetData("REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE", null);
+#endif
+ }
}
public enum RegexEngine
diff --git a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs
new file mode 100644
index 00000000000..936c7dace72
--- /dev/null
+++ b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs
@@ -0,0 +1,254 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Globalization;
+using Xunit;
+using System.Text.RegularExpressions.Symbolic;
+using System.Collections.Generic;
+
+namespace System.Text.RegularExpressions.Tests
+{
+ public class SymbolicRegexTests
+ {
+ [Theory]
+ [InlineData(UnicodeCategory.DecimalDigitNumber, 370)] //37 different kinds of decimal digits
+ [InlineData(UnicodeCategory.Surrogate, 2048)] //1024 low surrogates and 1024 high surrogates
+ public void BDDNumberOfRepresentedCharactersTests(UnicodeCategory category, uint expectedCardinality)
+ {
+ BDD digits = UnicodeCategoryConditions.GetCategory(category);
+ Assert.Equal(expectedCardinality, ComputeNumberOfRepresentedCharacters(digits));
+
+ // Returns how many characters this BDD represents
+ static uint ComputeNumberOfRepresentedCharacters(BDD bdd)
+ {
+ if (bdd.IsEmpty)
+ {
+ return 0;
+ }
+ if (bdd.IsFull)
+ {
+ return ushort.MaxValue;
+ }
+
+ (uint Lower, uint Upper)[] ranges = BDDRangeConverter.ToRanges(bdd);
+ uint result = 0;
+ for (int i = 0; i < ranges.Length; i++)
+ {
+ result += ranges[i].Upper - ranges[i].Lower + 1;
+ }
+ return result;
+ }
+ }
+
+ public static IEnumerable<object[]> SafeThresholdTests_MemberData()
+ {
+ var charSetSolver = new CharSetSolver();
+ var bddBuilder = new SymbolicRegexBuilder<BDD>(charSetSolver, charSetSolver);
+ var converter = new RegexNodeConverter(bddBuilder, null);
+
+ RegexOptions options = RegexOptions.NonBacktracking;
+
+ // pattern and its expected safe size
+ // all patterns have an implicit 0-start-capture node ⌊₀ and
+ // 0-end-capture node ⁰⌉ and thus also two extra cocatenation nodes
+ // let the safe size of a pattern X be denoted by #(X)
+ (string, int)[] patternData = new (string, int)[]{
+ // no singletons
+ ("()", 1),
+ ("()*", 1),
+ // no counters
+ ("(a)", 2),
+ ("(a|b)", 2), // (a|b) becomes [ab]
+ ("(a*)", 2),
+ ("(a?)", 2),
+ ("(ab)", 3),
+ ("(a+)", 3), // #(a+) = #(aa*) = 2 (1 is for the initial state)
+ ("(abc)", 4),
+ ("ab|c", 4),
+ // simple counters
+ ("(a{3,6})", 7), // 6x#(a) + 1
+ ("((ab){10})", 21),
+ ("((ab){10,})", 23),
+ ("((ab){0,10})", 21),
+ // nested counters
+ ("(((ab){10}){10})", 201),
+ ("(((ab){10}){0,10})", 201),
+ ("(((ab){10}){10})|((cd){10})", 221), // 200 + 20 + 1
+ ("(((ab){10,}c){10})|((cd){9,})", 251), // (2x11+1)x10 + 20 + 1
+ ("(((ab){10,}c){10,})|((cd){0,10})", 274), // (2x11+1)x11 + 20 + 1
+ // lower bound int.MaxValue is never unfolded and treated as infinity
+ ("(a{2147483647,})", 2),
+ // typical case that blows up the DFA size to 2^100 when .* is added at the beginnig (below)
+ ("a.{100}b", 103)
+ };
+
+ foreach ((string Pattern, int ExpectedSafeSize) in patternData)
+ {
+ RegexNode tree = RegexParser.Parse(Pattern, options | RegexOptions.ExplicitCapture, CultureInfo.CurrentCulture).Root;
+ SymbolicRegexNode<BDD> rootNode = converter.ConvertToSymbolicRegexNode(tree);
+ yield return new object[] { rootNode, ExpectedSafeSize };
+ }
+
+ // add .*? in front of the pattern, this adds 1 more NFA state
+ foreach ((string Pattern, int ExpectedSafeSize) in patternData)
+ {
+ RegexNode tree = RegexParser.Parse(".*?" + Pattern, options | RegexOptions.ExplicitCapture, CultureInfo.CurrentCulture).Root;
+ SymbolicRegexNode<BDD> rootNode = converter.ConvertToSymbolicRegexNode(tree);
+ yield return new object[] { rootNode, 1 + ExpectedSafeSize};
+ }
+
+ // use of anchors increases the estimate by 5x in general but in reality much less, at most 3x
+ foreach ((string Pattern, int ExpectedSafeSize) in patternData)
+ {
+ RegexNode tree = RegexParser.Parse(Pattern + "$", options | RegexOptions.ExplicitCapture, CultureInfo.CurrentCulture).Root;
+ SymbolicRegexNode<BDD> rootNode = converter.ConvertToSymbolicRegexNode(tree);
+ yield return new object[] { rootNode, 5 * ExpectedSafeSize };
+ }
+
+ // use of captures has no effect on the estimations
+ foreach ((string Pattern, int ExpectedSafeSize) in patternData)
+ {
+ RegexNode tree = RegexParser.Parse(Pattern, options, CultureInfo.CurrentCulture).Root;
+ SymbolicRegexNode<BDD> rootNode = converter.ConvertToSymbolicRegexNode(tree);
+ yield return new object[] { rootNode, ExpectedSafeSize };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(SafeThresholdTests_MemberData))]
+ public void SafeThresholdTests(object obj, int expectedSafeSize)
+ {
+ SymbolicRegexNode<BDD> node = (SymbolicRegexNode<BDD>)obj;
+ int safeSize = node.EstimateNfaSize();
+ Assert.Equal(expectedSafeSize, safeSize);
+ int nfaStateCount = CalculateNfaStateCount(node);
+ Assert.True(nfaStateCount <= expectedSafeSize);
+ }
+
+ /// <summary>
+ /// Compute the closure of all NFA states from root and return the size of the resulting state space.
+ /// </summary>
+ private static int CalculateNfaStateCount(SymbolicRegexNode<BDD> root)
+ {
+ // Here we are actually using the original BDD algebra (not converting to the BV or Uint64 algebra)
+ // because it does not matter which algebra we use here (this matters only for performance)
+ HashSet<(uint, SymbolicRegexNode<BDD>)> states = new();
+ Stack<(uint, SymbolicRegexNode<BDD>)> frontier = new();
+ List<BDD> minterms = root._builder._solver.GenerateMinterms(root.GetSets());
+
+ // Start from the initial state that has kind 'General' when no anchors are being used, else kind 'BeginningEnd'
+ (uint, SymbolicRegexNode<BDD>) initialState = (root._info.ContainsSomeAnchor ? CharKind.BeginningEnd : CharKind.General, root);
+
+ // Compute the closure of all NFA states from the given initial state
+ states.Add(initialState);
+ frontier.Push(initialState);
+ while (frontier.Count > 0)
+ {
+ (uint Kind, SymbolicRegexNode<BDD> Node) source = frontier.Pop();
+
+ // Iterate over all minterms to cover all possible inputs
+ foreach (BDD minterm in minterms)
+ {
+ uint kind = GetCharKind(minterm);
+ SymbolicRegexNode<BDD> target = source.Node.CreateDerivativeWithoutEffects(minterm, source.Kind);
+
+ //In the case of an NFA all the different alternatives in the DFA state become individual states themselves
+ foreach (SymbolicRegexNode<BDD> node in GetAlternatives(target))
+ {
+ (uint, SymbolicRegexNode<BDD>) state = (kind, node);
+ // Add the state to the set of states
+ if (states.Add(state))
+ {
+ // If state is new then it still needs to be explored
+ frontier.Push(state);
+ }
+ }
+ }
+ }
+
+ return states.Count;
+
+ // Enumerates the alternatives from a node, for eaxmple (ab|(bc|cd)) has three alternatives
+ static IEnumerable<SymbolicRegexNode<BDD>> GetAlternatives(SymbolicRegexNode<BDD> node)
+ {
+ if (node._kind == SymbolicRegexNodeKind.Alternate)
+ {
+ foreach (SymbolicRegexNode<BDD> elem in GetAlternatives(node._left!))
+ yield return elem;
+ foreach (SymbolicRegexNode<BDD> elem in GetAlternatives(node._right!))
+ yield return elem;
+ }
+ else if (!node.IsNothing) // omit deadend states
+ {
+ yield return node;
+ }
+ }
+
+ // Simplified character kind calculation that omits the special case that minterm can be the very last \n
+ // This omission has practically no effect of the size of the state space, but would complicate the logic
+ uint GetCharKind(BDD minterm) =>
+ minterm.Equals(root._builder._newLineSet) ? CharKind.Newline : // is \n
+ (!root._builder._solver.IsEmpty(root._builder._solver.And(root._builder._wordLetterForBoundariesSet, minterm)) ?
+ CharKind.WordLetter : // in \w
+ CharKind.General); // anything else, thus in particular in \W
+ }
+
+ public static IEnumerable<object[]> UnsafeThresholdTests_MemberData()
+ {
+ var charSetSolver = new CharSetSolver();
+ var bddBuilder = new SymbolicRegexBuilder<BDD>(charSetSolver, charSetSolver);
+ var converter = new RegexNodeConverter(bddBuilder, null);
+
+ // all patterns are considered with RegexOptions.ExplicitCapture
+ RegexOptions options = RegexOptions.NonBacktracking | RegexOptions.ExplicitCapture;
+
+ // patterns with large counters
+ string[] patternData = new string[]{
+ // simple counters that are too large
+ "((ab){0,9000})",
+ "((ab){1000})",
+ "((ab){100,5000})",
+ // almost infinite lower bound
+ "a{2147483646,}", // 2147483646 = int.MaxValue-1
+ // nested small counters causing unsafe blowup through multiplicative nature of counter nesting
+ "(((ab){10}){10}){10}", // more than 10^3
+ "((((abcd){4}){4}){4}){4}", // exponential: more than 4^5 = 1024
+ // combined large counters
+ "((ab){1000}){1000}", // more than 1000^2
+ "((ab){99999999}){99999999}", // multiply: much more than int.MaxValue
+ "(ab){0,1234567890}|(cd){1234567890,}",// sum: more than int.MaxValue
+ };
+
+ foreach (string Pattern in patternData)
+ {
+ RegexNode tree = RegexParser.Parse(Pattern, options, CultureInfo.CurrentCulture).Root;
+ SymbolicRegexNode<BDD> rootNode = converter.ConvertToSymbolicRegexNode(tree);
+ yield return new object[] { rootNode };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(UnsafeThresholdTests_MemberData))]
+ public void UnsafeThresholdTests(object node)
+ {
+ int size = ((SymbolicRegexNode<BDD>)node).EstimateNfaSize();
+ Assert.True(size > SymbolicRegexThresholds.GetSymbolicRegexSafeSizeThreshold());
+ }
+
+ [Theory]
+ [InlineData(200, 200)]
+ [InlineData(10_000, 10_000)]
+ [InlineData(int.MaxValue, int.MaxValue)]
+ [InlineData(0, SymbolicRegexThresholds.DefaultSymbolicRegexSafeSizeThreshold)]
+ [InlineData(-47, SymbolicRegexThresholds.DefaultSymbolicRegexSafeSizeThreshold)]
+ [InlineData("tmp", SymbolicRegexThresholds.DefaultSymbolicRegexSafeSizeThreshold)]
+ [InlineData(null, SymbolicRegexThresholds.DefaultSymbolicRegexSafeSizeThreshold)]
+ public void SafeThresholdConfigTest(object? newThresholdData, int expectedThreshold)
+ {
+ AppContext.SetData(SymbolicRegexThresholds.SymbolicRegexSafeSizeThreshold_ConfigKeyName, newThresholdData);
+ int k = SymbolicRegexThresholds.GetSymbolicRegexSafeSizeThreshold();
+ AppContext.SetData(SymbolicRegexThresholds.SymbolicRegexSafeSizeThreshold_ConfigKeyName, null);
+ Assert.Equal(expectedThreshold, k);
+ }
+ }
+}
diff --git a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/System.Text.RegularExpressions.Unit.Tests.csproj b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/System.Text.RegularExpressions.Unit.Tests.csproj
index f2e24cd806d..5a6bf287e16 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/System.Text.RegularExpressions.Unit.Tests.csproj
+++ b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/System.Text.RegularExpressions.Unit.Tests.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- xUnit2008 is about regexes and isn't appropriate in the test project for regexes -->
<!-- SYSLIB0036 is about obsoletion of regex members -->
@@ -14,7 +14,7 @@
<ItemGroup>
<DefaultReferenceExclusion Include="System.Text.RegularExpressions" />
<!--Include Unit tests as part of code coverage since we are compiling product code into the tests assembly-->
- <CoverageInclude Include="$(AssemblyName)"/>
+ <CoverageInclude Include="$(AssemblyName)" />
<Compile Include="CSharpCodeFixVerifier`2.cs" />
<Compile Include="RegexCharClassTests.cs" />
@@ -22,6 +22,7 @@
<Compile Include="RegexPrefixAnalyzerTests.cs" />
<Compile Include="RegexReductionTests.cs" />
<Compile Include="RegexTreeAnalyzerTests.cs" />
+ <Compile Include="SymbolicRegexTests.cs" />
<!-- Code included from System.Text.RegularExpressions -->
<Compile Include="$(CommonPath)System\HexConverter.cs" Link="Production\HexConverter.cs" />
@@ -51,6 +52,25 @@
<Compile Include="..\..\gen\UpgradeToRegexGeneratorCodeFixer.cs" Link="Production\UpgradeToRegexGeneratorCodeFixer.cs" />
<Compile Include="$(CommonTestPath)SourceGenerators\LiveReferencePack.cs" Link="Common\SourceGenerators\LiveReferencePack.cs" />
+ <!-- Code included from System.Text.RegularExpressions.Symbolic -->
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\BDD.cs" Link="Production\BDD.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\BDDRangeConverter.cs" Link="Production\BDDRangeConverter.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\CharKind.cs" Link="Production\CharKind.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\CharSetSolver.cs" Link="Production\CharSetSolver.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\DerivativeEffect.cs" Link="Production\DerivativeEffect.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\DfaMatchingState.cs" Link="Production\DfaMatchingState.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\DoublyLinkedList.cs" Link="Production\DoublyLinkedList.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\ISolver.cs" Link="Production\ISolver.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\MintermGenerator.cs" Link="Production\MintermGenerator.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\RegexNodeConverter.cs" Link="Production\RegexNodeConverter.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\SymbolicRegexBuilder.cs" Link="Production\SymbolicRegexBuilder.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\SymbolicRegexInfo.cs" Link="Production\SymbolicRegexInfo.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\SymbolicRegexKind.cs" Link="Production\SymbolicRegexKind.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\SymbolicRegexNode.cs" Link="Production\SymbolicRegexNode.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\SymbolicRegexThresholds.cs" Link="Production\SymbolicRegexThresholds.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\UnicodeCategoryConditions.cs" Link="Production\UnicodeCategoryConditions.cs" />
+ <Compile Include="..\..\src\System\Text\RegularExpressions\Symbolic\UnicodeCategoryRanges.cs" Link="Production\UnicodeCategoryRanges.cs" />
+
<!-- Code used as stubs to avoid pulling in further code from System.Text.RegularExpressions -->
<Compile Include="Stubs.cs" />
<Compile Include="UpgradeToRegexGeneratorAnalyzerTests.cs" />
diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index 0b7e69caae7..a7ff3edf116 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -171,8 +171,6 @@
<!-- https://github.com/dotnet/runtime/issues/50926 -->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Diagnostics.Tracing\tests\System.Diagnostics.Tracing.Tests.csproj" />
- <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Http\tests\FunctionalTests\System.Net.Http.Functional.Tests.csproj" />
-
<!-- Execution may be compromised -->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)Microsoft.Extensions.Caching.Memory\tests\Microsoft.Extensions.Caching.Memory.Tests.csproj" />
diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
index 0bc41f4a9d9..b66fe940497 100644
--- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -279,15 +279,6 @@
<Link>Common\Interop\Unix\System.Native\Interop.GetEnviron.cs</Link>
</Compile>
</ItemGroup>
- <ItemGroup Condition="'$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'">
- <Compile Include="$(BclSourcesRoot)\System\Environment.iOS.cs" />
- <Compile Include="$(CommonPath)Interop\OSX\System.Native\Interop.SearchPath.cs">
- <Link>Common\Interop\OSX\Interop.SearchPath.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\OSX\System.Native\Interop.SearchPath.iOS.cs">
- <Link>Common\Interop\OSX\Interop.SearchPath.iOS.cs</Link>
- </Compile>
- </ItemGroup>
<ItemGroup Condition="'$(TargetsBrowser)' == 'true'">
<Compile Include="$(BclSourcesRoot)\System\Threading\TimerQueue.Browser.Mono.cs" />
</ItemGroup>
diff --git a/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs b/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs
deleted file mode 100644
index 99d5b3305fb..00000000000
--- a/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs
+++ /dev/null
@@ -1,119 +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.IO;
-using System.Threading;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-using NSSearchPathDirectory = Interop.Sys.NSSearchPathDirectory;
-
-namespace System
-{
- public static partial class Environment
- {
- private static Dictionary<SpecialFolder, string>? s_specialFolders;
-
- private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option)
- {
- if (s_specialFolders == null)
- {
- Interlocked.CompareExchange(ref s_specialFolders, new Dictionary<SpecialFolder, string>(), null);
- }
-
- string? path;
- lock (s_specialFolders)
- {
- if (!s_specialFolders.TryGetValue(folder, out path))
- {
- path = GetSpecialFolder(folder) ?? string.Empty;
- s_specialFolders[folder] = path;
- }
- }
- return path;
- }
-
- private static string? GetSpecialFolder(SpecialFolder folder)
- {
- switch (folder)
- {
- case SpecialFolder.Personal:
- case SpecialFolder.LocalApplicationData:
- return CombineDocumentDirectory(string.Empty);
-
- case SpecialFolder.ApplicationData:
- // note: at first glance that looked like a good place to return NSLibraryDirectory
- // but it would break isolated storage for existing applications
- return CombineDocumentDirectory(".config");
-
- case SpecialFolder.Resources:
- return Interop.Sys.SearchPath(NSSearchPathDirectory.NSLibraryDirectory); // older (8.2 and previous) would return String.Empty
-
- case SpecialFolder.Desktop:
- case SpecialFolder.DesktopDirectory:
- return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Desktop");
-
- case SpecialFolder.MyMusic:
- return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Music");
-
- case SpecialFolder.MyPictures:
- return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Pictures");
-
- case SpecialFolder.Templates:
- return CombineDocumentDirectory("Templates");
-
- case SpecialFolder.MyVideos:
- return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos");
-
- case SpecialFolder.CommonTemplates:
- return "/usr/share/templates";
-
- case SpecialFolder.Fonts:
- return CombineDocumentDirectory(".fonts");
-
- case SpecialFolder.Favorites:
- return CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, "Favorites");
-
- case SpecialFolder.ProgramFiles:
- return Interop.Sys.SearchPath(NSSearchPathDirectory.NSApplicationDirectory);
-
- case SpecialFolder.InternetCache:
- return Interop.Sys.SearchPath(NSSearchPathDirectory.NSCachesDirectory);
-
- case SpecialFolder.UserProfile:
- return GetEnvironmentVariable("HOME");
-
- case SpecialFolder.CommonApplicationData:
- return "/usr/share";
-
- default:
- return string.Empty;
- }
-
- static string CombineSearchPath(NSSearchPathDirectory searchPath, string subdirectory)
- {
- string? path = Interop.Sys.SearchPath(searchPath);
- return path != null ?
- Path.Combine(path, subdirectory) :
- string.Empty;
- }
-
- static string CombineDocumentDirectory(string subdirectory)
- {
-#if TARGET_TVOS
- string? path = CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, Path.Combine("Caches", "Documents"));
- // Special version of CombineSearchPath which creates the path if needed.
- // This isn't needed for "real" search paths which always exist, but on tvOS
- // the base path is really a subdirectory we define rather than an OS directory.
- // In order to not treat Directory.Exists(SpecialFolder.ApplicationData) differently
- // on tvOS, guarantee that it exists by creating it here
- if (!Directory.Exists(path))
- Directory.CreateDirectory(path);
- path = Path.Combine(path, subdirectory);
-#else
- string? path = CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, subdirectory);
-#endif
- return path;
- }
- }
- }
-}
diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c
index a08096b8b1f..519a5741207 100644
--- a/src/mono/mono/component/debugger-agent.c
+++ b/src/mono/mono/component/debugger-agent.c
@@ -6498,8 +6498,8 @@ send_enc_delta (MonoImage *image, gconstpointer dmeta_bytes, int32_t dmeta_len,
EnCInfo info;
info.image = image;
- info.meta_bytes = dpdb_bytes;
- info.meta_len = dpdb_len;
+ info.meta_bytes = dmeta_bytes;
+ info.meta_len = dmeta_len;
info.pdb_bytes = dpdb_bytes;
info.pdb_len = dpdb_len;
@@ -7827,9 +7827,6 @@ static int get_static_field_value(MonoClassField* f, MonoClass* klass, MonoDomai
if (!is_ok(error))
return -1;
- /* TODO: metadata-update. implement support for added fields */
- g_assert (!m_field_is_from_update (f));
-
if (CHECK_ICORDBG (TRUE))
{
void *src;
diff --git a/src/mono/mono/component/hot_reload-stub.c b/src/mono/mono/component/hot_reload-stub.c
index 5043423c203..efe3163a9d8 100644
--- a/src/mono/mono/component/hot_reload-stub.c
+++ b/src/mono/mono/component/hot_reload-stub.c
@@ -101,6 +101,9 @@ hot_reload_stub_added_methods_iter (MonoClass *klass, gpointer *iter);
static MonoClassField *
hot_reload_stub_added_fields_iter (MonoClass *klass, gboolean lazy, gpointer *iter);
+static uint32_t
+hot_reload_get_num_fields_added (MonoClass *klass);
+
static MonoComponentHotReload fn_table = {
{ MONO_COMPONENT_ITF_VERSION, &hot_reload_stub_available },
&hot_reload_stub_set_fastpath_data,
@@ -131,6 +134,7 @@ static MonoComponentHotReload fn_table = {
&hot_reload_stub_get_typedef_skeleton_events,
&hot_reload_stub_added_methods_iter,
&hot_reload_stub_added_fields_iter,
+ &hot_reload_get_num_fields_added
};
static bool
@@ -313,6 +317,12 @@ hot_reload_stub_added_fields_iter (MonoClass *klass, gboolean lazy, gpointer *it
return NULL;
}
+static uint32_t
+hot_reload_get_num_fields_added (MonoClass *klass)
+{
+ return 0;
+}
+
MONO_COMPONENT_EXPORT_ENTRYPOINT
MonoComponentHotReload *
diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c
index 4a9e012055c..6f4696e4ef8 100644
--- a/src/mono/mono/component/hot_reload.c
+++ b/src/mono/mono/component/hot_reload.c
@@ -26,6 +26,7 @@
#include "mono/metadata/debug-internals.h"
#include "mono/metadata/mono-debug.h"
#include "mono/metadata/debug-mono-ppdb.h"
+#include "mono/metadata/class-init.h"
#include "mono/utils/bsearch.h"
@@ -134,6 +135,9 @@ hot_reload_added_methods_iter (MonoClass *klass, gpointer *iter);
static MonoClassField *
hot_reload_added_fields_iter (MonoClass *klass, gboolean lazy, gpointer *iter);
+static uint32_t
+hot_reload_get_num_fields_added (MonoClass *klass);
+
static MonoClassMetadataUpdateField *
metadata_update_field_setup_basic_info_and_resolve (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, DeltaInfo *delta_info, MonoClass *parent_klass, uint32_t fielddef_token, uint32_t field_flags, MonoError *error);
@@ -167,6 +171,7 @@ static MonoComponentHotReload fn_table = {
&hot_reload_get_typedef_skeleton_events,
&hot_reload_added_methods_iter,
&hot_reload_added_fields_iter,
+ &hot_reload_get_num_fields_added,
};
MonoComponentHotReload *
@@ -967,6 +972,17 @@ dump_update_summary (MonoImage *image_base, MonoImage *image_dmeta)
}
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "================================");
+ rows = mono_image_get_table_rows (image_dmeta, MONO_TABLE_TYPEDEF);
+ for (int i = 1; i <= rows; ++i) {
+ guint32 cols [MONO_TYPEDEF_SIZE];
+ mono_metadata_decode_row (&image_dmeta->tables [MONO_TABLE_TYPEDEF], i - 1, cols, MONO_TYPEDEF_SIZE);
+ const char *name = mono_metadata_string_heap (image_base, cols [MONO_TYPEDEF_NAME]);
+ const char *nspace = mono_metadata_string_heap (image_base, cols [MONO_TYPEDEF_NAMESPACE]);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "dmeta typedef i=%d (token=0x%08x) -> nspace=[%x]%s, name=[%x]%s", i, MONO_TOKEN_TYPE_REF | i, cols [MONO_TYPEDEF_NAMESPACE], nspace, cols [MONO_TYPEDEF_NAME], name);
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "================================");
+
rows = mono_image_get_table_rows (image_base, MONO_TABLE_METHOD);
for (int i = 1; i <= rows ; ++i) {
guint32 cols [MONO_METHOD_SIZE];
@@ -2854,7 +2870,8 @@ hot_reload_get_field (MonoClass *klass, uint32_t fielddef_token) {
static MonoClassMetadataUpdateField *
metadata_update_field_setup_basic_info_and_resolve (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, DeltaInfo *delta_info, MonoClass *parent_klass, uint32_t fielddef_token, uint32_t field_flags, MonoError *error)
{
- g_assert (m_class_is_inited (parent_klass));
+ if (!m_class_is_inited (parent_klass))
+ mono_class_init_internal (parent_klass);
MonoClassMetadataUpdateInfo *parent_info = mono_class_get_or_add_metadata_update_info (parent_klass);
@@ -3087,3 +3104,12 @@ hot_reload_added_fields_iter (MonoClass *klass, gboolean lazy G_GNUC_UNUSED, gpo
*iter = GUINT_TO_POINTER (idx);
return &field->field;
}
+
+static uint32_t
+hot_reload_get_num_fields_added (MonoClass *klass)
+{
+ MonoClassMetadataUpdateInfo *info = mono_class_get_metadata_update_info (klass);
+ if (!info)
+ return 0;
+ return g_slist_length (info->added_fields);
+}
diff --git a/src/mono/mono/component/hot_reload.h b/src/mono/mono/component/hot_reload.h
index 62c7c305c5e..c2d5b5dcee5 100644
--- a/src/mono/mono/component/hot_reload.h
+++ b/src/mono/mono/component/hot_reload.h
@@ -45,6 +45,7 @@ typedef struct _MonoComponentHotReload {
gboolean (*get_typedef_skeleton_events) (MonoImage *base_image, uint32_t typedef_token, uint32_t *first_event_idx, uint32_t *event_count);
MonoMethod* (*added_methods_iter) (MonoClass *klass, gpointer *iter);
MonoClassField* (*added_fields_iter) (MonoClass *klass, gboolean lazy, gpointer *iter);
+ uint32_t (*get_num_fields_added) (MonoClass *klass);
} MonoComponentHotReload;
MONO_COMPONENT_EXPORT_ENTRYPOINT
diff --git a/src/mono/mono/metadata/assembly.c b/src/mono/mono/metadata/assembly.c
index e0756bf2cec..56d206467bf 100644
--- a/src/mono/mono/metadata/assembly.c
+++ b/src/mono/mono/metadata/assembly.c
@@ -969,24 +969,21 @@ mono_assembly_load_reference (MonoImage *image, int index)
goto commit_reference;
}
- if (image->assembly) {
- if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
- char *aname_str = mono_stringify_assembly_name (&aname);
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Loading reference %d of %s (%s), looking for %s",
- index, image->name, mono_alc_is_default (mono_image_get_alc (image)) ? "default ALC" : "custom ALC" ,
- aname_str);
- g_free (aname_str);
- }
-
- MonoAssemblyByNameRequest req;
- mono_assembly_request_prepare_byname (&req, mono_image_get_alc (image));
- req.requesting_assembly = image->assembly;
- //req.no_postload_search = TRUE; // FIXME: should this be set?
- reference = mono_assembly_request_byname (&aname, &req, NULL);
- } else {
- g_assertf (image->assembly, "While loading reference %d MonoImage %s doesn't have a MonoAssembly", index, image->name);
+ g_assertf (image->assembly || image->not_executable, "While loading reference %d, executable MonoImage %s doesn't have a MonoAssembly", index, image->name);
+ if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
+ char *aname_str = mono_stringify_assembly_name (&aname);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Loading reference %d of %s (%s), looking for %s",
+ index, image->name, mono_alc_is_default (mono_image_get_alc (image)) ? "default ALC" : "custom ALC" ,
+ aname_str);
+ g_free (aname_str);
}
+ MonoAssemblyByNameRequest req;
+ mono_assembly_request_prepare_byname (&req, mono_image_get_alc (image));
+ req.requesting_assembly = image->assembly;
+ //req.no_postload_search = TRUE; // FIXME: should this be set?
+ reference = mono_assembly_request_byname (&aname, &req, NULL);
+
if (reference == NULL){
char *extra_msg;
@@ -1602,8 +1599,10 @@ mono_assembly_request_open (const char *filename, const MonoAssemblyOpenRequest
loaded_from_bundle = image != NULL;
}
- if (!image)
- image = mono_image_open_a_lot (load_req.alc, fname, status);
+ if (!image) {
+ MonoImageOpenOptions options = {0, };
+ image = mono_image_open_a_lot (load_req.alc, fname, status, &options);
+ }
if (!image){
if (*status == MONO_IMAGE_OK)
diff --git a/src/mono/mono/metadata/class-init.h b/src/mono/mono/metadata/class-init.h
index 1ec64459376..168f35a47e1 100644
--- a/src/mono/mono/metadata/class-init.h
+++ b/src/mono/mono/metadata/class-init.h
@@ -10,7 +10,7 @@
#include <mono/metadata/metadata.h>
#include <mono/metadata/class-internals.h>
-gboolean
+MONO_COMPONENT_API gboolean
mono_class_init_internal (MonoClass *klass);
void
diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c
index dcee1d3fc37..c7f0960fef0 100644
--- a/src/mono/mono/metadata/class.c
+++ b/src/mono/mono/metadata/class.c
@@ -4970,6 +4970,10 @@ mono_class_get_byref_type (MonoClass *klass)
int
mono_class_num_fields (MonoClass *klass)
{
+ MonoImage *image = m_class_get_image (klass);
+ if (G_UNLIKELY (image->has_updates)) {
+ return mono_class_get_field_count (klass) + mono_metadata_update_get_num_fields_added (klass);
+ }
return mono_class_get_field_count (klass);
}
diff --git a/src/mono/mono/metadata/image-internals.h b/src/mono/mono/metadata/image-internals.h
index d22b85bdce1..d9433dda2a3 100644
--- a/src/mono/mono/metadata/image-internals.h
+++ b/src/mono/mono/metadata/image-internals.h
@@ -9,6 +9,17 @@
#include <mono/metadata/image.h>
#include <mono/metadata/loader-internals.h>
+typedef struct {
+ int dont_care_about_cli : 1;
+ int dont_care_about_pecoff : 1;
+} MonoImageLoadOptions;
+
+typedef struct {
+ MonoImageLoadOptions load_options;
+ int not_executable : 1;
+ int metadata_only : 1;
+} MonoImageOpenOptions;
+
MonoImage*
mono_image_loaded_internal (MonoAssemblyLoadContext *alc, const char *name);
@@ -19,6 +30,6 @@ MonoImage*
mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error);
MonoImage *
-mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status);
+mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, const MonoImageOpenOptions *options);
#endif /* __MONO_METADATA_IMAGE_INTERNALS_H__ */
diff --git a/src/mono/mono/metadata/image.c b/src/mono/mono/metadata/image.c
index 0bb317c3e5c..2dbcf88cc27 100644
--- a/src/mono/mono/metadata/image.c
+++ b/src/mono/mono/metadata/image.c
@@ -104,7 +104,7 @@ mono_images_unlock(void)
}
static MonoImage *
-mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status);
+mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, const MonoImageOpenOptions *options);
/* Maps string keys to MonoImageStorage values.
*
@@ -1174,8 +1174,7 @@ dump_encmap (MonoImage *image)
}
static MonoImage *
-do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
- gboolean care_about_cli, gboolean care_about_pecoff)
+do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, const MonoImageLoadOptions *options)
{
ERROR_DECL (error);
GSList *l;
@@ -1201,7 +1200,7 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
if (status)
*status = MONO_IMAGE_IMAGE_INVALID;
- if (care_about_pecoff == FALSE)
+ if (options->dont_care_about_pecoff == TRUE)
goto done;
if (!mono_image_load_pe_data (image))
@@ -1210,7 +1209,7 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
image->loader = (MonoImageLoader*)&pe_loader;
}
- if (care_about_cli == FALSE) {
+ if (options->dont_care_about_cli == TRUE) {
goto done;
}
@@ -1409,8 +1408,7 @@ mono_image_storage_new_raw_data (char *datac, guint32 data_len, gboolean raw_dat
}
static MonoImage *
-do_mono_image_open (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status,
- gboolean care_about_cli, gboolean care_about_pecoff, gboolean metadata_only)
+do_mono_image_open (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, const MonoImageOpenOptions *options)
{
MonoCLIImageInfo *iinfo;
MonoImage *image;
@@ -1424,6 +1422,7 @@ do_mono_image_open (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOp
}
image = g_new0 (MonoImage, 1);
+ image->ref_count = 1;
image->storage = storage;
mono_image_init_raw_data (image, storage);
if (!image->raw_data) {
@@ -1433,14 +1432,14 @@ do_mono_image_open (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOp
*status = MONO_IMAGE_IMAGE_INVALID;
return NULL;
}
- iinfo = g_new0 (MonoCLIImageInfo, 1);
- image->image_info = iinfo;
+ image->not_executable = !!options->not_executable;
+ image->metadata_only = !!options->metadata_only;
image->name = mono_path_resolve_symlinks (fname);
image->filename = g_strdup (image->name);
- image->metadata_only = !!metadata_only;
- image->ref_count = 1;
+ iinfo = g_new0 (MonoCLIImageInfo, 1);
+ image->image_info = iinfo;
image->alc = alc;
- return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
+ return do_mono_image_load (image, status, &options->load_options);
}
/**
@@ -1627,7 +1626,8 @@ mono_image_open_from_data_internal (MonoAssemblyLoadContext *alc, char *data, gu
image->ref_count = 1;
image->alc = alc;
- image = do_mono_image_load (image, status, TRUE, TRUE);
+ MonoImageLoadOptions options = {0, };
+ image = do_mono_image_load (image, status, &options);
if (image == NULL)
return NULL;
@@ -1742,7 +1742,8 @@ mono_image_open_from_module_handle (MonoAssemblyLoadContext *alc, HMODULE module
image->ref_count = has_entry_point ? 0 : 1;
image->alc = alc;
- image = do_mono_image_load (image, status, TRUE, TRUE);
+ MonoImageLoadOptions options = {0, };
+ image = do_mono_image_load (image, status, &options);
if (image == NULL)
return NULL;
@@ -1761,11 +1762,12 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r
*status = MONO_IMAGE_NOT_SUPPORTED;
return NULL;
}
- return mono_image_open_a_lot (mono_alc_get_default (), fname, status);
+ MonoImageOpenOptions options = {0, };
+ return mono_image_open_a_lot (mono_alc_get_default (), fname, status, &options);
}
static MonoImage *
-mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status)
+mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, const MonoImageOpenOptions *options)
{
MonoImage *image;
GHashTable *loaded_images = mono_loaded_images_get_hash (li);
@@ -1867,7 +1869,7 @@ mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadConte
mono_images_unlock ();
// Image not loaded, load it now
- image = do_mono_image_open (alc, fname, status, TRUE, TRUE, FALSE);
+ image = do_mono_image_open (alc, fname, status, options);
if (image == NULL)
return NULL;
@@ -1875,10 +1877,10 @@ mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadConte
}
MonoImage *
-mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status)
+mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, const MonoImageOpenOptions *options)
{
MonoLoadedImages *li = mono_alc_get_loaded_images (alc);
- return mono_image_open_a_lot_parameterized (li, alc, fname, status);
+ return mono_image_open_a_lot_parameterized (li, alc, fname, status, options);
}
/**
@@ -1893,7 +1895,8 @@ mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImag
MonoImage *
mono_image_open (const char *fname, MonoImageOpenStatus *status)
{
- return mono_image_open_a_lot (mono_alc_get_default (), fname, status);
+ MonoImageOpenOptions options = {0, };
+ return mono_image_open_a_lot (mono_alc_get_default (), fname, status, &options);
}
/**
@@ -1911,7 +1914,9 @@ mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
{
g_return_val_if_fail (fname != NULL, NULL);
- return do_mono_image_open (mono_alc_get_default (), fname, status, FALSE, TRUE, FALSE);
+ MonoImageOpenOptions options = {0, };
+ options.load_options.dont_care_about_cli = 1;
+ return do_mono_image_open (mono_alc_get_default (), fname, status, &options);
}
/**
@@ -1926,7 +1931,10 @@ mono_image_open_raw (MonoAssemblyLoadContext *alc, const char *fname, MonoImageO
{
g_return_val_if_fail (fname != NULL, NULL);
- return do_mono_image_open (alc, fname, status, FALSE, FALSE, FALSE);
+ MonoImageOpenOptions options = {0, };
+ options.load_options.dont_care_about_cli = 1;
+ options.load_options.dont_care_about_pecoff = 1;
+ return do_mono_image_open (alc, fname, status, &options);
}
/*
@@ -1937,7 +1945,9 @@ mono_image_open_raw (MonoAssemblyLoadContext *alc, const char *fname, MonoImageO
MonoImage *
mono_image_open_metadata_only (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status)
{
- return do_mono_image_open (alc, fname, status, TRUE, TRUE, TRUE);
+ MonoImageOpenOptions options = {0, };
+ options.metadata_only = 1;
+ return do_mono_image_open (alc, fname, status, &options);
}
/**
diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h
index d2b0e98aedb..7539845aa17 100644
--- a/src/mono/mono/metadata/metadata-internals.h
+++ b/src/mono/mono/metadata/metadata-internals.h
@@ -305,6 +305,9 @@ struct _MonoImage {
/* Whenever this is a dynamically emitted module */
guint8 dynamic : 1;
+ /* Whenever this image is not an executable, such as .mibc */
+ guint8 not_executable : 1;
+
/* Whenever this image contains uncompressed metadata */
guint8 uncompressed_metadata : 1;
diff --git a/src/mono/mono/metadata/metadata-update.c b/src/mono/mono/metadata/metadata-update.c
index bddbfa129e8..55331070852 100644
--- a/src/mono/mono/metadata/metadata-update.c
+++ b/src/mono/mono/metadata/metadata-update.c
@@ -212,3 +212,9 @@ mono_metadata_update_added_fields_iter (MonoClass *klass, gboolean lazy, gpointe
{
return mono_component_hot_reload()->added_fields_iter (klass, lazy, iter);
}
+
+uint32_t
+mono_metadata_update_get_num_fields_added (MonoClass *klass)
+{
+ return mono_component_hot_reload()->get_num_fields_added (klass);
+} \ No newline at end of file
diff --git a/src/mono/mono/metadata/metadata-update.h b/src/mono/mono/metadata/metadata-update.h
index 1cf2200e6d5..85d94e0dae4 100644
--- a/src/mono/mono/metadata/metadata-update.h
+++ b/src/mono/mono/metadata/metadata-update.h
@@ -88,4 +88,6 @@ mono_metadata_update_added_methods_iter (MonoClass *klass, gpointer *iter);
MonoClassField *
mono_metadata_update_added_fields_iter (MonoClass *klass, gboolean lazy, gpointer *iter);
+uint32_t
+mono_metadata_update_get_num_fields_added (MonoClass *klass);
#endif /*__MONO_METADATA_UPDATE_H__*/
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index 2d1a4b29571..3c551b139fa 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -43,11 +43,13 @@
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/assembly-internals.h>
+#include <mono/metadata/image-internals.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/reflection-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/mempool-internals.h>
+#include <mono/metadata/mono-basic-block.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/custom-attrs-internals.h>
@@ -186,6 +188,7 @@ typedef struct MonoAotOptions {
char *llvm_outfile;
char *data_outfile;
GList *profile_files;
+ GList *mibc_profile_files;
gboolean save_temps;
gboolean write_symbols;
gboolean metadata_only;
@@ -8522,6 +8525,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
opts->profile_files = g_list_append (opts->profile_files, g_strdup (arg + strlen ("profile=")));
} else if (!strcmp (arg, "profile-only")) {
opts->profile_only = TRUE;
+ } else if (str_begins_with (arg, "mibc-profile=")) {
+ opts->mibc_profile_files = g_list_append (opts->mibc_profile_files, g_strdup (arg + strlen ("mibc-profile=")));
} else if (!strcmp (arg, "verbose")) {
opts->verbose = TRUE;
} else if (!strcmp (arg, "allow-errors")) {
@@ -13132,6 +13137,70 @@ add_profile_method (MonoAotCompile *acfg, MonoMethod *m)
add_extra_method (acfg, m);
}
+//---------------------------------------------------------------------------------------
+//
+// add_single_profile_method filters MonoMethods to be added for AOT compilation.
+// The filter logic is extracted from add_profile_instances and comments are retained
+// from there.
+//
+// Arguments:
+// * acfg - MonoAotCompiler instance
+// * method - MonoMethod to attempt to add for AOT compilation
+//
+// Return Value:
+// int pertaining whether or not the method was added to be AOT'd
+//
+
+static int
+add_single_profile_method (MonoAotCompile *acfg, MonoMethod *method)
+{
+ if (!method)
+ return 0;
+
+ /*
+ * Add methods referenced by the profile and
+ * Add fully shared version of method instances 'related' to this assembly to the AOT image.
+ */
+ if (!method->is_inflated || mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) {
+ if (!acfg->aot_opts.profile_only)
+ return 0;
+ if (m_class_get_image (method->klass) != acfg->image)
+ return 0;
+ add_profile_method (acfg, method);
+ return 1;
+ }
+
+ /* Add all instances from the profile */
+ if (acfg->aot_opts.dedup_include) {
+ add_profile_method (acfg, method);
+ return 1;
+ }
+
+ MonoGenericContext *ctx = mono_method_get_context (method);
+ /* For simplicity, add instances which reference the assembly we are compiling */
+ if ((ctx->class_inst && inst_references_image (ctx->class_inst, acfg->image)) ||
+ (ctx->method_inst && inst_references_image (ctx->method_inst, acfg->image))) {
+ add_profile_method (acfg, method);
+ return 1;
+ }
+
+ /* Add instances where the gtd is in the assembly and its inflated with types from this assembly or corlib */
+ if (m_class_get_image (method->klass) == acfg->image &&
+ ((ctx->class_inst && is_local_inst (ctx->class_inst, acfg->image)) ||
+ (ctx->method_inst && is_local_inst (ctx->method_inst, acfg->image)))) {
+ add_profile_method (acfg, method);
+ return 1;
+ }
+
+ /*
+ * FIXME: We might skip some instances, for example:
+ * Foo<Bar> won't be compiled when compiling Foo's assembly since it doesn't match the first case,
+ * and it won't be compiled when compiling Bar's assembly if Foo's assembly is not loaded.
+ */
+
+ return 0;
+}
+
static void
add_profile_instances (MonoAotCompile *acfg, ProfileData *data)
{
@@ -13142,77 +13211,169 @@ add_profile_instances (MonoAotCompile *acfg, ProfileData *data)
if (!data)
return;
- if (acfg->aot_opts.profile_only) {
- /* Add methods referenced by the profile */
- g_hash_table_iter_init (&iter, data->methods);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- MethodProfileData *mdata = (MethodProfileData*)value;
- MonoMethod *m = mdata->method;
-
- if (!m)
- continue;
- if (m->is_inflated)
- continue;
- if (m_class_get_image (m->klass) != acfg->image)
- continue;
- add_profile_method (acfg, m);
- count ++;
- }
- }
-
- /*
- * Add method instances 'related' to this assembly to the AOT image.
- */
g_hash_table_iter_init (&iter, data->methods);
while (g_hash_table_iter_next (&iter, &key, &value)) {
MethodProfileData *mdata = (MethodProfileData*)value;
MonoMethod *m = mdata->method;
- MonoGenericContext *ctx;
+ count += add_single_profile_method (acfg, m);
+ }
+
+ printf ("Added %d methods from profile.\n", count);
+}
+
+typedef enum {
+ FIND_METHOD_TYPE_ENTRY_START,
+ FIND_METHOD_TYPE_ENTRY_END,
+} MibcGroupMethodEntryState;
+
+//---------------------------------------------------------------------------------------
+//
+// add_mibc_group_method_methods iterates over a mibcGroupMethod MonoMethod to obtain
+// each method/type entry in that group. Each entry begins with LDTOKEN opcode, followed
+// by a series of instructions including another LDTOKEN opcode but excluding a POP opcode
+// ending with a POP opcode to denote the end of the entry. To iterate over entries,
+// a MibcGroupMethodEntryState state is tracked, identifying whether we are looking for
+// an entry starting LDTOKEN opcode or entry ending POP opcode. Each LDTOKEN opcode's
+// argument denotes a methodref or methodspec. Before ultimately adding the entry's method
+// for AOT compilation, checks for the method's class and image are used to skip methods
+// whose class and images cannot be resolved.
+//
+// Sample mibcGroupMethod format
+//
+// Method 'Assemblies_HelloWorld;_1' (#11b) (0x06000001)
+// {
+// IL_0000: ldtoken 0x0A0002B5 // Method/Type Entry token
+// IL_0005: pop
+// }
+//
+// Arguments:
+// * acfg - MonoAotCompiler instance
+// * mibcGroupMethod - MonoMethod representing the group of assemblies that
+// describes each Method/Type entry with the .mibc file
+// * image - MonoImage representing the .mibc file
+// * mibcModuleClass - MonoClass containing the AssemblyDictionary
+// * context - MonoGenericContext of the AssemblyDictionary MonoMethod
+//
+// Return Value:
+// int pertaining to the number of methods added within the mibcGroupMethod
+//
+
+static int
+add_mibc_group_method_methods (MonoAotCompile *acfg, MonoMethod *mibcGroupMethod, MonoImage *image, MonoClass *mibcModuleClass, MonoGenericContext *context)
+{
+ ERROR_DECL (error);
- if (!m)
+ MonoMethodHeader *mibcGroupMethodHeader = mono_method_get_header_internal (mibcGroupMethod, error);
+ mono_error_assert_ok (error);
+
+ int count = 0;
+ MibcGroupMethodEntryState state = FIND_METHOD_TYPE_ENTRY_START;
+ uint8_t *cur = (uint8_t*)mibcGroupMethodHeader->code;
+ uint8_t *end = (uint8_t*)mibcGroupMethodHeader->code + mibcGroupMethodHeader->code_size;
+ while (cur < end) {
+ MonoOpcodeEnum il_op;
+ const unsigned char *opcodeIp = (unsigned char*)cur;
+ const unsigned char *opcodeEnd = (unsigned char*)end;
+ cur += mono_opcode_value_and_size (&opcodeIp, opcodeEnd, &il_op);
+
+ if (state == FIND_METHOD_TYPE_ENTRY_END) {
+ if (il_op == MONO_CEE_POP)
+ state = FIND_METHOD_TYPE_ENTRY_START;
continue;
- if (!m->is_inflated)
+ }
+ g_assert (il_op == MONO_CEE_LDTOKEN);
+ state = FIND_METHOD_TYPE_ENTRY_END;
+
+ g_assert (opcodeIp + 4 < opcodeEnd);
+ guint32 mibcGroupMethodEntryToken = read32 (opcodeIp + 1);
+ g_assertf ((mono_metadata_token_table (mibcGroupMethodEntryToken) == MONO_TABLE_MEMBERREF || mono_metadata_token_table (mibcGroupMethodEntryToken) == MONO_TABLE_METHODSPEC), "token %x is not MemberRef or MethodSpec.\n", mibcGroupMethodEntryToken);
+
+ MonoMethod *methodEntry = mono_get_method_checked (image, mibcGroupMethodEntryToken, mibcModuleClass, context, error);
+ mono_error_assert_ok (error);
+
+ MonoClass *method_class = mono_method_get_class (methodEntry);
+ if (!method_class)
continue;
- if (mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) {
- if (acfg->aot_opts.profile_only && m_class_get_image (m->klass) == acfg->image) {
- // Add the fully shared version to its home image
- add_profile_method (acfg, m);
- count ++;
- }
+
+ MonoImage *method_image = mono_class_get_image (method_class);
+ if (!method_image)
continue;
- }
- if (acfg->aot_opts.dedup_include) {
- /* Add all instances from the profile */
- add_profile_method (acfg, m);
- count ++;
- } else {
- ctx = mono_method_get_context (m);
- /* For simplicity, add instances which reference the assembly we are compiling */
- if (((ctx->class_inst && inst_references_image (ctx->class_inst, acfg->image)) ||
- (ctx->method_inst && inst_references_image (ctx->method_inst, acfg->image)))) {
- //printf ("%s\n", mono_method_full_name (m, TRUE));
- add_profile_method (acfg, m);
- count ++;
- } else if (m_class_get_image (m->klass) == acfg->image &&
- ((ctx->class_inst && is_local_inst (ctx->class_inst, acfg->image)) ||
- (ctx->method_inst && is_local_inst (ctx->method_inst, acfg->image)))) {
- /* Add instances where the gtd is in the assembly and its inflated with types from this assembly or corlib */
- //printf ("%s\n", mono_method_full_name (m, TRUE));
- add_profile_method (acfg, m);
- count ++;
- } else {
- //printf ("SKIP: %s (%s)\n", mono_method_get_full_name (m), acfg->image->name);
- }
- /*
- * FIXME: We might skip some instances, for example:
- * Foo<Bar> won't be compiled when compiling Foo's assembly since it doesn't match the first case,
- * and it won't be compiled when compiling Bar's assembly if Foo's assembly is not loaded.
- */
- }
+ count += add_single_profile_method (acfg, methodEntry);
+ }
+ return count;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// add_mibc_profile_methods is the overarching method that adds methods within a .mibc
+// profile file to be compiled ahead of time. .mibc is a portable executable with
+// methods grouped under mibcGroupMethods, which are summarized within the global
+// function AssemblyDictionary. This method obtains the AssemblyDictionary and iterates
+// over il opcodes and arguments to retrieve mibcGroupMethods and thereafter calls
+// add_mibc_group_method_methods.
+//
+// Sample AssemblyDictionary format
+//
+// Method 'AssemblyDictionary' (#2f67) (0x06000006)
+// {
+// IL_0000: ldstr 0x70000001
+// IL_0005: ldtoken 0x06000001 // mibcGroupMethod
+// IL_000a: pop
+// ...
+// }
+//
+// Arguments:
+// * acfg - MonoAotCompiler instance
+// * filename - the .mibc profile file containing the methods to AOT compile
+//
+
+static void
+add_mibc_profile_methods (MonoAotCompile *acfg, char *filename)
+{
+ MonoImageOpenStatus status = MONO_IMAGE_OK;
+ MonoImageOpenOptions options = {0, };
+ options.not_executable = 1;
+ MonoImage *image = mono_image_open_a_lot (mono_alc_get_default (), filename, &status, &options);
+ g_assert (image != NULL);
+ g_assert (status == MONO_IMAGE_OK);
+
+ ERROR_DECL (error);
+
+ MonoClass *mibcModuleClass = mono_class_from_name_checked (image, "", "<Module>", error);
+ mono_error_assert_ok (error);
+
+ MonoMethod *assemblyDictionary = mono_class_get_method_from_name_checked (mibcModuleClass, "AssemblyDictionary", 0, 0, error);
+ MonoGenericContext *context = mono_method_get_context (assemblyDictionary);
+ mono_error_assert_ok (error);
+
+ MonoMethodHeader *header = mono_method_get_header_internal (assemblyDictionary, error);
+ mono_error_assert_ok (error);
+
+ int count = 0;
+ uint8_t *cur = (uint8_t*)header->code;
+ uint8_t *end = (uint8_t*)header->code + header->code_size;
+ while (cur < end) {
+ MonoOpcodeEnum il_op;
+ const unsigned char *opcodeIp = (unsigned char*)cur;
+ const unsigned char *opcodeEnd = (unsigned char*)end;
+ cur += mono_opcode_value_and_size (&opcodeIp, opcodeEnd, &il_op);
+ // opcodeIp gets moved to point at end of opcode
+ // il opcode arg is opcodeIp + 1
+ // we only care about args of ldtoken's, which are 32bits/4bytes
+ if (il_op != MONO_CEE_LDTOKEN)
+ continue;
+
+ g_assert (opcodeIp + 4 < opcodeEnd);
+ guint32 token = read32 (opcodeIp + 1);
+
+ MonoMethod *mibcGroupMethod = mono_get_method_checked (image, token, mibcModuleClass, context, error);
+ mono_error_assert_ok (error);
+
+ count += add_mibc_group_method_methods (acfg, mibcGroupMethod, image, mibcModuleClass, context);
}
- printf ("Added %d methods from profile.\n", count);
+ printf ("Added %d methods from mibc profile.\n", count);
}
static void
@@ -14201,6 +14362,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options,
add_profile_instances (acfg, (ProfileData*)l->data);
}
+ if (acfg->aot_opts.mibc_profile_files) {
+ GList *l;
+
+ for (l = acfg->aot_opts.mibc_profile_files; l; l = l->next) {
+ add_mibc_profile_methods (acfg, (char*)l->data);
+ }
+ }
+
/* PLT offset 0 is reserved for the PLT trampoline */
acfg->plt_offset = 1;
add_preinit_got_slots (acfg);
diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c
index 1fd777e4235..5e2907780fa 100644
--- a/src/mono/mono/mini/interp/interp.c
+++ b/src/mono/mono/mini/interp/interp.c
@@ -7005,7 +7005,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_CASE(MINT_TIER_ENTER_METHOD) {
frame->imethod->entry_count++;
if (frame->imethod->entry_count > INTERP_TIER_ENTRY_LIMIT)
- mono_interp_tier_up_frame_enter (frame, context, &ip);
+ ip = mono_interp_tier_up_frame_enter (frame, context);
else
ip++;
MINT_IN_BREAK;
@@ -7013,7 +7013,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_CASE(MINT_TIER_PATCHPOINT) {
frame->imethod->entry_count++;
if (frame->imethod->entry_count > INTERP_TIER_ENTRY_LIMIT)
- mono_interp_tier_up_frame_patchpoint (frame, context, &ip);
+ ip = mono_interp_tier_up_frame_patchpoint (frame, context, ip [1]);
else
ip += 2;
MINT_IN_BREAK;
diff --git a/src/mono/mono/mini/interp/tiering.c b/src/mono/mono/mini/interp/tiering.c
index a064c9ffe63..7830c66c4c1 100644
--- a/src/mono/mono/mini/interp/tiering.c
+++ b/src/mono/mono/mini/interp/tiering.c
@@ -155,8 +155,8 @@ mono_interp_register_imethod_patch_site (gpointer *imethod_ptr)
mono_os_mutex_unlock (&tiering_mutex);
}
-void
-mono_interp_tier_up_frame_enter (InterpFrame *frame, ThreadContext *context, const guint16 **ip)
+const guint16*
+mono_interp_tier_up_frame_enter (InterpFrame *frame, ThreadContext *context)
{
InterpMethod *optimized_method;
if (frame->imethod->optimized_imethod)
@@ -165,7 +165,7 @@ mono_interp_tier_up_frame_enter (InterpFrame *frame, ThreadContext *context, con
optimized_method = tier_up_method (frame->imethod, context);
context->stack_pointer = (guchar*)frame->stack + optimized_method->alloca_size;
frame->imethod = optimized_method;
- *ip = optimized_method->code;
+ return optimized_method->code;
}
static int
@@ -180,8 +180,8 @@ lookup_patchpoint_data (InterpMethod *imethod, int data)
return G_MAXINT32;
}
-void
-mono_interp_tier_up_frame_patchpoint (InterpFrame *frame, ThreadContext *context, const guint16 **ip)
+const guint16*
+mono_interp_tier_up_frame_patchpoint (InterpFrame *frame, ThreadContext *context, int bb_index)
{
InterpMethod *unoptimized_method = frame->imethod;
InterpMethod *optimized_method;
@@ -209,6 +209,5 @@ mono_interp_tier_up_frame_patchpoint (InterpFrame *frame, ThreadContext *context
}
context->stack_pointer = (guchar*)frame->stack + optimized_method->alloca_size;
frame->imethod = optimized_method;
- int bb_index = (*ip) [1];
- *ip = optimized_method->code + lookup_patchpoint_data (optimized_method, bb_index);
+ return optimized_method->code + lookup_patchpoint_data (optimized_method, bb_index);
}
diff --git a/src/mono/mono/mini/interp/tiering.h b/src/mono/mono/mini/interp/tiering.h
index fd93e83ea7d..dbd7da87ecd 100644
--- a/src/mono/mono/mini/interp/tiering.h
+++ b/src/mono/mono/mini/interp/tiering.h
@@ -17,10 +17,10 @@ mono_interp_register_imethod_data_items (gpointer *data_items, GSList *indexes);
void
mono_interp_register_imethod_patch_site (gpointer *imethod_ptr);
-void
-mono_interp_tier_up_frame_enter (InterpFrame *frame, ThreadContext *context, const guint16 **ip);
+const guint16*
+mono_interp_tier_up_frame_enter (InterpFrame *frame, ThreadContext *context);
-void
-mono_interp_tier_up_frame_patchpoint (InterpFrame *frame, ThreadContext *context, const guint16 **ip);
+const guint16*
+mono_interp_tier_up_frame_patchpoint (InterpFrame *frame, ThreadContext *context, int bb_index);
#endif /* __MONO_MINI_INTERP_TIERING_H__ */
diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c
index d87db0556f2..0371868a8fb 100644
--- a/src/mono/mono/mini/method-to-ir.c
+++ b/src/mono/mono/mini/method-to-ir.c
@@ -8912,6 +8912,8 @@ calli_end:
break;
}
+ if (!(ins_flag & MONO_INST_NONULLCHECK))
+ MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg, FALSE);
ins = mini_emit_memory_load (cfg, m_class_get_byval_arg (klass), sp [0], 0, ins_flag);
*sp++ = ins;
diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c
index 441f20b1491..4c705e6f1cd 100644
--- a/src/mono/mono/mini/mini-llvm.c
+++ b/src/mono/mono/mini/mini-llvm.c
@@ -3818,9 +3818,11 @@ emit_gc_pin (EmitContext *ctx, LLVMBuilderRef builder, int vreg)
{
if (ctx->values [vreg] == LLVMConstNull (IntPtrType ()))
return;
+#if 0
MonoInst *var = get_vreg_to_inst (ctx->cfg, vreg);
if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT|MONO_INST_IS_DEAD))
return;
+#endif
LLVMValueRef index0 = const_int32 (0);
LLVMValueRef index1 = const_int32 (ctx->gc_var_indexes [vreg] - 1);
LLVMValueRef indexes [] = { index0, index1 };
@@ -3861,11 +3863,15 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
int ngc_vars = 0;
for (int i = 0; i < cfg->next_vreg; ++i) {
if (vreg_is_ref (cfg, i)) {
+ ctx->gc_var_indexes [i] = ngc_vars + 1;
+ ngc_vars ++;
+ /*
MonoInst *var = get_vreg_to_inst (ctx->cfg, i);
if (!(var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT|MONO_INST_IS_DEAD))) {
ctx->gc_var_indexes [i] = ngc_vars + 1;
ngc_vars ++;
}
+ */
}
}
@@ -4114,17 +4120,16 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder)
#ifdef TARGET_WASM
/*
+ * FIXME:
* Storing ref arguments to the pin area is not needed
* since it's done by the caller.
*/
- /*
for (int i = 0; i < cfg->num_varinfo; ++i) {
MonoInst *var = cfg->varinfo [i];
if (var->opcode == OP_ARG && vreg_is_ref (cfg, var->dreg) && ctx->values [var->dreg])
emit_gc_pin (ctx, builder, var->dreg);
}
- */
#endif
if (cfg->deopt) {
@@ -7700,11 +7705,11 @@ MONO_RESTORE_WARNING
break;
}
case OP_STOREX_MEMBASE: {
- LLVMTypeRef t = LLVMTypeOf (values [ins->sreg1]);
+ LLVMTypeRef t = LLVMTypeOf (lhs);
LLVMValueRef dest;
dest = convert (ctx, LLVMBuildAdd (builder, convert (ctx, values [ins->inst_destbasereg], IntPtrType ()), LLVMConstInt (IntPtrType (), ins->inst_offset, FALSE), ""), pointer_type (t));
- mono_llvm_build_aligned_store (builder, values [ins->sreg1], dest, FALSE, 1);
+ mono_llvm_build_aligned_store (builder, lhs, dest, FALSE, 1);
break;
}
case OP_XBINOP:
@@ -11294,7 +11299,8 @@ MONO_RESTORE_WARNING
if (!skip_volatile_store)
emit_volatile_store (ctx, ins->dreg);
#ifdef TARGET_WASM
- if (vreg_is_ref (cfg, ins->dreg) && ctx->values [ins->dreg] && ins->opcode != OP_MOVE)
+ //if (vreg_is_ref (cfg, ins->dreg) && ctx->values [ins->dreg] && ins->opcode != OP_MOVE)
+ if (vreg_is_ref (cfg, ins->dreg) && ctx->values [ins->dreg])
emit_gc_pin (ctx, builder, ins->dreg);
#endif
}
diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c
index 0af0c06b00a..ed4c268fb6a 100644
--- a/src/mono/mono/mini/simd-intrinsics.c
+++ b/src/mono/mono/mini/simd-intrinsics.c
@@ -775,7 +775,7 @@ emit_vector_create_elementwise (
return ins;
}
-#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
+#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_WASM)
static int
type_to_xinsert_op (MonoTypeEnum type)
@@ -4043,6 +4043,23 @@ arch_emit_simd_intrinsics (const char *class_ns, const char *class_name, MonoCom
cfg->uses_simd_intrinsics |= MONO_CFG_USES_SIMD_INTRINSICS;
return simd_inst;
}
+#elif TARGET_WASM
+static
+MonoInst*
+arch_emit_simd_intrinsics (const char *class_ns, const char *class_name, MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ if (!strcmp (class_ns, "System.Runtime.Intrinsics")) {
+ if (!strcmp (class_name, "Vector128"))
+ return emit_sri_vector (cfg, cmethod, fsig, args);
+ }
+
+ if (!strcmp (class_ns, "System.Runtime.Intrinsics")) {
+ if (!strcmp (class_name, "Vector128`1"))
+ return emit_vector64_vector128_t (cfg, cmethod, fsig, args);
+ }
+
+ return NULL;
+}
#else
static
MonoInst*
diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets
index 244cfb3120f..a1d524c993f 100644
--- a/src/mono/wasm/build/WasmApp.Native.targets
+++ b/src/mono/wasm/build/WasmApp.Native.targets
@@ -91,6 +91,7 @@
See https://github.com/dotnet/runtime/issues/53367 for the motivating issue
-->
<EmscriptenEnvVars Include="PYTHONUTF8=1" />
+ <EmscriptenEnvVars Include="EM_WORKAROUND_PYTHON_BUG_34780=1" />
</ItemGroup>
</Target>
@@ -200,6 +201,7 @@
<_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" />
<_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmExceptionHandling)' == 'false'" />
<_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmExceptionHandling)' == 'true'" />
+ <_EmccCommonFlags Include="-msimd128" Condition="'$(WasmSIMD)' == 'true'" />
<_EmccIncludePaths Include="$(_WasmIntermediateOutputPath.TrimEnd('\/'))" />
<_EmccIncludePaths Include="$(_WasmRuntimePackIncludeDir)mono-2.0" />
@@ -427,7 +429,7 @@
</ItemGroup>
<Message Text="Stripping symbols from dotnet.wasm ..." Importance="High" Condition="'$(WasmNativeStrip)' == 'true'" />
- <Exec Command='wasm-opt$(_ExeExt) --enable-exception-handling --strip-dwarf "$(_WasmIntermediateOutputPath)dotnet.wasm" -o "$(_WasmIntermediateOutputPath)dotnet.wasm"'
+ <Exec Command='wasm-opt$(_ExeExt) --enable-simd --enable-exception-handling --strip-dwarf "$(_WasmIntermediateOutputPath)dotnet.wasm" -o "$(_WasmIntermediateOutputPath)dotnet.wasm"'
Condition="'$(WasmNativeStrip)' == 'true'"
IgnoreStandardErrorWarningFormat="true"
EnvironmentVariables="@(EmscriptenEnvVars)" />
@@ -517,6 +519,7 @@
<MonoAOTCompilerDefaultAotArguments Include="static" />
<MonoAOTCompilerDefaultAotArguments Include="direct-icalls" />
<MonoAOTCompilerDefaultAotArguments Include="deterministic" />
+ <MonoAOTCompilerDefaultAotArguments Include="mattr=simd" Condition="'$(WasmSIMD)' == 'true'" />
<MonoAOTCompilerDefaultProcessArguments Include="--wasm-exceptions" Condition="'$(WasmExceptionHandling)' == 'true'" />
<AotProfilePath Include="$(WasmAotProfilePath)"/>
</ItemGroup>
diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets
index b491d4ec99c..1fe3c7cddb8 100644
--- a/src/mono/wasm/build/WasmApp.targets
+++ b/src/mono/wasm/build/WasmApp.targets
@@ -66,6 +66,7 @@
Defaults to false.
- $(WasmAotProfilePath) - Path to an AOT profile file.
- $(WasmExceptionHandling) - Enable support for the WASM Exception Handling feature.
+ - $(WasmSIMD) - Enable support for the WASM SIMD feature.
Public items:
- @(WasmExtraFilesToDeploy) - Files to copy to $(WasmAppDir).
@@ -86,6 +87,7 @@
<PropertyGroup>
<WasmDedup Condition="'$(WasmDedup)' == ''">false</WasmDedup>
<WasmExceptionHandling Condition="'$(WasmExceptionHandling)' == ''">false</WasmExceptionHandling>
+ <WasmSIMD Condition="'$(WasmSIMD)' == ''">false</WasmSIMD>
<!--<WasmStripAOTAssemblies Condition="'$(AOTMode)' == 'LLVMOnlyInterp'">false</WasmStripAOTAssemblies>-->
<!--<WasmStripAOTAssemblies Condition="'$(WasmStripAOTAssemblies)' == ''">$(RunAOTCompilation)</WasmStripAOTAssemblies>-->
diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
index 5b0e309563f..9fb4b8f04fe 100644
--- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
+++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
@@ -347,6 +347,7 @@ namespace Microsoft.WebAssembly.Diagnostics
public TypeInfo TypeInfo { get; }
public bool HasSequencePoints { get => !DebugInformation.SequencePointsBlob.IsNil; }
private ParameterInfo[] _parametersInfo;
+ public int KickOffMethod { get; }
public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader)
{
@@ -357,11 +358,15 @@ namespace Microsoft.WebAssembly.Diagnostics
this.Source = source;
this.Token = token;
this.methodDefHandle = methodDefHandle;
- this.Name = asmMetadataReader.GetString(methodDef.Name);
+ this.Name = assembly.EnCGetString(methodDef.Name);
this.pdbMetadataReader = pdbMetadataReader;
+ if (!DebugInformation.GetStateMachineKickoffMethod().IsNil)
+ this.KickOffMethod = asmMetadataReader.GetRowNumber(DebugInformation.GetStateMachineKickoffMethod());
+ else
+ this.KickOffMethod = -1;
this.IsEnCMethod = false;
this.TypeInfo = type;
- if (HasSequencePoints)
+ if (HasSequencePoints && source != null)
{
var sps = DebugInformation.GetSequencePoints();
SequencePoint start = sps.First();
@@ -398,7 +403,7 @@ namespace Microsoft.WebAssembly.Diagnostics
if (ctorHandle.Kind == HandleKind.MemberReference)
{
var container = asmMetadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent;
- var name = asmMetadataReader.GetString(asmMetadataReader.GetTypeReference((TypeReferenceHandle)container).Name);
+ var name = assembly.EnCGetString(asmMetadataReader.GetTypeReference((TypeReferenceHandle)container).Name);
switch (name)
{
case "DebuggerHiddenAttribute":
@@ -434,7 +439,7 @@ namespace Microsoft.WebAssembly.Diagnostics
for (int i = 0; i < paramsCnt; i++)
{
var parameter = Assembly.asmMetadataReader.GetParameter(paramsHandles[i]);
- var paramName = Assembly.asmMetadataReader.GetString(parameter.Name);
+ var paramName = Assembly.EnCGetString(parameter.Name);
var isOptional = parameter.Attributes.HasFlag(ParameterAttributes.Optional) && parameter.Attributes.HasFlag(ParameterAttributes.HasDefault);
if (!isOptional)
{
@@ -454,9 +459,9 @@ namespace Microsoft.WebAssembly.Diagnostics
return paramsInfo;
}
- public void UpdateEnC(MetadataReader asmMetadataReader, MetadataReader pdbMetadataReaderParm, int method_idx)
+ public void UpdateEnC(MetadataReader asmMetadataReader, MetadataReader pdbMetadataReaderParm, int methodIdx)
{
- this.DebugInformation = pdbMetadataReaderParm.GetMethodDebugInformation(MetadataTokens.MethodDebugInformationHandle(method_idx));
+ this.DebugInformation = pdbMetadataReaderParm.GetMethodDebugInformation(MetadataTokens.MethodDebugInformationHandle(methodIdx));
this.pdbMetadataReader = pdbMetadataReaderParm;
this.IsEnCMethod = true;
if (HasSequencePoints)
@@ -481,7 +486,7 @@ namespace Microsoft.WebAssembly.Diagnostics
StartLocation = new SourceLocation(this, start);
EndLocation = new SourceLocation(this, end);
}
- localScopes = pdbMetadataReader.GetLocalScopes(MetadataTokens.MethodDefinitionHandle(method_idx));
+ localScopes = pdbMetadataReader.GetLocalScopes(MetadataTokens.MethodDefinitionHandle(methodIdx));
}
public SourceLocation GetLocationByIl(int pos)
@@ -678,22 +683,21 @@ namespace Microsoft.WebAssembly.Diagnostics
public Dictionary<string, DebuggerBrowsableState?> DebuggerBrowsableFields = new();
public Dictionary<string, DebuggerBrowsableState?> DebuggerBrowsableProperties = new();
- public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type, ILogger logger)
+ public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type, MetadataReader metadataReader, ILogger logger)
{
this.logger = logger;
this.assembly = assembly;
- var metadataReader = assembly.asmMetadataReader;
Token = MetadataTokens.GetToken(metadataReader, typeHandle);
this.type = type;
methods = new List<MethodInfo>();
- Name = metadataReader.GetString(type.Name);
+ Name = assembly.EnCGetString(type.Name);
var declaringType = type;
while (declaringType.IsNested)
{
declaringType = metadataReader.GetTypeDefinition(declaringType.GetDeclaringType());
Name = metadataReader.GetString(declaringType.Name) + "." + Name;
}
- Namespace = metadataReader.GetString(declaringType.Namespace);
+ Namespace = assembly.EnCGetString(declaringType.Namespace);
if (Namespace.Length > 0)
FullName = Namespace + "." + Name;
else
@@ -704,7 +708,7 @@ namespace Microsoft.WebAssembly.Diagnostics
try
{
var fieldDefinition = metadataReader.GetFieldDefinition(field);
- var fieldName = metadataReader.GetString(fieldDefinition.Name);
+ var fieldName = assembly.EnCGetString(fieldDefinition.Name);
AppendToBrowsable(DebuggerBrowsableFields, fieldDefinition.GetCustomAttributes(), fieldName);
}
catch (Exception ex)
@@ -719,7 +723,7 @@ namespace Microsoft.WebAssembly.Diagnostics
try
{
var propDefinition = metadataReader.GetPropertyDefinition(prop);
- var propName = metadataReader.GetString(propDefinition.Name);
+ var propName = assembly.EnCGetString(propDefinition.Name);
AppendToBrowsable(DebuggerBrowsableProperties, propDefinition.GetCustomAttributes(), propName);
}
catch (Exception ex)
@@ -740,7 +744,7 @@ namespace Microsoft.WebAssembly.Diagnostics
continue;
var container = metadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent;
var valueBytes = metadataReader.GetBlobBytes(metadataReader.GetCustomAttribute(cattr).Value);
- var attributeName = metadataReader.GetString(metadataReader.GetTypeReference((TypeReferenceHandle)container).Name);
+ var attributeName = assembly.EnCGetString(metadataReader.GetTypeReference((TypeReferenceHandle)container).Name);
if (attributeName != "DebuggerBrowsableAttribute")
continue;
var state = (DebuggerBrowsableState)valueBytes[2];
@@ -783,14 +787,15 @@ namespace Microsoft.WebAssembly.Diagnostics
internal PEReader peReader;
internal MetadataReader asmMetadataReader { get; }
internal MetadataReader pdbMetadataReader { get; set; }
- internal List<MetadataReader> enCMetadataReader = new List<MetadataReader>();
+ internal List<Tuple<MetadataReader, MetadataReader>> enCMetadataReader = new List<Tuple<MetadataReader, MetadataReader>>();
private int debugId;
internal int PdbAge { get; }
internal System.Guid PdbGuid { get; }
internal string PdbName { get; }
internal bool PdbInformationAvailable { get; }
public bool TriedToLoadSymbolsOnDemand { get; set; }
- public MethodInfo EntryPoint { get; private set; }
+
+ private readonly Dictionary<int, SourceFile> _documentIdToSourceFileTable = new Dictionary<int, SourceFile>();
public unsafe AssemblyInfo(MonoProxy monoProxy, SessionId sessionId, string url, byte[] assembly, byte[] pdb, ILogger logger, CancellationToken token)
{
@@ -856,41 +861,128 @@ namespace Microsoft.WebAssembly.Diagnostics
MetadataReader asmMetadataReader = MetadataReaderProvider.FromMetadataStream(asmStream).GetMetadataReader();
var pdbStream = new MemoryStream(pdb);
MetadataReader pdbMetadataReader = MetadataReaderProvider.FromPortablePdbStream(pdbStream).GetMetadataReader();
- enCMetadataReader.Add(asmMetadataReader);
- enCMetadataReader.Add(pdbMetadataReader);
+ enCMetadataReader.Add(new (asmMetadataReader, pdbMetadataReader));
PopulateEnC(asmMetadataReader, pdbMetadataReader);
return true;
}
+ private static int GetTypeDefIdx(MetadataReader asmMetadataReaderParm, int number)
+ {
+ int i = 1;
+ foreach (var encMapHandle in asmMetadataReaderParm.GetEditAndContinueMapEntries())
+ {
+ if (encMapHandle.Kind == HandleKind.TypeDefinition)
+ {
+ if (asmMetadataReaderParm.GetRowNumber(encMapHandle) == number)
+ return i;
+ i++;
+ }
+ }
+ return -1;
+ }
- private void PopulateEnC(MetadataReader asmMetadataReaderParm, MetadataReader pdbMetadataReaderParm)
+ private static int GetMethodDebugInformationIdx(MetadataReader pdbMetadataReaderParm, int number)
{
int i = 1;
- foreach (EntityHandle encMapHandle in asmMetadataReaderParm.GetEditAndContinueMapEntries())
+ foreach (var encMapHandle in pdbMetadataReaderParm.GetEditAndContinueMapEntries())
{
if (encMapHandle.Kind == HandleKind.MethodDebugInformation)
{
- var method = methods[asmMetadataReader.GetRowNumber(encMapHandle)];
- method.UpdateEnC(asmMetadataReaderParm, pdbMetadataReaderParm, i);
+ if (pdbMetadataReaderParm.GetRowNumber(encMapHandle) == number)
+ return i;
i++;
}
}
+ return -1;
}
- private void Populate()
+ public string EnCGetString(StringHandle strHandle)
{
- var d2s = new Dictionary<int, SourceFile>();
+ var asmMetadataReaderLocal = asmMetadataReader;
+ var strIdx = strHandle.GetHashCode();
+ int i = 0;
+ while (strIdx > asmMetadataReaderLocal.GetHeapSize(HeapIndex.String))
+ {
+ strIdx -= asmMetadataReaderLocal.GetHeapSize(HeapIndex.String);
+ asmMetadataReaderLocal = enCMetadataReader[i].Item1;
+ i+=1;
+ }
+ return asmMetadataReaderLocal.GetString(MetadataTokens.StringHandle(strIdx));
+ }
- SourceFile FindSource(DocumentHandle doc, int rowid, string documentName)
+ private void PopulateEnC(MetadataReader asmMetadataReaderParm, MetadataReader pdbMetadataReaderParm)
+ {
+ TypeInfo typeInfo = null;
+ int methodIdxAsm = 1;
+ foreach (var entry in asmMetadataReaderParm.GetEditAndContinueLogEntries())
{
- if (d2s.TryGetValue(rowid, out SourceFile source))
- return source;
+ if (entry.Operation == EditAndContinueOperation.AddMethod ||
+ entry.Operation == EditAndContinueOperation.AddField)
+ {
+ var typeHandle = (TypeDefinitionHandle)entry.Handle;
+ if (!TypesByToken.TryGetValue(MetadataTokens.GetToken(asmMetadataReaderParm, typeHandle), out typeInfo))
+ {
+ int typeDefIdx = GetTypeDefIdx(asmMetadataReaderParm, asmMetadataReaderParm.GetRowNumber(entry.Handle));
+ var typeDefinition = asmMetadataReaderParm.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle(typeDefIdx));
+ StringHandle name = MetadataTokens.StringHandle(typeDefinition.Name.GetHashCode() & 127);
+ typeInfo = new TypeInfo(this, typeHandle, typeDefinition, asmMetadataReaderParm, logger);
+ TypesByName[typeInfo.FullName] = typeInfo;
+ TypesByToken[typeInfo.Token] = typeInfo;
+ }
+ }
+ else if (entry.Operation == EditAndContinueOperation.Default)
+ {
+ var entryRow = asmMetadataReader.GetRowNumber(entry.Handle);
+ if (entry.Handle.Kind == HandleKind.MethodDefinition)
+ {
+ var methodDefinition = asmMetadataReaderParm.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle(methodIdxAsm));
+ int methodIdx = GetMethodDebugInformationIdx(pdbMetadataReaderParm, entryRow);
+ if (methods.TryGetValue(entryRow, out MethodInfo method))
+ {
+ method.UpdateEnC(asmMetadataReaderParm, pdbMetadataReaderParm, methodIdx);
+ }
+ else if (typeInfo != null)
+ {
+ var methodDebugInformation = pdbMetadataReaderParm.GetMethodDebugInformation(MetadataTokens.MethodDebugInformationHandle(methodIdx));
+ SourceFile source = null;
+ if (!methodDebugInformation.Document.IsNil)
+ {
+ var document = pdbMetadataReaderParm.GetDocument(methodDebugInformation.Document);
+ var documentName = pdbMetadataReaderParm.GetString(document.Name);
+ source = GetOrAddSourceFile(methodDebugInformation.Document, asmMetadataReaderParm.GetRowNumber(methodDebugInformation.Document), documentName);
+ }
+ var methodInfo = new MethodInfo(this, MetadataTokens.MethodDefinitionHandle(methodIdxAsm), entryRow, source, typeInfo, asmMetadataReaderParm, pdbMetadataReaderParm);
+ methods[entryRow] = methodInfo;
- var src = new SourceFile(this, sources.Count, doc, GetSourceLinkUrl(documentName), documentName);
- sources.Add(src);
- d2s[rowid] = src;
- return src;
- };
+ if (source != null)
+ source.AddMethod(methodInfo);
+
+ typeInfo.Methods.Add(methodInfo);
+ }
+ methodIdxAsm++;
+ }
+ else if (entry.Handle.Kind == HandleKind.FieldDefinition)
+ {
+ //Implement new instance field when it's supported on runtime
+ }
+ }
+ else
+ {
+ logger.LogError($"Not supported EnC operation {entry.Operation}");
+ }
+ }
+ }
+ private SourceFile GetOrAddSourceFile(DocumentHandle doc, int rowid, string documentName)
+ {
+ if (_documentIdToSourceFileTable.TryGetValue(rowid, out SourceFile source))
+ return source;
+
+ var src = new SourceFile(this, _documentIdToSourceFileTable.Count, doc, GetSourceLinkUrl(documentName), documentName);
+ _documentIdToSourceFileTable[rowid] = src;
+ return src;
+ }
+ private void Populate()
+ {
foreach (DocumentHandle dh in asmMetadataReader.Documents)
{
asmMetadataReader.GetDocument(dh);
@@ -899,16 +991,11 @@ namespace Microsoft.WebAssembly.Diagnostics
if (pdbMetadataReader != null)
ProcessSourceLink();
- MethodDefinitionHandle entryPointHandle = default;
- if (asmMetadataReader.DebugMetadataHeader is not null)
- entryPointHandle = asmMetadataReader.DebugMetadataHeader.EntryPoint;
- if (pdbMetadataReader is not null && pdbMetadataReader.DebugMetadataHeader is not null)
- entryPointHandle = pdbMetadataReader.DebugMetadataHeader.EntryPoint;
foreach (TypeDefinitionHandle type in asmMetadataReader.TypeDefinitions)
{
var typeDefinition = asmMetadataReader.GetTypeDefinition(type);
- var typeInfo = new TypeInfo(this, type, typeDefinition, logger);
+ var typeInfo = new TypeInfo(this, type, typeDefinition, asmMetadataReader, logger);
TypesByName[typeInfo.FullName] = typeInfo;
TypesByToken[typeInfo.Token] = typeInfo;
if (pdbMetadataReader != null)
@@ -919,24 +1006,20 @@ namespace Microsoft.WebAssembly.Diagnostics
if (!method.ToDebugInformationHandle().IsNil)
{
var methodDebugInformation = pdbMetadataReader.GetMethodDebugInformation(method.ToDebugInformationHandle());
+ SourceFile source = null;
if (!methodDebugInformation.Document.IsNil)
{
var document = pdbMetadataReader.GetDocument(methodDebugInformation.Document);
var documentName = pdbMetadataReader.GetString(document.Name);
- SourceFile source = FindSource(methodDebugInformation.Document, asmMetadataReader.GetRowNumber(methodDebugInformation.Document), documentName);
- var methodInfo = new MethodInfo(this, method, asmMetadataReader.GetRowNumber(method), source, typeInfo, asmMetadataReader, pdbMetadataReader);
- methods[asmMetadataReader.GetRowNumber(method)] = methodInfo;
-
- if (source != null)
- source.AddMethod(methodInfo);
+ source = GetOrAddSourceFile(methodDebugInformation.Document, asmMetadataReader.GetRowNumber(methodDebugInformation.Document), documentName);
+ }
+ var methodInfo = new MethodInfo(this, method, asmMetadataReader.GetRowNumber(method), source, typeInfo, asmMetadataReader, pdbMetadataReader);
+ methods[asmMetadataReader.GetRowNumber(method)] = methodInfo;
- typeInfo.Methods.Add(methodInfo);
- if (entryPointHandle.IsNil || EntryPoint is not null)
- continue;
+ if (source != null)
+ source.AddMethod(methodInfo);
- if (method.Equals(entryPointHandle))
- EntryPoint = methodInfo;
- }
+ typeInfo.Methods.Add(methodInfo);
}
}
}
@@ -989,7 +1072,7 @@ namespace Microsoft.WebAssembly.Diagnostics
return null;
}
- public IEnumerable<SourceFile> Sources => this.sources;
+ public IEnumerable<SourceFile> Sources => this._documentIdToSourceFileTable.Values;
public Dictionary<int, MethodInfo> Methods => this.methods;
public Dictionary<string, TypeInfo> TypesByName { get; } = new();
@@ -1239,10 +1322,14 @@ namespace Microsoft.WebAssembly.Diagnostics
public string Url { get; set; }
public Task<byte[][]> Data { get; set; }
}
-
public static IEnumerable<MethodInfo> EnC(AssemblyInfo asm, byte[] meta_data, byte[] pdb_data)
{
asm.EnC(meta_data, pdb_data);
+ return GetEnCMethods(asm);
+ }
+
+ public static IEnumerable<MethodInfo> GetEnCMethods(AssemblyInfo asm)
+ {
foreach (var method in asm.Methods)
{
if (method.Value.IsEnCMethod)
@@ -1344,12 +1431,6 @@ namespace Microsoft.WebAssembly.Diagnostics
public SourceFile GetFileById(SourceId id) => AllSources().SingleOrDefault(f => f.SourceId.Equals(id));
public AssemblyInfo GetAssemblyByName(string name) => assemblies.FirstOrDefault(a => a.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
- public MethodInfo FindEntryPoint(string preferredEntrypointAssembly)
- {
- AssemblyInfo foundAsm = assemblies.FirstOrDefault(asm => asm.EntryPoint?.Assembly.Name == preferredEntrypointAssembly);
- foundAsm ??= assemblies.FirstOrDefault(asm => asm.EntryPoint is not null);
- return foundAsm?.EntryPoint;
- }
/*
V8 uses zero based indexing for both line and column.
diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
index 483b33025ef..5f2ecaa1996 100644
--- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
+++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
@@ -213,6 +213,12 @@ namespace Microsoft.WebAssembly.Diagnostics
string top_func = args?["callFrames"]?[0]?["functionName"]?.Value<string>();
switch (top_func) {
// keep function names un-mangled via src\mono\wasm\runtime\rollup.config.js
+ case "mono_wasm_set_entrypoint_breakpoint":
+ case "_mono_wasm_set_entrypoint_breakpoint":
+ {
+ await OnSetEntrypointBreakpoint(sessionId, args, token);
+ return true;
+ }
case "mono_wasm_runtime_ready":
case "_mono_wasm_runtime_ready":
{
@@ -638,7 +644,7 @@ namespace Microsoft.WebAssembly.Diagnostics
}
MethodInfo methodInfo = type.Methods.FirstOrDefault(m => m.Name == methodName);
- if (methodInfo == null)
+ if (methodInfo?.Source is null)
{
// Maybe this is an async method, in which case the debug info is attached
// to the async method implementation, in class named:
@@ -1306,6 +1312,72 @@ namespace Microsoft.WebAssembly.Diagnostics
}
}
+ private async Task OnSetEntrypointBreakpoint(SessionId sessionId, JObject args, CancellationToken token)
+ {
+ try
+ {
+ ExecutionContext context = GetContext(sessionId);
+
+ var argsNew = JObject.FromObject(new
+ {
+ callFrameId = args?["callFrames"]?[0]?["callFrameId"]?.Value<string>(),
+ expression = "assembly_name_str + '|' + entrypoint_method_token",
+ });
+ Result assemblyAndMethodToken = await SendCommand(sessionId, "Debugger.evaluateOnCallFrame", argsNew, token);
+ if (!assemblyAndMethodToken.IsOk)
+ {
+ logger.LogDebug("Failure evaluating assembly_name_str + '|' + entrypoint_method_token");
+ return;
+ }
+ logger.LogDebug($"Entrypoint assembly and method token {assemblyAndMethodToken.Value["result"]["value"].Value<string>()}");
+
+ var assemblyAndMethodTokenArr = assemblyAndMethodToken.Value["result"]["value"].Value<string>().Split('|', StringSplitOptions.TrimEntries);
+ var assemblyName = assemblyAndMethodTokenArr[0];
+ var methodToken = Convert.ToInt32(assemblyAndMethodTokenArr[1]) & 0xffffff; //token
+
+ var store = await LoadStore(sessionId, token);
+ AssemblyInfo assembly = store.GetAssemblyByName(assemblyName);
+ if (assembly == null)
+ {
+ logger.LogDebug($"Could not find entrypoint assembly {assemblyName} in the store");
+ return;
+ }
+ var method = assembly.GetMethodByToken(methodToken);
+ if (method.StartLocation == null) //It's an async method and we need to get the MoveNext method to add the breakpoint
+ method = assembly.Methods.FirstOrDefault(m => m.Value.KickOffMethod == methodToken).Value;
+ if (method == null)
+ {
+ logger.LogDebug($"Could not find entrypoint method {methodToken} in assembly {assemblyName}");
+ return;
+ }
+ var sourceFile = assembly.Sources.FirstOrDefault(sf => sf.SourceId == method.SourceId);
+ if (sourceFile == null)
+ {
+ logger.LogDebug($"Could not source file {method.SourceName} for method {method.Name} in assembly {assemblyName}");
+ return;
+ }
+ string bpId = $"auto:{method.StartLocation.Line}:{method.StartLocation.Column}:{sourceFile.DotNetUrl}";
+ BreakpointRequest request = new(bpId, JObject.FromObject(new
+ {
+ lineNumber = method.StartLocation.Line,
+ columnNumber = method.StartLocation.Column,
+ url = sourceFile.Url
+ }));
+ context.BreakpointRequests[bpId] = request;
+ if (request.TryResolve(sourceFile))
+ await SetBreakpoint(sessionId, context.store, request, sendResolvedEvent: false, fromEnC: false, token);
+ logger.LogInformation($"Adding bp req {request}");
+ }
+ catch (Exception e)
+ {
+ logger.LogDebug($"Unable to set entrypoint breakpoint. {e}");
+ }
+ finally
+ {
+ await SendResume(sessionId, token);
+ }
+ }
+
private async Task<bool> OnEvaluateOnCallFrame(MessageId msg_id, int scopeId, string expression, CancellationToken token)
{
try
@@ -1441,31 +1513,6 @@ namespace Microsoft.WebAssembly.Diagnostics
{
await OnSourceFileAdded(sessionId, source, context, token);
}
-
- if (_options?.AutoSetBreakpointOnEntryPoint == true)
- {
- MethodInfo entryPoint = context.store.FindEntryPoint(_options!.EntrypointAssembly);
- if (entryPoint is not null)
- {
- var sourceFile = entryPoint.Assembly.Sources.Single(sf => sf.SourceId == entryPoint.SourceId);
- string bpId = $"auto:{entryPoint.StartLocation.Line}:{entryPoint.StartLocation.Column}:{sourceFile.DotNetUrl}";
- BreakpointRequest request = new(bpId, JObject.FromObject(new
- {
- lineNumber = entryPoint.StartLocation.Line,
- columnNumber = entryPoint.StartLocation.Column,
- url = sourceFile.Url
- }));
- logger.LogInformation($"Adding bp req {request}");
- context.BreakpointRequests[bpId] = request;
- request.TryResolve(sourceFile);
- if (request.TryResolve(sourceFile))
- await SetBreakpoint(sessionId, context.store, request, true, true, token);
- }
- else
- {
- logger.LogWarning($"No entrypoint found for setting automatic breakpoint");
- }
- }
}
}
catch (Exception e)
diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ProxyOptions.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ProxyOptions.cs
index c853faf4821..cf7f4318604 100644
--- a/src/mono/wasm/debugger/BrowserDebugProxy/ProxyOptions.cs
+++ b/src/mono/wasm/debugger/BrowserDebugProxy/ProxyOptions.cs
@@ -27,7 +27,5 @@ public class ProxyOptions
}
}
public string? LogPath { get; set; }
- public bool AutoSetBreakpointOnEntryPoint { get; set; }
- public string? EntrypointAssembly { get; set; }
public bool RunningForBlazor { get; set; }
}
diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
index 57ca89891b9..1e5fd0b4c07 100644
--- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
+++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
@@ -582,17 +582,21 @@ namespace DebuggerTests
}
[ConditionalTheory(nameof(RunningOnChrome))]
- [InlineData(false, "RunStepThrough", 847, 8)]
- [InlineData(true, "RunStepThrough", 847, 8)]
- [InlineData(false, "RunNonUserCode", 852, 4, "NonUserCodeBp")]
- [InlineData(true, "RunNonUserCode", 867, 8)]
- [InlineData(false, "RunStepThroughWithNonUserCode", 933, 8)]
- [InlineData(true, "RunStepThroughWithNonUserCode", 933, 8)]
- public async Task StepThroughOrNonUserCodeAttributeStepInNoBp(bool justMyCodeEnabled, string evalFunName, int line, int col, string funcName="")
+ [InlineData(false, "RunStepThrough", "DebuggerAttribute", 1, 847, 8)]
+ [InlineData(true, "RunStepThrough", "DebuggerAttribute", 1, 847, 8)]
+ [InlineData(false, "RunNonUserCode", "DebuggerAttribute", 1, 852, 4, "NonUserCodeBp")]
+ [InlineData(true, "RunNonUserCode", "DebuggerAttribute", 1, 867, 8)]
+ [InlineData(false, "RunStepThroughWithNonUserCode", "DebuggerAttribute", 1, 933, 8)]
+ [InlineData(true, "RunStepThroughWithNonUserCode", "DebuggerAttribute", 1, 933, 8)]
+ [InlineData(false, "EvaluateStepThroughAttr", "DefaultInterfaceMethod", 2, 1091, 4)]
+ [InlineData(true, "EvaluateStepThroughAttr", "DefaultInterfaceMethod", 2, 1091, 4)]
+ [InlineData(false, "EvaluateNonUserCodeAttr", "DefaultInterfaceMethod", 2, 1048, 4, "NonUserCodeDefaultMethod")]
+ [InlineData(true, "EvaluateNonUserCodeAttr", "DefaultInterfaceMethod", 2, 1097, 4)]
+ public async Task StepThroughOrNonUserCodeAttributeStepInNoBp(bool justMyCodeEnabled, string evalFunName, string evalClassName, int bpLine, int line, int col, string funcName="")
{
- var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", evalFunName, 1);
+ var bp_init = await SetBreakpointInMethod("debugger-test.dll", evalClassName, evalFunName, bpLine);
var init_location = await EvaluateAndCheck(
- $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DebuggerAttribute:{evalFunName}'); }}, 1);",
+ $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] {evalClassName}:{evalFunName}'); }}, 1);",
"dotnet://debugger-test.dll/debugger-test.cs",
bp_init.Value["locations"][0]["lineNumber"].Value<int>(),
bp_init.Value["locations"][0]["columnNumber"].Value<int>(),
@@ -708,38 +712,42 @@ namespace DebuggerTests
}
[ConditionalTheory(nameof(RunningOnChrome))]
- [InlineData("Debugger.stepInto", 1, 2, false)]
- [InlineData("Debugger.stepInto", 1, 2, true)]
- [InlineData("Debugger.resume", 1, 2, true)]
- [InlineData("Debugger.stepInto", 2, 3, false)]
- [InlineData("Debugger.resume", 2, 3, false)]
- public async Task StepperBoundary(string debuggingAction, int lineBpInit, int lineBpFinal, bool hasBpInDecoratedFun)
+ [InlineData("DebuggerAttribute", "RunNoBoundary", "DebuggerAttribute", "Debugger.stepInto", 1, 2, false)]
+ [InlineData("DebuggerAttribute", "RunNoBoundary", "DebuggerAttribute", "Debugger.stepInto", 1, 2, true)]
+ [InlineData("DebuggerAttribute", "RunNoBoundary", "DebuggerAttribute", "Debugger.resume", 1, 2, true)]
+ [InlineData("DebuggerAttribute", "RunNoBoundary", "DebuggerAttribute", "Debugger.stepInto", 2, 3, false, true)]
+ [InlineData("DebuggerAttribute", "RunNoBoundary", "DebuggerAttribute", "Debugger.resume", 2, 3, false, true)]
+ [InlineData("DefaultInterfaceMethod", "EvaluateStepperBoundaryAttr", "IExtendIDefaultInterface", "Debugger.stepInto", 2, 3, false)]
+ [InlineData("DefaultInterfaceMethod", "EvaluateStepperBoundaryAttr", "IExtendIDefaultInterface", "Debugger.stepInto", 2, 3, true)]
+ [InlineData("DefaultInterfaceMethod", "EvaluateStepperBoundaryAttr", "IExtendIDefaultInterface", "Debugger.resume", 2, 3, true)]
+ public async Task StepperBoundary(
+ string className, string evalFunName, string decoratedMethodClassName, string debuggingAction, int lineBpInit, int lineBpFinal, bool hasBpInDecoratedFun, bool isTestingUserBp = false)
{
// behavior of StepperBoundary is the same for JMC enabled and disabled
// but the effect of NonUserCode escape is better visible for JMC: enabled
await SetJustMyCode(true);
- var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunNoBoundary", lineBpInit);
+ var bp_init = await SetBreakpointInMethod("debugger-test.dll", className, evalFunName, lineBpInit);
var init_location = await EvaluateAndCheck(
- $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DebuggerAttribute:RunNoBoundary'); }}, {lineBpInit});",
+ $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] {className}:{evalFunName}'); }}, {lineBpInit});",
"dotnet://debugger-test.dll/debugger-test.cs",
bp_init.Value["locations"][0]["lineNumber"].Value<int>(),
bp_init.Value["locations"][0]["columnNumber"].Value<int>(),
- "RunNoBoundary"
+ evalFunName
);
- var bp_final = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunNoBoundary", lineBpFinal);
+ var bp_final = await SetBreakpointInMethod("debugger-test.dll", className, evalFunName, lineBpFinal);
if (hasBpInDecoratedFun)
{
- var bp_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "BoundaryBp", 2);
+ var bp_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", decoratedMethodClassName, "BoundaryBp", 2);
var line_decorated_fun = bp_decorated_fun.Value["locations"][0]["lineNumber"].Value<int>();
var col_decorated_fun = bp_decorated_fun.Value["locations"][0]["columnNumber"].Value<int>();
await SendCommandAndCheck(null, debuggingAction, "dotnet://debugger-test.dll/debugger-test.cs", line_decorated_fun, col_decorated_fun, "BoundaryBp");
}
- if (lineBpInit == 2)
+ if (isTestingUserBp)
await SendCommandAndCheck(null, debuggingAction, "dotnet://debugger-test.dll/debugger-test.cs", 879, 8, "BoundaryUserBp");
var line = bp_final.Value["locations"][0]["lineNumber"].Value<int>();
var col = bp_final.Value["locations"][0]["columnNumber"].Value<int>();
- await SendCommandAndCheck(null, debuggingAction, "dotnet://debugger-test.dll/debugger-test.cs", line, col, "RunNoBoundary");
+ await SendCommandAndCheck(null, debuggingAction, "dotnet://debugger-test.dll/debugger-test.cs", line, col, evalFunName);
}
[ConditionalFact(nameof(RunningOnChrome))]
@@ -811,5 +819,82 @@ namespace DebuggerTests
}
);
}
+
+ [ConditionalTheory(nameof(RunningOnChrome))]
+ [InlineData("IDefaultInterface", "DefaultMethod", "Evaluate", 1070, 1001, 999, 1003)]
+ [InlineData("IExtendIDefaultInterface", "IDefaultInterface.DefaultMethodToOverride", "Evaluate", 1071, 1030, 1028, 1032)]
+ [InlineData("IDefaultInterface", "DefaultMethodAsync", "EvaluateAsync", 37, 1014, 1012, 1016, true, "Start<IDefaultInterface/<DefaultMethodAsync>d__2>")]
+ public async Task BreakInDefaultInterfaceMethod(
+ string dimClassName, string dimName, string entryMethod, int evaluateAsPrevFrameLine, int dimAsPrevFrameLine, int functionLocationLine, int functionEndLine, bool isAsync = false, string asyncPrevFrameInDim = "")
+ {
+ string assembly = "dotnet://debugger-test.dll/debugger-test.cs";
+ var bpDim = await SetBreakpointInMethod("debugger-test.dll", dimClassName, dimName, 1);
+ var pauseInDim = await EvaluateAndCheck(
+ $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DefaultInterfaceMethod:{entryMethod}'); }}, 1);",
+ assembly,
+ bpDim.Value["locations"][0]["lineNumber"].Value<int>(),
+ bpDim.Value["locations"][0]["columnNumber"].Value<int>(),
+ isAsync ? "MoveNext" : dimName,
+ wait_for_event_fn: async (pause_location) => { await CheckDefaultMethod(pause_location, isAsync ? "MoveNext" : dimName); }
+ );
+
+ // check prev frame in DIM
+ string prevFrameInDim = isAsync ? asyncPrevFrameInDim : entryMethod;
+ Assert.Equal(pauseInDim["callFrames"][1]["functionName"].Value<string>(), prevFrameInDim);
+ Assert.Equal(pauseInDim["callFrames"][1]["location"]["lineNumber"].Value<int>(), evaluateAsPrevFrameLine);
+
+ string funCalledFromDim = "MethodForCallingFromDIM";
+ var bpFunCalledFromDim = await SetBreakpointInMethod("debugger-test.dll", "DefaultInterfaceMethod", funCalledFromDim, 1);
+
+ // check prev frame in method called from DIM
+ var pauseInFunCalledFromDim = await SendCommandAndCheck(null, "Debugger.resume",
+ null,
+ bpFunCalledFromDim.Value["locations"][0]["lineNumber"].Value<int>(),
+ bpFunCalledFromDim.Value["locations"][0]["columnNumber"].Value<int>(),
+ funCalledFromDim);
+
+ string prevFrameFromDim = isAsync ? "MoveNext" : dimName;
+ Assert.Equal(pauseInFunCalledFromDim["callFrames"][1]["functionName"].Value<string>(), prevFrameFromDim);
+ Assert.Equal(pauseInFunCalledFromDim["callFrames"][1]["location"]["lineNumber"].Value<int>(), dimAsPrevFrameLine);
+
+
+ async Task CheckDefaultMethod(JObject pause_location, string methodName)
+ {
+ Assert.Equal("other", pause_location["reason"]?.Value<string>());
+ Assert.Equal(bpDim.Value["breakpointId"]?.ToString(), pause_location["hitBreakpoints"]?[0]?.Value<string>());
+
+ var top_frame = pause_location["callFrames"][0];
+ Assert.Equal(methodName, top_frame["functionName"].Value<string>());
+ Assert.Contains("debugger-test.cs", top_frame["url"].Value<string>());
+
+ CheckLocation(assembly, functionLocationLine, 4, scripts, top_frame["functionLocation"]);
+
+ var scope = top_frame["scopeChain"][0];
+ Assert.Equal("local", scope["type"]);
+ Assert.Equal(methodName, scope["name"]);
+
+ Assert.Equal("object", scope["object"]["type"]);
+ CheckLocation(assembly, functionLocationLine, 4, scripts, scope["startLocation"]);
+ CheckLocation(assembly, functionEndLine, 4, scripts, scope["endLocation"]);
+ await Task.CompletedTask;
+ }
+ }
+
+ [Fact]
+ public async Task CheckDefaultInterfaceMethodHiddenAttribute()
+ {
+ string methodName = "EvaluateHiddenAttr";
+ string assembly = "dotnet://debugger-test.dll/debugger-test.cs";
+ var hidden_bp = await SetBreakpointInMethod("debugger-test.dll", "IExtendIDefaultInterface", "HiddenDefaultMethod", 1);
+ var final_bp = await SetBreakpointInMethod("debugger-test.dll", "DefaultInterfaceMethod", methodName, 3);
+ // check if bp in hidden DIM was ignored:
+ var final_location = await EvaluateAndCheck(
+ $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DefaultInterfaceMethod:{methodName}'); }}, 1);",
+ assembly,
+ final_bp.Value["locations"][0]["lineNumber"].Value<int>(),
+ final_bp.Value["locations"][0]["columnNumber"].Value<int>(),
+ methodName
+ );
+ }
}
}
diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs
index 76cc33929ad..2fb50a9b020 100644
--- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs
+++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs
@@ -1220,5 +1220,22 @@ namespace DebuggerTests
expected_props = new [] { TString("S"), TString("T"), TString("R") };
await CheckProps(props, expected_props, "props#2");
});
+
+ [Theory]
+ [InlineData("DefaultMethod", "IDefaultInterface", "Evaluate")]
+ [InlineData("DefaultMethod2", "IExtendIDefaultInterface", "Evaluate")]
+ [InlineData("DefaultMethodAsync", "IDefaultInterface", "EvaluateAsync", true)]
+ public async Task EvaluateLocalsInDefaultInterfaceMethod(string pauseMethod, string methodInterface, string entryMethod, bool isAsync = false) =>
+ await CheckInspectLocalsAtBreakpointSite(
+ methodInterface, pauseMethod, 2, isAsync ? "MoveNext" : pauseMethod,
+ $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DefaultInterfaceMethod:{entryMethod}'); }})",
+ wait_for_event_fn: async (pause_location) =>
+ {
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ await EvaluateOnCallFrameAndCheck(id,
+ ("localString", TString($"{pauseMethod}()")),
+ ("this", TObject("DIMClass")),
+ ("this.dimClassMember", TNumber(123)));
+ });
}
}
diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs
index 5a241c9ae07..37dc79dddcb 100644
--- a/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs
+++ b/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs
@@ -409,5 +409,121 @@ namespace DebuggerTests
AssertEqual("StaticMethod1", top_frame?["functionName"]?.Value<string>(), top_frame?.ToString());
CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 48, 12, scripts, top_frame["location"]);
}
+
+ [ConditionalFact(nameof(RunningOnChrome))]
+ public async Task DebugHotReloadMethod_AddingNewMethod()
+ {
+ string asm_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll");
+ string pdb_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb");
+ string asm_file_hot_reload = Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll");
+
+ var bp_notchanged = await SetBreakpoint(".*/MethodBody1.cs$", 55, 12, use_regex: true);
+ var bp_invalid = await SetBreakpoint(".*/MethodBody1.cs$", 59, 12, use_regex: true);
+
+ var pause_location = await LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges(
+ asm_file, pdb_file, "MethodBody6", "StaticMethod1");
+
+ CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 55, 12, scripts, pause_location["callFrames"]?[0]["location"]);
+ //apply first update
+ pause_location = await LoadAssemblyAndTestHotReloadUsingSDB(
+ asm_file_hot_reload, "MethodBody6", "NewMethodStatic", 1);
+
+ JToken top_frame = pause_location["callFrames"]?[0];
+ AssertEqual("NewMethodStatic", top_frame?["functionName"]?.Value<string>(), top_frame?.ToString());
+ CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 59, 12, scripts, top_frame["location"]);
+ await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 60, 12, "NewMethodStatic",
+ locals_fn: async (locals) =>
+ {
+ CheckNumber(locals, "i", 20);
+ await Task.CompletedTask;
+ }
+ );
+ }
+
+ [ConditionalFact(nameof(RunningOnChrome))]
+ public async Task DebugHotReloadMethod_AddingNewStaticField()
+ {
+ string asm_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll");
+ string pdb_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb");
+ string asm_file_hot_reload = Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll");
+
+ var bp_notchanged = await SetBreakpoint(".*/MethodBody1.cs$", 55, 12, use_regex: true);
+ var bp_invalid = await SetBreakpoint(".*/MethodBody1.cs$", 59, 12, use_regex: true);
+
+ var pause_location = await LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges(
+ asm_file, pdb_file, "MethodBody6", "StaticMethod1");
+
+ CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 55, 12, scripts, pause_location["callFrames"]?[0]["location"]);
+ //apply first update
+ pause_location = await LoadAssemblyAndTestHotReloadUsingSDB(
+ asm_file_hot_reload, "MethodBody6", "NewMethodStatic", 1);
+
+ JToken top_frame = pause_location["callFrames"]?[0];
+ AssertEqual("NewMethodStatic", top_frame?["functionName"]?.Value<string>(), top_frame?.ToString());
+ CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 59, 12, scripts, top_frame["location"]);
+
+ await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 61, 12, "NewMethodStatic",
+ locals_fn: async (locals) =>
+ {
+ CheckNumber(locals, "i", 20);
+ await Task.CompletedTask;
+ }, times: 2
+ );
+ await EvaluateOnCallFrameAndCheck(top_frame["callFrameId"].Value<string>(),
+ ("ApplyUpdateReferencedAssembly.MethodBody6.newStaticField", TNumber(10)));
+
+ }
+
+ [ConditionalFact(nameof(RunningOnChrome))]
+ public async Task DebugHotReloadMethod_AddingNewClass()
+ {
+ string asm_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll");
+ string pdb_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb");
+ string asm_file_hot_reload = Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll");
+
+ var bp_notchanged = await SetBreakpoint(".*/MethodBody1.cs$", 55, 12, use_regex: true);
+ var bp_invalid = await SetBreakpoint(".*/MethodBody1.cs$", 73, 12, use_regex: true);
+ var bp_invalid1 = await SetBreakpoint(".*/MethodBody1.cs$", 83, 12, use_regex: true);
+ var bp_invalid2 = await SetBreakpoint(".*/MethodBody1.cs$", 102, 12, use_regex: true);
+
+ var pause_location = await LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges(
+ asm_file, pdb_file, "MethodBody6", "StaticMethod1");
+
+ CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 55, 12, scripts, pause_location["callFrames"]?[0]["location"]);
+ //apply first update
+ pause_location = await LoadAssemblyAndTestHotReloadUsingSDB(
+ asm_file_hot_reload, "MethodBody7", "StaticMethod1", 1);
+
+ JToken top_frame = pause_location["callFrames"]?[0];
+ AssertEqual("StaticMethod1", top_frame?["functionName"]?.Value<string>(), top_frame?.ToString());
+ CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 73, 12, scripts, top_frame["location"]);
+
+ pause_location = await StepAndCheck(StepKind.Resume, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 83, 12, "InstanceMethod",
+ locals_fn: async (locals) =>
+ {
+ CheckNumber(locals, "aLocal", 50);
+ await Task.CompletedTask;
+ }
+ );
+
+ var props = await GetObjectOnFrame(pause_location["callFrames"][0], "this");
+ Assert.Equal(3, props.Count());
+ CheckNumber(props, "attr1", 15);
+ await CheckString(props, "attr2", "20");
+
+ await EvaluateOnCallFrameAndCheck(pause_location["callFrames"]?[0]["callFrameId"].Value<string>(),
+ ("ApplyUpdateReferencedAssembly.MethodBody7.staticField", TNumber(80)));
+
+ //apply second update
+ pause_location = await LoadAssemblyAndTestHotReloadUsingSDB(
+ asm_file_hot_reload, "MethodBody8", "StaticMethod1", 2);
+
+ top_frame = pause_location["callFrames"]?[0];
+ AssertEqual("InstanceMethod", top_frame?["functionName"]?.Value<string>(), top_frame?.ToString());
+ CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 102, 12, scripts, top_frame["location"]);
+
+ await EvaluateOnCallFrameAndCheck(pause_location["callFrames"]?[0]["callFrameId"].Value<string>(),
+ ("ApplyUpdateReferencedAssembly.MethodBody8.staticField", TNumber(80)));
+ }
}
}
diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs
index 9c4e99a8364..3abc1d4b538 100644
--- a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs
+++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1.cs
@@ -50,4 +50,11 @@ namespace ApplyUpdateReferencedAssembly
Console.WriteLine("original");
}
}
+
+ public class MethodBody6 {
+ public static void StaticMethod1 () {
+ Console.WriteLine("breakpoint in a line that will not be changed");
+ Console.WriteLine("original");
+ }
+ }
}
diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs
index bb8d82ac56d..cef3214d9c8 100644
--- a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs
+++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v1.cs
@@ -51,4 +51,37 @@ namespace ApplyUpdateReferencedAssembly
Console.WriteLine("original");
}
}
+ public class MethodBody6 {
+ public static void StaticMethod1 () {
+ Console.WriteLine("breakpoint in a line that will not be changed");
+ Console.WriteLine("original");
+ }
+ public static void NewMethodStatic () {
+ int i = 20;
+ newStaticField = 10;
+ Console.WriteLine($"add a breakpoint in the new static method, look at locals {newStaticField}");
+ /*var newvar = new MethodBody6();
+ newvar.NewMethodInstance (10);*/
+ }
+ public static int newStaticField;
+ }
+
+ public class MethodBody7 {
+ public static int staticField;
+ int attr1;
+ string attr2;
+ public static void StaticMethod1 () {
+ Console.WriteLine("breakpoint in a method in a new class");
+ Console.WriteLine("original");
+ MethodBody7 newvar = new MethodBody7();
+ staticField = 80;
+ newvar.InstanceMethod();
+ }
+ public void InstanceMethod () {
+ int aLocal = 50;
+ attr1 = 15;
+ attr2 = "20";
+ Console.WriteLine($"add a breakpoint the instance method of the new class");
+ }
+ }
}
diff --git a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs
index 8850f85956d..48c3b9911e8 100644
--- a/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs
+++ b/src/mono/wasm/debugger/tests/ApplyUpdateReferencedAssembly/MethodBody1_v2.cs
@@ -50,4 +50,57 @@ namespace ApplyUpdateReferencedAssembly
Console.WriteLine("original");
}
}
+
+ public class MethodBody6 {
+ public static void StaticMethod1 () {
+ Console.WriteLine("breakpoint in a line that will not be changed");
+ Console.WriteLine("original");
+ }
+ public static void NewMethodStatic () {
+ int i = 20;
+ newStaticField = 10;
+ Console.WriteLine($"add a breakpoint in the new static method, look at locals {newStaticField}");
+ /*var newvar = new MethodBody6();
+ newvar.NewMethodInstance (10);*/
+ }
+ public static int newStaticField;
+ }
+
+ public class MethodBody7 {
+ public static int staticField;
+ int attr1;
+ string attr2;
+ public static void StaticMethod1 () {
+ Console.WriteLine("breakpoint in a method in a new class");
+ Console.WriteLine("original");
+ MethodBody7 newvar = new MethodBody7();
+ staticField = 80;
+ newvar.InstanceMethod();
+ }
+ public void InstanceMethod () {
+ int aLocal = 50;
+ attr1 = 15;
+ attr2 = "20";
+ Console.WriteLine($"add a breakpoint the instance method of the new class");
+ }
+ }
+
+ public class MethodBody8 {
+ public static int staticField;
+ int attr1;
+ string attr2;
+ public static void StaticMethod1 () {
+ Console.WriteLine("breakpoint in a method in a new class");
+ Console.WriteLine("original");
+ MethodBody8 newvar = new MethodBody8();
+ staticField = 80;
+ newvar.InstanceMethod();
+ }
+ public void InstanceMethod () {
+ int aLocal = 50;
+ attr1 = 15;
+ attr2 = "20";
+ Console.WriteLine($"add a breakpoint the instance method of the new class");
+ }
+ }
}
diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs
index cf2d5466c94..1700ac8d846 100644
--- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs
+++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs
@@ -992,3 +992,120 @@ public class TestHotReloadUsingSDB {
myMethod.Invoke(null, null);
}
}
+
+#region Default Interface Method
+public interface IDefaultInterface
+{
+ string DefaultMethod()
+ {
+ string localString = "DefaultMethod()";
+ DefaultInterfaceMethod.MethodForCallingFromDIM();
+ return $"{localString} from IDefaultInterface";
+ }
+
+ int DefaultMethodToOverride()
+ {
+ int retValue = 10;
+ return retValue;
+ }
+
+ async System.Threading.Tasks.Task DefaultMethodAsync()
+ {
+ string localString = "DefaultMethodAsync()";
+ DefaultInterfaceMethod.MethodForCallingFromDIM();
+ await System.Threading.Tasks.Task.FromResult(0);
+ }
+}
+
+public interface IExtendIDefaultInterface : IDefaultInterface
+{
+ void DefaultMethod2(out string t)
+ {
+ string localString = "DefaultMethod2()";
+ t = $"{localString} from IExtendIDefaultInterface";
+ }
+
+ int IDefaultInterface.DefaultMethodToOverride()
+ {
+ int retValue = 110;
+ DefaultInterfaceMethod.MethodForCallingFromDIM();
+ return retValue;
+ }
+
+ [System.Diagnostics.DebuggerHidden]
+ void HiddenDefaultMethod()
+ {
+ var a = 9;
+ }
+
+ [System.Diagnostics.DebuggerStepThroughAttribute]
+ void StepThroughDefaultMethod()
+ {
+ var a = 0;
+ }
+
+ [System.Diagnostics.DebuggerNonUserCode]
+ void NonUserCodeDefaultMethod(Action boundaryTestFun = null)
+ {
+ if (boundaryTestFun != null)
+ boundaryTestFun();
+ }
+
+ [System.Diagnostics.DebuggerStepperBoundary]
+ void BoundaryBp()
+ {
+ var a = 15;
+ }
+}
+
+public class DIMClass : IExtendIDefaultInterface
+{
+ public int dimClassMember = 123;
+}
+
+public static class DefaultInterfaceMethod
+{
+ public static void Evaluate()
+ {
+ IExtendIDefaultInterface extendDefaultInter = new DIMClass();
+ string defaultFromIDefault = extendDefaultInter.DefaultMethod();
+ int overrideFromIExtend = extendDefaultInter.DefaultMethodToOverride();
+ extendDefaultInter.DefaultMethod2(out string default2FromIExtend);
+ }
+
+ public static async void EvaluateAsync()
+ {
+ IDefaultInterface defaultInter = new DIMClass();
+ await defaultInter.DefaultMethodAsync();
+ }
+
+ public static void EvaluateHiddenAttr()
+ {
+ IExtendIDefaultInterface extendDefaultInter = new DIMClass();
+ extendDefaultInter.HiddenDefaultMethod();
+ }
+
+ public static void EvaluateStepThroughAttr()
+ {
+ IExtendIDefaultInterface extendDefaultInter = new DIMClass();
+ extendDefaultInter.StepThroughDefaultMethod();
+ }
+
+ public static void EvaluateNonUserCodeAttr()
+ {
+ IExtendIDefaultInterface extendDefaultInter = new DIMClass();
+ extendDefaultInter.NonUserCodeDefaultMethod();
+ }
+
+ public static void EvaluateStepperBoundaryAttr()
+ {
+ IExtendIDefaultInterface extendDefaultInter = new DIMClass();
+ extendDefaultInter.NonUserCodeDefaultMethod(extendDefaultInter.BoundaryBp);
+ }
+
+ public static void MethodForCallingFromDIM()
+ {
+ string text = "a place for pausing and inspecting DIM";
+ }
+}
+#endregion
diff --git a/src/mono/wasm/host/CommonConfiguration.cs b/src/mono/wasm/host/CommonConfiguration.cs
index 309800ae1f6..eb0a0af997d 100644
--- a/src/mono/wasm/host/CommonConfiguration.cs
+++ b/src/mono/wasm/host/CommonConfiguration.cs
@@ -109,10 +109,6 @@ internal sealed class CommonConfiguration
if (HostProperties.FirefoxDebuggingPort is not null)
options.FirefoxDebugPort = HostProperties.FirefoxDebuggingPort.Value;
options.LogPath = ".";
- options.AutoSetBreakpointOnEntryPoint = true;
- if (!string.IsNullOrEmpty(HostProperties.MainAssembly))
- options.EntrypointAssembly = HostProperties.MainAssembly;
-
return options;
}
diff --git a/src/mono/wasm/host/RunConfiguration.cs b/src/mono/wasm/host/RunConfiguration.cs
index 4d4b84a0527..67a4f2e8954 100644
--- a/src/mono/wasm/host/RunConfiguration.cs
+++ b/src/mono/wasm/host/RunConfiguration.cs
@@ -74,8 +74,6 @@ internal sealed class RunConfiguration
if (HostProperties.FirefoxDebuggingPort is not null)
options.FirefoxDebugPort = HostProperties.FirefoxDebuggingPort.Value;
options.LogPath = ".";
- options.AutoSetBreakpointOnEntryPoint = true;
-
return options;
}
}
diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt
index 9962dbff59c..b55a14d2eb5 100644
--- a/src/mono/wasm/runtime/CMakeLists.txt
+++ b/src/mono/wasm/runtime/CMakeLists.txt
@@ -35,7 +35,7 @@ set_target_properties(dotnet PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}")
if(CMAKE_BUILD_TYPE STREQUAL "Release")
- add_custom_command(TARGET dotnet POST_BUILD COMMAND ${EMSDK_PATH}/upstream/bin/wasm-opt --enable-exception-handling --strip-dwarf ${NATIVE_BIN_DIR}/dotnet.wasm -o ${NATIVE_BIN_DIR}/dotnet.wasm)
+ add_custom_command(TARGET dotnet POST_BUILD COMMAND ${EMSDK_PATH}/upstream/bin/wasm-opt ${WASM_OPT_ADDITIONAL_FLAGS} --enable-exception-handling --strip-dwarf ${NATIVE_BIN_DIR}/dotnet.wasm -o ${NATIVE_BIN_DIR}/dotnet.wasm)
endif()
configure_file(wasm-config.h.in include/wasm/wasm-config.h)
diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
index ec39de8e376..ceeb9d37d75 100644
--- a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
+++ b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
@@ -42,6 +42,7 @@ const linked_functions = [
"mono_wasm_invoke_js",
"mono_wasm_invoke_js_blazor",
"mono_wasm_trace_logger",
+ "mono_wasm_set_entrypoint_breakpoint",
// corebindings.c
"mono_wasm_invoke_js_with_args_ref",
diff --git a/src/mono/wasm/runtime/crypto-worker.ts b/src/mono/wasm/runtime/crypto-worker.ts
index ea7bd9e6fce..f17a455892d 100644
--- a/src/mono/wasm/runtime/crypto-worker.ts
+++ b/src/mono/wasm/runtime/crypto-worker.ts
@@ -65,10 +65,15 @@ class LibraryChannel {
private comm: Int32Array;
private msg: Uint16Array;
+ // LOCK states
+ private get LOCK_UNLOCKED(): number { return 0; } // 0 means the lock is unlocked
+ private get LOCK_OWNED(): number { return 1; } // 1 means the LibraryChannel owns the lock
+
// Index constants for the communication buffer.
private get STATE_IDX(): number { return 0; }
private get MSG_SIZE_IDX(): number { return 1; }
- private get COMM_LAST_IDX(): number { return this.MSG_SIZE_IDX; }
+ private get LOCK_IDX(): number { return 2; }
+ private get COMM_LAST_IDX(): number { return this.LOCK_IDX; }
// Communication states.
private get STATE_SHUTDOWN(): number { return -1; } // Shutdown
@@ -125,6 +130,8 @@ class LibraryChannel {
let msg_written = 0;
for (; ;) {
+ this.acquire_lock();
+
// Write the message and return how much was written.
const wrote = this.write_to_msg(msg, msg_written, msg_len);
msg_written += wrote;
@@ -137,6 +144,9 @@ class LibraryChannel {
// Notify webworker
Atomics.store(this.comm, this.STATE_IDX, state);
+
+ this.release_lock();
+
Atomics.notify(this.comm, this.STATE_IDX);
// The send message is complete.
@@ -172,6 +182,8 @@ class LibraryChannel {
state = Atomics.load(this.comm, this.STATE_IDX);
} while (state !== this.STATE_RESP && state !== this.STATE_RESP_P);
+ this.acquire_lock();
+
const size_to_read = Atomics.load(this.comm, this.MSG_SIZE_IDX);
// Append the latest part of the message.
@@ -179,12 +191,16 @@ class LibraryChannel {
// The response is complete.
if (state === this.STATE_RESP) {
+ this.release_lock();
break;
}
// Reset the size and transition to await state.
Atomics.store(this.comm, this.MSG_SIZE_IDX, 0);
Atomics.store(this.comm, this.STATE_IDX, this.STATE_AWAIT);
+
+ this.release_lock();
+
Atomics.notify(this.comm, this.STATE_IDX);
}
@@ -202,6 +218,19 @@ class LibraryChannel {
return String.fromCharCode.apply(null, slicedMessage);
}
+ private acquire_lock() {
+ while (Atomics.compareExchange(this.comm, this.LOCK_IDX, this.LOCK_UNLOCKED, this.LOCK_OWNED) !== this.LOCK_UNLOCKED) {
+ // empty
+ }
+ }
+
+ private release_lock() {
+ const result = Atomics.compareExchange(this.comm, this.LOCK_IDX, this.LOCK_OWNED, this.LOCK_UNLOCKED);
+ if (result !== this.LOCK_OWNED) {
+ throw "CRYPTO: LibraryChannel tried to release a lock that wasn't acquired: " + result;
+ }
+ }
+
public static create(msg_char_len: number): LibraryChannel {
if (msg_char_len === undefined) {
msg_char_len = 1024; // Default size is arbitrary but is in 'char' units (i.e. UTF-16 code points).
diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts
index 5f9984af2a4..c4892f33dbf 100644
--- a/src/mono/wasm/runtime/cwraps.ts
+++ b/src/mono/wasm/runtime/cwraps.ts
@@ -135,7 +135,7 @@ export interface t_Cwraps {
mono_wasm_try_unbox_primitive_and_get_type_ref(obj: MonoObjectRef, buffer: VoidPtr, buffer_size: number): number;
mono_wasm_box_primitive_ref(klass: MonoClass, value: VoidPtr, value_size: number, result: MonoObjectRef): void;
mono_wasm_intern_string_ref(strRef: MonoStringRef): void;
- mono_wasm_assembly_get_entry_point(assembly: MonoAssembly): MonoMethod;
+ mono_wasm_assembly_get_entry_point(assembly: MonoAssembly, idx: number): MonoMethod;
mono_wasm_string_array_new_ref(size: number, result: MonoObjectRef): void;
mono_wasm_typed_array_new_ref(arr: VoidPtr, length: number, size: number, type: number, result: MonoObjectRef): void;
mono_wasm_class_get_type(klass: MonoClass): MonoType;
diff --git a/src/mono/wasm/runtime/debug.ts b/src/mono/wasm/runtime/debug.ts
index 7a702f2053e..f767c28dd3b 100644
--- a/src/mono/wasm/runtime/debug.ts
+++ b/src/mono/wasm/runtime/debug.ts
@@ -5,7 +5,6 @@ import { INTERNAL, Module, MONO, runtimeHelpers } from "./imports";
import { toBase64StringImpl } from "./base64";
import cwraps from "./cwraps";
import { VoidPtr, CharPtr } from "./types/emscripten";
-
const commands_received : any = new Map<number, CommandResponse>();
const wasm_func_map = new Map<number, string>();
commands_received.remove = function (key: number) : CommandResponse { const value = this.get(key); this.delete(key); return value;};
@@ -158,10 +157,19 @@ export function mono_wasm_wait_for_debugger(): Promise<void> {
}
export function mono_wasm_debugger_attached(): void {
- runtimeHelpers.wait_for_debugger = 1;
+ if (runtimeHelpers.wait_for_debugger == -1)
+ runtimeHelpers.wait_for_debugger = 1;
cwraps.mono_wasm_set_is_debugger_attached(true);
}
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export function mono_wasm_set_entrypoint_breakpoint(assembly_name: CharPtr, entrypoint_method_token: number): void {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const assembly_name_str = Module.UTF8ToString(assembly_name).concat(".dll");
+ // eslint-disable-next-line no-debugger
+ debugger;
+}
+
function _create_proxy_from_object_id(objectId: string, details: any) {
if (objectId.startsWith("dotnet:array:")) {
let ret: Array<any>;
diff --git a/src/mono/wasm/runtime/dotnet-crypto-worker.js b/src/mono/wasm/runtime/dotnet-crypto-worker.js
index c6416492a71..0110693a1a4 100644
--- a/src/mono/wasm/runtime/dotnet-crypto-worker.js
+++ b/src/mono/wasm/runtime/dotnet-crypto-worker.js
@@ -3,9 +3,14 @@
var ChannelWorker = {
_impl: class {
+ // LOCK states
+ get LOCK_UNLOCKED() { return 0; } // 0 means the lock is unlocked
+ get LOCK_OWNED() { return 2; } // 2 means the ChannelWorker owns the lock
+
// BEGIN ChannelOwner contract - shared constants.
get STATE_IDX() { return 0; }
get MSG_SIZE_IDX() { return 1; }
+ get LOCK_IDX() { return 2; }
// Communication states.
get STATE_SHUTDOWN() { return -1; } // Shutdown
@@ -51,6 +56,8 @@ var ChannelWorker = {
_read_request() {
var request = "";
for (;;) {
+ this._acquire_lock();
+
// Get the current state and message size
var state = Atomics.load(this.comm, this.STATE_IDX);
var size_to_read = Atomics.load(this.comm, this.MSG_SIZE_IDX);
@@ -59,16 +66,22 @@ var ChannelWorker = {
request += this._read_from_msg(0, size_to_read);
// The request is complete.
- if (state === this.STATE_REQ)
+ if (state === this.STATE_REQ) {
+ this._release_lock();
break;
+ }
// Shutdown the worker.
- if (state === this.STATE_SHUTDOWN)
+ if (state === this.STATE_SHUTDOWN) {
+ this._release_lock();
return this.STATE_SHUTDOWN;
+ }
// Reset the size and transition to await state.
Atomics.store(this.comm, this.MSG_SIZE_IDX, 0);
Atomics.store(this.comm, this.STATE_IDX, this.STATE_AWAIT);
+ this._release_lock();
+
Atomics.wait(this.comm, this.STATE_IDX, this.STATE_AWAIT);
}
@@ -88,6 +101,8 @@ var ChannelWorker = {
var msg_written = 0;
for (;;) {
+ this._acquire_lock();
+
// Write the message and return how much was written.
var wrote = this._write_to_msg(msg, msg_written, msg_len);
msg_written += wrote;
@@ -101,6 +116,8 @@ var ChannelWorker = {
// Update the state
Atomics.store(this.comm, this.STATE_IDX, state);
+ this._release_lock();
+
// Wait for the transition to know the main thread has
// received the response by moving onto a new state.
Atomics.wait(this.comm, this.STATE_IDX, state);
@@ -121,6 +138,19 @@ var ChannelWorker = {
}
return ii - start;
}
+
+ _acquire_lock() {
+ while (Atomics.compareExchange(this.comm, this.LOCK_IDX, this.LOCK_UNLOCKED, this.LOCK_OWNED) !== this.LOCK_UNLOCKED) {
+ // empty
+ }
+ }
+
+ _release_lock() {
+ const result = Atomics.compareExchange(this.comm, this.LOCK_IDX, this.LOCK_OWNED, this.LOCK_UNLOCKED);
+ if (result !== this.LOCK_OWNED) {
+ throw "CRYPTO: ChannelWorker tried to release a lock that wasn't acquired: " + result;
+ }
+ }
},
create: function (comm_buf, msg_buf, msg_char_len) {
diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c
index 32528ad0559..2a30682885e 100644
--- a/src/mono/wasm/runtime/driver.c
+++ b/src/mono/wasm/runtime/driver.c
@@ -19,6 +19,7 @@
#include <mono/metadata/loader.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/object.h>
+#include <mono/metadata/debug-helpers.h>
// FIXME: unavailable in emscripten
// #include <mono/metadata/gc-internals.h>
@@ -42,6 +43,7 @@ void core_initialize_internals ();
#endif
extern MonoString* mono_wasm_invoke_js (MonoString *str, int *is_exception);
+extern void mono_wasm_set_entrypoint_breakpoint (const char* assembly_name, int method_token);
// Blazor specific custom routines - see dotnet_support.js for backing code
extern void* mono_wasm_invoke_js_blazor (MonoString **exceptionMessage, void *callInfo, void* arg0, void* arg1, void* arg2);
@@ -723,7 +725,7 @@ mono_wasm_invoke_method (MonoMethod *method, MonoObject *this_arg, void *params[
}
EMSCRIPTEN_KEEPALIVE MonoMethod*
-mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
+mono_wasm_assembly_get_entry_point (MonoAssembly *assembly, int auto_insert_breakpoint)
{
MonoImage *image;
MonoMethod *method;
@@ -776,6 +778,13 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
end:
MONO_EXIT_GC_UNSAFE;
+ if (auto_insert_breakpoint)
+ {
+ MonoAssemblyName *aname = mono_assembly_get_name (assembly);
+ const char *name = mono_assembly_name_get_name (aname);
+ if (name != NULL)
+ mono_wasm_set_entrypoint_breakpoint(name, mono_method_get_token (method));
+ }
return method;
}
diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
index 47b59063b7b..5866ffed265 100644
--- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
+++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
@@ -71,6 +71,7 @@ const linked_functions = [
"mono_wasm_fire_debugger_agent_message",
"mono_wasm_debugger_log",
"mono_wasm_add_dbg_command_received",
+ "mono_wasm_set_entrypoint_breakpoint",
// mono-threads-wasm.c
"schedule_background_exec",
diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts
index 8a77c785c9c..439665bcc94 100644
--- a/src/mono/wasm/runtime/exports.ts
+++ b/src/mono/wasm/runtime/exports.ts
@@ -28,6 +28,7 @@ import {
mono_wasm_symbolicate_string,
mono_wasm_stringify_as_error_with_stack,
mono_wasm_debugger_attached,
+ mono_wasm_set_entrypoint_breakpoint,
} from "./debug";
import { ENVIRONMENT_IS_WEB, ExitStatusError, runtimeHelpers, setImportsAndExports } from "./imports";
import { DotnetModuleConfigImports, DotnetModule, is_nullish } from "./types";
@@ -342,6 +343,7 @@ export const __linker_exports: any = {
mono_wasm_invoke_js,
mono_wasm_invoke_js_blazor,
mono_wasm_trace_logger,
+ mono_wasm_set_entrypoint_breakpoint,
// also keep in sync with corebindings.c
mono_wasm_invoke_js_with_args_ref,
diff --git a/src/mono/wasm/runtime/method-calls.ts b/src/mono/wasm/runtime/method-calls.ts
index 5b37c0ae017..eb1ad3dadec 100644
--- a/src/mono/wasm/runtime/method-calls.ts
+++ b/src/mono/wasm/runtime/method-calls.ts
@@ -201,7 +201,11 @@ export function mono_bind_assembly_entry_point(assembly: string, signature?: str
if (!asm)
throw new Error("Could not find assembly: " + assembly);
- const method = cwraps.mono_wasm_assembly_get_entry_point(asm);
+ let auto_set_breakpoint = 0;
+ if (runtimeHelpers.wait_for_debugger == 1)
+ auto_set_breakpoint = 1;
+
+ const method = cwraps.mono_wasm_assembly_get_entry_point(asm, auto_set_breakpoint);
if (!method)
throw new Error("Could not find entry point for assembly: " + assembly);
diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj
index 1f08bf6d9c7..8b309cd75c6 100644
--- a/src/mono/wasm/wasm.proj
+++ b/src/mono/wasm/wasm.proj
@@ -17,6 +17,7 @@
<ICULibDir Condition="'$(MonoWasmThreads)' != 'true'">$([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'lib'))</ICULibDir>
<ICULibDir Condition="'$(MonoWasmThreads)' == 'true'">$([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'lib'))</ICULibDir>
<WasmEnableES6 Condition="'$(WasmEnableES6)' == ''">false</WasmEnableES6>
+ <WasmEnableSIMD Condition="'$(WasmEnableSIMD)' == ''">false</WasmEnableSIMD>
<FilterSystemTimeZones Condition="'$(FilterSystemTimeZones)' == ''">false</FilterSystemTimeZones>
<EmccCmd>emcc</EmccCmd>
<WasmObjDir>$(ArtifactsObjDir)wasm</WasmObjDir>
@@ -131,7 +132,7 @@
<PropertyGroup>
<_DefaultExportedFunctions Condition="$([MSBuild]::VersionGreaterThanOrEquals('$(_EmccVersion)', '3.1.7'))"
- >_malloc,stackSave,stackRestore,stackAlloc,_memalign,_memset,_htons,_ntohs</_DefaultExportedFunctions>
+ >_malloc,stackSave,stackRestore,stackAlloc,_memalign,_memset,_htons,_ntohs,_free</_DefaultExportedFunctions>
<!-- _htons,_ntohs,__get_daylight,__get_timezone,__get_tzname are exported temporarily, until the issue is fixed in emscripten, https://github.com/dotnet/runtime/issues/64724 -->
<_DefaultExportedFunctions Condition="'$(_DefaultExportedFunctions)' == '' and $([MSBuild]::VersionGreaterThan('$(_EmccVersion)', '3.0'))"
@@ -141,14 +142,15 @@
</PropertyGroup>
<ItemGroup>
+ <_EmccCommonFlags Condition="'$(WasmEnableSIMD)' == 'true'" Include="-msimd128" />
+ <_EmccCommonFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-s USE_PTHREADS=1" />
+ <_EmccLinkFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-Wno-pthreads-mem-growth" />
+ <_EmccLinkFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-s PTHREAD_POOL_SIZE=2" />
<_EmccLinkFlags Include="-s EXPORT_ES6=1" Condition="'$(WasmEnableES6)' == 'true'" />
<_EmccLinkFlags Include="-s ALLOW_MEMORY_GROWTH=1" />
<_EmccLinkFlags Include="-s NO_EXIT_RUNTIME=1" />
<_EmccLinkFlags Include="-s FORCE_FILESYSTEM=1" />
<_EmccLinkFlags Include="-s EXPORTED_RUNTIME_METHODS=&quot;['FS','print','ccall','cwrap','setValue','getValue','UTF8ToString','UTF8ArrayToString','FS_createPath','FS_createDataFile','removeRunDependency','addRunDependency', 'FS_readFile']&quot;" />
- <_EmccCommonFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-s USE_PTHREADS=1" />
- <_EmccLinkFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-Wno-pthreads-mem-growth" />
- <_EmccLinkFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-s PTHREAD_POOL_SIZE=2" />
<_EmccLinkFlags Include="-s EXPORTED_FUNCTIONS=$(_DefaultExportedFunctions)" Condition="'$(_DefaultExportedFunctions)' != ''" />
<_EmccLinkFlags Include="--source-map-base http://example.com" />
<_EmccLinkFlags Include="-s STRICT_JS=1" />
@@ -213,6 +215,7 @@
<CMakeBuildRuntimeConfigureCmd>$(CMakeBuildRuntimeConfigureCmd) -DICU_LIB_DIR=&quot;$(ICULibDir.TrimEnd('\/'))&quot;</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd>$(CMakeBuildRuntimeConfigureCmd) -DMONO_ARTIFACTS_DIR=&quot;$(MonoArtifactsPath.TrimEnd('\/'))&quot;</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd>$(CMakeBuildRuntimeConfigureCmd) -DNATIVE_BIN_DIR=&quot;$(NativeBinDir.TrimEnd('\/'))&quot;</CMakeBuildRuntimeConfigureCmd>
+ <CMakeBuildRuntimeConfigureCmd Condition="'$(WasmEnableSIMD)' == 'true' and '$(Configuration)' == 'Release'">$(CMakeBuildRuntimeConfigureCmd) -DWASM_OPT_ADDITIONAL_FLAGS=&quot;--enable-simd&quot;</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd Condition="'$(MonoWasmThreads)' == 'true'">$(CMakeBuildRuntimeConfigureCmd) -DDISABLE_THREADS=0</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd Condition="'$(MonoWasmThreadsNoUser)' == 'true'">$(CMakeBuildRuntimeConfigureCmd) -DDISABLE_WASM_USER_THREADS=1</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd>$(CMakeBuildRuntimeConfigureCmd) $(CMakeConfigurationEmsdkPath)</CMakeBuildRuntimeConfigureCmd>
diff --git a/src/native/libs/ReadMe.md b/src/native/libs/ReadMe.md
new file mode 100644
index 00000000000..49397cef86e
--- /dev/null
+++ b/src/native/libs/ReadMe.md
@@ -0,0 +1,3 @@
+For information on how to build, how to update the binplacing of the native artifacts please refer to
+[How to building native components only](../../../docs/workflow/building/libraries/README.md#how-to-building-native-components-only)
+section in the libraries' building document.
diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt
index 45bfea5a8e7..19466c7572d 100644
--- a/src/native/libs/System.Native/CMakeLists.txt
+++ b/src/native/libs/System.Native/CMakeLists.txt
@@ -52,6 +52,11 @@ endif()
if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
set(NATIVE_SOURCES ${NATIVE_SOURCES}
+ pal_datetime.m)
+endif()
+
+if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
+ set(NATIVE_SOURCES ${NATIVE_SOURCES}
pal_log.m
pal_searchpath.m)
else ()
diff --git a/src/native/libs/System.Native/pal_datetime.h b/src/native/libs/System.Native/pal_datetime.h
index 1b88d472780..bc59762a066 100644
--- a/src/native/libs/System.Native/pal_datetime.h
+++ b/src/native/libs/System.Native/pal_datetime.h
@@ -8,6 +8,6 @@
PALEXPORT int64_t SystemNative_GetSystemTimeAsTicks(void);
-#if defined(TARGET_ANDROID)
+#if defined(TARGET_ANDROID) || defined(__APPLE__)
PALEXPORT char* SystemNative_GetDefaultTimeZone(void);
#endif
diff --git a/src/native/libs/System.Native/pal_datetime.m b/src/native/libs/System.Native/pal_datetime.m
new file mode 100644
index 00000000000..cd45b54358f
--- /dev/null
+++ b/src/native/libs/System.Native/pal_datetime.m
@@ -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.
+
+#include "pal_datetime.h"
+#import <Foundation/Foundation.h>
+
+char* SystemNative_GetDefaultTimeZone()
+{
+ NSTimeZone *tz = [NSTimeZone localTimeZone];
+ NSString *name = [tz name];
+ return (name != nil) ? strdup([name UTF8String]) : NULL;
+} \ No newline at end of file
diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c
index 430f3712fca..22828c0da57 100644
--- a/src/native/libs/System.Native/pal_networking.c
+++ b/src/native/libs/System.Native/pal_networking.c
@@ -1440,7 +1440,10 @@ int32_t SystemNative_Send(intptr_t socket, void* buffer, int32_t bufferLen, int3
ssize_t res;
#if defined(__APPLE__) && __APPLE__
// possible OSX kernel bug: https://github.com/dotnet/runtime/issues/27221
- while ((res = send(fd, buffer, (size_t)bufferLen, socketFlags)) < 0 && (errno == EINTR || errno == EPROTOTYPE));
+ // According to https://github.com/dotnet/runtime/issues/63291 the EPROTOTYPE may be
+ // permanent so we need to limit retries.
+ int maxProtoRetry = 4;
+ while ((res = send(fd, buffer, (size_t)bufferLen, socketFlags)) < 0 && (errno == EINTR || (errno == EPROTOTYPE && --maxProtoRetry > 0)));
#else
while ((res = send(fd, buffer, (size_t)bufferLen, socketFlags)) < 0 && errno == EINTR);
#endif
@@ -1476,7 +1479,10 @@ int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader,
ssize_t res;
#if defined(__APPLE__) && __APPLE__
// possible OSX kernel bug: https://github.com/dotnet/runtime/issues/27221
- while ((res = sendmsg(fd, &header, socketFlags)) < 0 && (errno == EINTR || errno == EPROTOTYPE));
+ // According to https://github.com/dotnet/runtime/issues/63291 the EPROTOTYPE may be
+ // permanent so we need to limit retries.
+ int maxProtoRetry = 4;
+ while ((res = sendmsg(fd, &header, socketFlags)) < 0 && (errno == EINTR || (errno == EPROTOTYPE && --maxProtoRetry > 0)));
#else
while ((res = sendmsg(fd, &header, socketFlags)) < 0 && errno == EINTR);
#endif
diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
index 66cf3ec06e8..fcc24b6111b 100644
--- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
+++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
@@ -117,6 +117,11 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
public string[]? AotProfilePath { get; set; }
/// <summary>
+ /// Mibc file to use for profile-guided optimization, *only* the methods described in the file will be AOT compiled.
+ /// </summary>
+ public string[]? MibcProfilePath { get; set; }
+
+ /// <summary>
/// List of profilers to use.
/// </summary>
public string[]? Profilers { get; set; }
@@ -278,6 +283,18 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
}
}
+ if (MibcProfilePath != null)
+ {
+ foreach (var path in MibcProfilePath)
+ {
+ if (!File.Exists(path))
+ {
+ Log.LogError($"MibcProfilePath '{path}' doesn't exist.");
+ return false;
+ }
+ }
+ }
+
if (UseLLVM)
{
if (string.IsNullOrEmpty(LLVMPath))
@@ -739,6 +756,15 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
}
}
+ if (MibcProfilePath?.Length > 0)
+ {
+ aotArgs.Add("profile-only");
+ foreach (var path in MibcProfilePath)
+ {
+ aotArgs.Add($"mibc-profile={path}");
+ }
+ }
+
if (!string.IsNullOrEmpty(AotArguments))
{
aotArgs.Add(AotArguments);
diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs
index 2db7094b009..73465e8c009 100644
--- a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs
+++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs
@@ -97,6 +97,7 @@ namespace Wasm.Build.Tests
EnvVars["_WasmStrictVersionMatch"] = "true";
EnvVars["MSBuildSDKsPath"] = string.Empty;
EnvVars["PATH"] = $"{sdkForWorkloadPath}{Path.PathSeparator}{Environment.GetEnvironmentVariable("PATH")}";
+ EnvVars["EM_WORKAROUND_PYTHON_BUG_34780"] = "1";
// helps with debugging
EnvVars["WasmNativeStrip"] = "false";
diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmBuildAppTest.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmBuildAppTest.cs
index d6ae5ed870c..1e8f600ec86 100644
--- a/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmBuildAppTest.cs
+++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmBuildAppTest.cs
@@ -10,16 +10,11 @@ using Xunit.Abstractions;
namespace Wasm.Build.Tests
{
- public class WasmBuildAppTest : BuildTestBase
+ public class WasmBuildAppTest : WasmBuildAppBase
{
public WasmBuildAppTest(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext)
{}
- public static IEnumerable<object?[]> MainMethodTestData(bool aot, RunHost host)
- => ConfigWithAOTData(aot)
- .WithRunHosts(host)
- .UnwrapItemsAsArrays();
-
[Theory]
[ActiveIssue("https://github.com/dotnet/runtime/issues/61725", TestPlatforms.Windows)]
[MemberData(nameof(MainMethodTestData), parameters: new object[] { /*aot*/ true, RunHost.All })]
@@ -153,14 +148,26 @@ namespace Wasm.Build.Tests
RunAndTestWasmApp(buildArgs, expectedExitCode: 42,
test: output => Assert.Contains("System.Threading.ThreadPool.MaxThreads: 20", output), host: host, id: id);
}
+ }
+
+ public class WasmBuildAppBase : BuildTestBase
+ {
+ public static IEnumerable<object?[]> MainMethodTestData(bool aot, RunHost host)
+ => ConfigWithAOTData(aot)
+ .WithRunHosts(host)
+ .UnwrapItemsAsArrays();
+
+ public WasmBuildAppBase(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext)
+ {
+ }
- void TestMain(string projectName,
- string programText,
- BuildArgs buildArgs,
- RunHost host,
- string id,
- string extraProperties = "",
- bool? dotnetWasmFromRuntimePack = null)
+ protected void TestMain(string projectName,
+ string programText,
+ BuildArgs buildArgs,
+ RunHost host,
+ string id,
+ string extraProperties = "",
+ bool? dotnetWasmFromRuntimePack = null)
{
buildArgs = buildArgs with { ProjectName = projectName };
buildArgs = ExpandBuildArgs(buildArgs, extraProperties);
@@ -178,5 +185,4 @@ namespace Wasm.Build.Tests
test: output => Assert.Contains("Hello, World!", output), host: host, id: id);
}
}
-
- }
+}
diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmSIMDTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmSIMDTests.cs
new file mode 100644
index 00000000000..8c5c397b82c
--- /dev/null
+++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/WasmSIMDTests.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+using Xunit.Abstractions;
+
+#nullable enable
+
+namespace Wasm.Build.Tests
+{
+ public class WasmSIMDTests : WasmBuildAppBase
+ {
+ public WasmSIMDTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
+ : base(output, buildContext)
+ {
+ }
+
+ [Theory]
+ [MemberData(nameof(MainMethodTestData), parameters: new object[] { /*aot*/ true, RunHost.All })]
+ public void BuildWithSIMD(BuildArgs buildArgs, RunHost host, string id)
+ => TestMain("main_simd_aot",
+ @"
+ using System;
+ using System.Runtime.Intrinsics;
+
+ public class TestClass {
+ public static int Main()
+ {
+ var v1 = Vector128.Create(0x12345678);
+ var v2 = Vector128.Create(0x23456789);
+ var v3 = v1*v2;
+ Console.WriteLine(v3);
+ Console.WriteLine(""Hello, World!"");
+
+ return 42;
+ }
+ }",
+ buildArgs, host, id, extraProperties: "<WasmSIMD>true</WasmSIMD>");
+ }
+}
diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.cmd b/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.cmd
index bca245bc437..c2523168b90 100644
--- a/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.cmd
+++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.cmd
@@ -94,14 +94,16 @@ exit /b %EXIT_CODE%
REM Functions
:SetEnvVars
if [%TEST_USING_WORKLOADS%] == [true] (
- set "PATH=%BASE_DIR%\dotnet-workload;%PATH%"
set SDK_HAS_WORKLOAD_INSTALLED=true
- set "SDK_FOR_WORKLOAD_TESTING_PATH=%BASE_DIR%\dotnet-workload"
+ robocopy /np /nfl /e %BASE_DIR%\dotnet-workload %EXECUTION_DIR%\dotnet-workload
+ set "SDK_FOR_WORKLOAD_TESTING_PATH=%EXECUTION_DIR%\dotnet-workload"
+ set "PATH=%EXECUTION_DIR%\dotnet-workload;%PATH%"
set "AppRefDir=%BASE_DIR%\microsoft.netcore.app.ref"
) else (
- set "PATH=%BASE_DIR%\sdk-no-workload;%PATH%"
set SDK_HAS_WORKLOAD_INSTALLED=false
- set "SDK_FOR_WORKLOAD_TESTING_PATH=%BASE_DIR%\sdk-no-workload"
+ robocopy /np /nfl /e %BASE_DIR%\sdk-no-workload %EXECUTION_DIR%\sdk-no-workload
+ set "SDK_FOR_WORKLOAD_TESTING_PATH=%EXECUTION_DIR%\sdk-no-workload"
+ set "PATH=%EXECUTION_DIR%\sdk-no-workload;%PATH%"
set "AppRefDir=%BASE_DIR%\microsoft.netcore.app.ref"
)
EXIT /b 0
diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.sh b/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.sh
index 1130c803f27..97ed44c3606 100644
--- a/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.sh
+++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/data/RunScriptTemplate.sh
@@ -67,14 +67,16 @@ echo XHARNESS_ARGS=$XHARNESS_ARGS
function set_env_vars()
{
if [ "x$TEST_USING_WORKLOADS" = "xtrue" ]; then
- export PATH=$BASE_DIR/dotnet-workload:$PATH
+ cp -r $BASE_DIR/dotnet-workload $EXECUTION_DIR
+ export PATH=$EXECUTION_DIR/dotnet-workload:$PATH
export SDK_HAS_WORKLOAD_INSTALLED=true
- export SDK_FOR_WORKLOAD_TESTING_PATH=$BASE_DIR/dotnet-workload
+ export SDK_FOR_WORKLOAD_TESTING_PATH=$EXECUTION_DIR/dotnet-workload
export AppRefDir=$BASE_DIR/microsoft.netcore.app.ref
else
- export PATH=$BASE_DIR/sdk-no-workload:$PATH
+ cp -r $BASE_DIR/sdk-no-workload $EXECUTION_DIR
+ export PATH=$EXECUTION_DIR/sdk-no-workload:$PATH
export SDK_HAS_WORKLOAD_INSTALLED=false
- export SDK_FOR_WORKLOAD_TESTING_PATH=$BASE_DIR/sdk-no-workload
+ export SDK_FOR_WORKLOAD_TESTING_PATH=$EXECUTION_DIR/sdk-no-workload
export AppRefDir=$BASE_DIR/microsoft.netcore.app.ref
fi
}
diff --git a/src/tests/Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj b/src/tests/Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj
index e8864b4eb5f..04496ab0b05 100644
--- a/src/tests/Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj
+++ b/src/tests/Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj
@@ -21,6 +21,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\Coreclr.TestWrapper\CoreclrTestWrapperLib.cs" Link="CoreclrTestWrapperLib.cs" />
+ <Compile Include="..\Coreclr.TestWrapper\MobileAppHandler.cs" Link="MobileAppHandler.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs
index 23bbdc5ca48..4dea184184c 100644
--- a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs
+++ b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs
@@ -305,85 +305,91 @@ namespace CoreclrTestLib
using (var errorWriter = new StreamWriter(errorStream))
using (Process process = new Process())
{
- // Windows can run the executable implicitly
- if (OperatingSystem.IsWindows())
+ if (MobileAppHandler.IsRetryRequested(testBinaryBase))
{
- process.StartInfo.FileName = executable;
+ outputWriter.WriteLine("\nWork item retry had been requested earlier - skipping test...");
}
- // Non-windows needs to be told explicitly to run through /bin/bash shell
else
{
- process.StartInfo.FileName = "/bin/bash";
- process.StartInfo.Arguments = executable;
- }
-
- process.StartInfo.UseShellExecute = false;
- process.StartInfo.RedirectStandardOutput = true;
- process.StartInfo.RedirectStandardError = true;
- process.StartInfo.EnvironmentVariables.Add("__Category", category);
- process.StartInfo.EnvironmentVariables.Add("__TestBinaryBase", testBinaryBase);
- process.StartInfo.EnvironmentVariables.Add("__OutputDir", outputDir);
-
- DateTime startTime = DateTime.Now;
- process.Start();
+ // Windows can run the executable implicitly
+ if (OperatingSystem.IsWindows())
+ {
+ process.StartInfo.FileName = executable;
+ }
+ // Non-windows needs to be told explicitly to run through /bin/bash shell
+ else
+ {
+ process.StartInfo.FileName = "/bin/bash";
+ process.StartInfo.Arguments = executable;
+ }
- var cts = new CancellationTokenSource();
- Task copyOutput = process.StandardOutput.BaseStream.CopyToAsync(outputStream, 4096, cts.Token);
- Task copyError = process.StandardError.BaseStream.CopyToAsync(errorStream, 4096, cts.Token);
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.RedirectStandardError = true;
+ process.StartInfo.EnvironmentVariables.Add("__Category", category);
+ process.StartInfo.EnvironmentVariables.Add("__TestBinaryBase", testBinaryBase);
+ process.StartInfo.EnvironmentVariables.Add("__OutputDir", outputDir);
- if (process.WaitForExit(timeout))
- {
- // Process completed. Check process.ExitCode here.
- exitCode = process.ExitCode;
- Task.WaitAll(copyOutput, copyError);
- }
- else
- {
- // Timed out.
+ DateTime startTime = DateTime.Now;
+ process.Start();
- DateTime endTime = DateTime.Now;
+ var cts = new CancellationTokenSource();
+ Task copyOutput = process.StandardOutput.BaseStream.CopyToAsync(outputStream, 4096, cts.Token);
+ Task copyError = process.StandardError.BaseStream.CopyToAsync(errorStream, 4096, cts.Token);
- try
+ if (process.WaitForExit(timeout))
{
- cts.Cancel();
+ // Process completed. Check process.ExitCode here.
+ exitCode = process.ExitCode;
+ MobileAppHandler.CheckExitCode(exitCode, testBinaryBase, category, outputWriter);
+ Task.WaitAll(copyOutput, copyError);
}
- catch {}
+ else
+ {
+ // Timed out.
+ DateTime endTime = DateTime.Now;
- outputWriter.WriteLine("\ncmdLine:{0} Timed Out (timeout in milliseconds: {1}{2}{3}, start: {4}, end: {5})",
- executable, timeout, (environmentVar != null) ? " from variable " : "", (environmentVar != null) ? TIMEOUT_ENVIRONMENT_VAR : "",
- startTime.ToString(), endTime.ToString());
- errorWriter.WriteLine("\ncmdLine:{0} Timed Out (timeout in milliseconds: {1}{2}{3}, start: {4}, end: {5})",
- executable, timeout, (environmentVar != null) ? " from variable " : "", (environmentVar != null) ? TIMEOUT_ENVIRONMENT_VAR : "",
- startTime.ToString(), endTime.ToString());
+ try
+ {
+ cts.Cancel();
+ }
+ catch {}
- if (collectCrashDumps)
- {
- if (crashDumpFolder != null)
+ outputWriter.WriteLine("\ncmdLine:{0} Timed Out (timeout in milliseconds: {1}{2}{3}, start: {4}, end: {5})",
+ executable, timeout, (environmentVar != null) ? " from variable " : "", (environmentVar != null) ? TIMEOUT_ENVIRONMENT_VAR : "",
+ startTime.ToString(), endTime.ToString());
+ errorWriter.WriteLine("\ncmdLine:{0} Timed Out (timeout in milliseconds: {1}{2}{3}, start: {4}, end: {5})",
+ executable, timeout, (environmentVar != null) ? " from variable " : "", (environmentVar != null) ? TIMEOUT_ENVIRONMENT_VAR : "",
+ startTime.ToString(), endTime.ToString());
+
+ if (collectCrashDumps)
{
- foreach (var child in FindChildProcessesByName(process, "corerun"))
+ if (crashDumpFolder != null)
{
- string crashDumpPath = Path.Combine(Path.GetFullPath(crashDumpFolder), string.Format("crashdump_{0}.dmp", child.Id));
- Console.WriteLine($"Attempting to collect crash dump: {crashDumpPath}");
- if (CollectCrashDump(child, crashDumpPath))
+ foreach (var child in FindChildProcessesByName(process, "corerun"))
{
- Console.WriteLine("Collected crash dump: {0}", crashDumpPath);
- }
- else
- {
- Console.WriteLine("Failed to collect crash dump");
+ string crashDumpPath = Path.Combine(Path.GetFullPath(crashDumpFolder), string.Format("crashdump_{0}.dmp", child.Id));
+ Console.WriteLine($"Attempting to collect crash dump: {crashDumpPath}");
+ if (CollectCrashDump(child, crashDumpPath))
+ {
+ Console.WriteLine("Collected crash dump: {0}", crashDumpPath);
+ }
+ else
+ {
+ Console.WriteLine("Failed to collect crash dump");
+ }
}
}
}
- }
- // kill the timed out processes after we've collected dumps
- process.Kill(entireProcessTree: true);
+ // kill the timed out processes after we've collected dumps
+ process.Kill(entireProcessTree: true);
+ }
}
- outputWriter.WriteLine("Test Harness Exitcode is : " + exitCode.ToString());
- outputWriter.Flush();
-
- errorWriter.Flush();
+ outputWriter.WriteLine("Test Harness Exitcode is : " + exitCode.ToString());
+ outputWriter.Flush();
+ errorWriter.Flush();
}
return exitCode;
diff --git a/src/tests/Common/Coreclr.TestWrapper/MobileAppHandler.cs b/src/tests/Common/Coreclr.TestWrapper/MobileAppHandler.cs
index 11fd19e3f7a..aef07d4ff18 100644
--- a/src/tests/Common/Coreclr.TestWrapper/MobileAppHandler.cs
+++ b/src/tests/Common/Coreclr.TestWrapper/MobileAppHandler.cs
@@ -9,6 +9,19 @@ namespace CoreclrTestLib
{
public class MobileAppHandler
{
+ // See https://github.com/dotnet/xharness/blob/main/src/Microsoft.DotNet.XHarness.Common/CLI/ExitCode.cs
+ // 78 - PACKAGE_INSTALLATION_FAILURE
+ // 81 - DEVICE_NOT_FOUND
+ // 82 - RETURN_CODE_NOT_SET
+ // 83 - APP_LAUNCH_FAILURE
+ // 84 - DEVICE_FILE_COPY_FAILURE
+ // 86 - PACKAGE_INSTALLATION_TIMEOUT
+ // 88 - SIMULATOR_FAILURE
+ // 89 - DEVICE_FAILURE
+ // 90 - APP_LAUNCH_TIMEOUT
+ // 91 - ADB_FAILURE
+ private static readonly int[] _knownExitCodes = new int[] { 78, 81, 82, 83, 84, 86, 88, 89, 90, 91 };
+
public int InstallMobileApp(string platform, string category, string testBinaryBase, string reportBase)
{
return HandleMobileApp("install", platform, category, testBinaryBase, reportBase);
@@ -23,12 +36,6 @@ namespace CoreclrTestLib
{
int exitCode = -100;
- if (File.Exists($"{testBinaryBase}/.retry"))
- {
- // We have requested a work item retry because of an infra issue - no point executing further tests
- return exitCode;
- }
-
string outputFile = Path.Combine(reportBase, action, $"{category}_{action}.output.txt");
string errorFile = Path.Combine(reportBase, action, $"{category}_{action}.error.txt");
bool platformValueFlag = true;
@@ -119,23 +126,7 @@ namespace CoreclrTestLib
{
// Process completed.
exitCode = process.ExitCode;
-
- // See https://github.com/dotnet/xharness/blob/main/src/Microsoft.DotNet.XHarness.Common/CLI/ExitCode.cs
- // 78 - PACKAGE_INSTALLATION_FAILURE
- // 81 - DEVICE_NOT_FOUND
- // 85 - ADB_DEVICE_ENUMERATION_FAILURE
- // 86 - PACKAGE_INSTALLATION_TIMEOUT
- // 88 - SIMULATOR_FAILURE
- // 89 - DEVICE_FAILURE
- // 90 - APP_LAUNCH_TIMEOUT
- // 91 - ADB_FAILURE
- var retriableCodes = new[] { 78, 81, 85, 86, 88, 89, 90, 91 };
- if (retriableCodes.Contains(exitCode))
- {
- CreateRetryFile($"{testBinaryBase}/.retry", exitCode, category);
- return exitCode;
- }
-
+ CheckExitCode(exitCode, testBinaryBase, category, outputWriter);
Task.WaitAll(copyOutput, copyError);
}
else
@@ -191,5 +182,19 @@ namespace CoreclrTestLib
writer.WriteLine($"appName: {appName}; exitCode: {exitCode}");
}
}
+
+ public static void CheckExitCode(int exitCode, string testBinaryBase, string category, StreamWriter outputWriter)
+ {
+ if (_knownExitCodes.Contains(exitCode))
+ {
+ CreateRetryFile($"{testBinaryBase}/.retry", exitCode, category);
+ outputWriter.WriteLine("\nInfra issue was detected and a work item retry was requested");
+ }
+ }
+
+ public static bool IsRetryRequested(string testBinaryBase)
+ {
+ return File.Exists($"{testBinaryBase}/.retry");
+ }
}
}
diff --git a/src/tests/Common/testenvironment.proj b/src/tests/Common/testenvironment.proj
index fcc3e3926fe..4cc62162bc2 100644
--- a/src/tests/Common/testenvironment.proj
+++ b/src/tests/Common/testenvironment.proj
@@ -42,7 +42,9 @@
COMPlus_HeapVerify;
COMPlus_JITMinOpts;
COMPlus_JitELTHookEnabled;
+ COMPlus_JitFakeProcedureSplitting;
COMPlus_JitStress;
+ COMPlus_JitStressProcedureSplitting;
COMPlus_JitStressRegs;
COMPlus_TailcallStress;
COMPlus_ReadyToRun;
@@ -188,6 +190,7 @@
<TestEnvironment Include="jitosr" TC_OnStackReplacement="1" TC_QuickJitForLoops="1" TieredCompilation="1" />
<TestEnvironment Include="jitosr_stress" TC_OnStackReplacement="1" TC_QuickJitForLoops="1" TC_OnStackReplacement_InitialCounter="1" OSR_HitLimit="1" TieredCompilation="1" />
<TestEnvironment Include="jitosr_stress_random" TC_OnStackReplacement="1" TC_QuickJitForLoops="1" TC_OnStackReplacement_InitialCounter="1" OSR_HitLimit="2" TieredCompilation="1" JitRandomOnStackReplacement="15"/>
+ <TestEnvironment Include="jit_stress_splitting" JitFakeProcedureSplitting="1" JitStressProcedureSplitting="1" />
<TestEnvironment Include="jitosr_pgo" TC_OnStackReplacement="1" TC_QuickJitForLoops="1" TieredCompilation="1" TieredPGO="1" />
<TestEnvironment Include="jitpartialcompilation" TC_PartialCompilation="1" TC_QuickJitForLoops="1" TieredCompilation="1" />
<TestEnvironment Include="jitpartialcompilation_pgo" TC_PartialCompilation="1" TC_QuickJitForLoops="1" TieredCompilation="1" TieredPGO="1" />
diff --git a/src/tests/JIT/Directed/StructABI/SevenByteStruct.cs b/src/tests/JIT/Directed/StructABI/SevenByteStruct.cs
new file mode 100644
index 00000000000..b8924b99bc4
--- /dev/null
+++ b/src/tests/JIT/Directed/StructABI/SevenByteStruct.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.Runtime.CompilerServices;
+
+// On ARM32 the following has S0 passed in two registers, which requires passing 3 bytes in the last register.
+// We cannot do that in a single load from an arbitrary source and must copy it to a local first.
+
+public struct S0
+{
+ public byte F0;
+ public byte F1;
+ public byte F2;
+ public byte F3;
+ public byte F4;
+ public byte F5;
+ public byte F6;
+}
+
+public class SevenByteStruct
+{
+ public static S0 s_4 = new S0 { F0 = 1, F1 = 2, F2 = 3, F3 = 4, F4 = 5, F5 = 6, F6 = 7 };
+ public static int Main()
+ {
+ ref S0 vr0 = ref s_4;
+ int sum = M35(vr0);
+ return sum == 28 ? 100 : -1;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static int M35(S0 arg0)
+ {
+ return arg0.F0 + arg0.F1 + arg0.F2 + arg0.F3 + arg0.F4 + arg0.F5 + arg0.F6;
+ }
+}
diff --git a/src/tests/JIT/Directed/StructABI/SevenByteStruct.csproj b/src/tests/JIT/Directed/StructABI/SevenByteStruct.csproj
new file mode 100644
index 00000000000..9d281a449d0
--- /dev/null
+++ b/src/tests/JIT/Directed/StructABI/SevenByteStruct.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>PdbOnly</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="SevenByteStruct.cs" />
+ </ItemGroup>
+</Project>
diff --git a/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.cs b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.cs
new file mode 100644
index 00000000000..e1c93bc68fb
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.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.
+//
+// In this issue, although we were not removing an unreachable block, we were removing all the code
+// inside it and as such should update the liveness information. Since we were not updating the liveness
+// information for such scenarios, we were hitting an assert during register allocation.
+public class Program
+{
+ public static ulong[] s_14;
+ public static uint s_34;
+ public static int Main()
+ {
+ var vr2 = new ulong[][]{new ulong[]{0}};
+ M27(s_34, vr2);
+ return 100;
+ }
+
+ public static void M27(uint arg4, ulong[][] arg5)
+ {
+ arg5[0][0] = arg5[0][0];
+ for (int var7 = 0; var7 < 1; var7++)
+ {
+ return;
+ }
+
+ try
+ {
+ s_14 = arg5[0];
+ }
+ finally
+ {
+ arg4 = arg4;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.csproj b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.csproj
new file mode 100644
index 00000000000..57ed2079d02
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_1.csproj
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>PdbOnly</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.cs b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.cs
new file mode 100644
index 00000000000..a741e669199
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// In this issue, we were not removing all the unreachable blocks and that led us to expect that
+// there should be an IG label for one of the unreachable block, but we were not creating it leading
+// to an assert failure.
+public class _65659_2
+{
+ public static bool[][,] s_2;
+ public static short[,][] s_8;
+ public static bool[] s_10;
+ public static ushort[][] s_29;
+ public static int Main()
+ {
+ bool vr1 = M47();
+ return 100;
+ }
+
+ public static bool M47()
+ {
+ bool var0 = default(bool);
+ try
+ {
+ if (var0)
+ {
+ try
+ {
+ if (s_10[0])
+ {
+ return s_2[0][0, 0];
+ }
+ }
+ finally
+ {
+ s_8[0, 0][0] = 0;
+ }
+ }
+ }
+ finally
+ {
+ s_29 = s_29;
+ }
+
+ return true;
+ }
+} \ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.csproj b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.csproj
new file mode 100644
index 00000000000..57ed2079d02
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/GitHub_69659/GitHub_69659_2.csproj
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>PdbOnly</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.cs b/src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.cs
new file mode 100644
index 00000000000..0799ab5ef34
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+public unsafe class Runtime_64375
+{
+ public static int Main()
+ {
+ var a = new StructWithFloats { FloatOne = 1, FloatThree = 2 };
+
+ return Problem(&a) ? 101 : 100;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static bool Problem(StructWithFloats* p1)
+ {
+ var a = new Vector2(p1->FloatOne, p1->FloatTwo);
+ var b = new Vector2(p1->FloatThree, p1->FloatFour);
+
+ return a == b;
+ }
+
+ struct StructWithFloats
+ {
+ public float FloatOne;
+ public float FloatTwo;
+ public float FloatThree;
+ public float FloatFour;
+ }
+}
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.csproj
new file mode 100644
index 00000000000..cf94135633b
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_64375/Runtime_64375.csproj
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <Optimize>True</Optimize>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.cs b/src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.cs
new file mode 100644
index 00000000000..aae6c864afd
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.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.Numerics;
+using System.Runtime.CompilerServices;
+
+public class Runtime_70124
+{
+ public static int Main()
+ {
+ return Problem(Vector2.One, Vector2.One) != new Vector2(3, 3) ? 101 : 100;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Vector2 Problem(Vector2 a, Vector2 b)
+ {
+ CallForVtor2(a + b);
+
+ return (a + b) + a;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void CallForVtor2(Vector2 vtor) { }
+}
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.csproj
new file mode 100644
index 00000000000..f492aeac9d0
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_70124/Runtime_70124.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.cs b/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.cs
new file mode 100644
index 00000000000..a3ad46606fa
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.cs
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// Note: This test file is the source of the Runtime_70259.il file. It requires
+// InlineIL.Fody to compile. It is not used as anything but a reference of that
+// IL file.
+
+using InlineIL;
+using System;
+using System.Runtime.CompilerServices;
+
+class Runtime_70259
+{
+ private static int Main()
+ {
+ // This creates an open delegate that goes through shuffle thunk and
+ // then VSD stub. On arm32 it also goes through wrapper delegate.
+ Func<IFace, int> del = typeof(IFace).GetMethod("Method").CreateDelegate<Func<IFace, int>>();
+
+ // We need a normal call here to get a call site of the form `call
+ // [rel32]` which triggers the bug.
+ return CallMe(del);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static int CallMe(Func<IFace, int> del)
+ {
+ IL.Push(del);
+ IL.Push(new C());
+ IL.Emit.Tail();
+ IL.Emit.Call(new MethodRef(typeof(Func<IFace, int>), "Invoke"));
+ return IL.Return<int>();
+ }
+
+ interface IFace
+ {
+ int Method();
+ }
+
+ class C : IFace
+ {
+ public virtual int Method()
+ {
+ return 100;
+ }
+ }
+}
+
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.il b/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.il
new file mode 100644
index 00000000000..5182397e5af
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.il
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// See Runtime_70259.cs.
+
+// Microsoft (R) .NET IL Disassembler. Version 7.0.0-dev
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern System.Runtime
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 7:0:0:0
+}
+.assembly Runtime_70259
+{
+}
+.module Runtime_70259.dll
+// MVID: {78ECA09B-26A9-44BB-9FD2-D94B639A44D5}
+.custom instance void [System.Runtime]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000001F5DF740000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class private auto ansi beforefieldinit Runtime_70259
+ extends [System.Runtime]System.Object
+{
+ .class interface abstract auto ansi nested private IFace
+ {
+ .method public hidebysig newslot abstract virtual
+ instance int32 Method() cil managed
+ {
+ } // end of method IFace::Method
+
+ } // end of class IFace
+
+ .class auto ansi nested private beforefieldinit C
+ extends [System.Runtime]System.Object
+ implements Runtime_70259/IFace
+ {
+ .method public hidebysig newslot virtual
+ instance int32 Method() cil managed
+ {
+ // Code size 3 (0x3)
+ .maxstack 8
+ IL_0000: ldc.i4.s 100
+ IL_0002: ret
+ } // end of method C::Method
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [System.Runtime]System.Object::.ctor()
+ IL_0006: ret
+ } // end of method C::.ctor
+
+ } // end of class C
+
+ .method private hidebysig static int32
+ Main() cil managed
+ {
+ .entrypoint
+ // Code size 31 (0x1f)
+ .maxstack 8
+ IL_0000: ldtoken Runtime_70259/IFace
+ IL_0005: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
+ IL_000a: ldstr "Method"
+ IL_000f: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string)
+ IL_0014: callvirt instance !!0 [System.Runtime]System.Reflection.MethodInfo::CreateDelegate<class [System.Runtime]System.Func`2<class Runtime_70259/IFace,int32>>()
+ IL_0019: call int32 Runtime_70259::CallMe(class [System.Runtime]System.Func`2<class Runtime_70259/IFace,int32>)
+ IL_001e: ret
+ } // end of method Runtime_70259::Main
+
+ .method private hidebysig static int32
+ CallMe(class [System.Runtime]System.Func`2<class Runtime_70259/IFace,int32> del) cil managed noinlining
+ {
+ // Code size 14 (0xe)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: newobj instance void Runtime_70259/C::.ctor()
+ IL_0006: tail.
+ IL_0008: call instance !1 class [System.Runtime]System.Func`2<class Runtime_70259/IFace,int32>::Invoke(!0)
+ IL_000d: ret
+ } // end of method Runtime_70259::CallMe
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [System.Runtime]System.Object::.ctor()
+ IL_0006: ret
+ } // end of method Runtime_70259::.ctor
+
+} // end of class Runtime_70259
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.ilproj b/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.ilproj
new file mode 100644
index 00000000000..a1a6c92bec3
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259.ilproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk.IL">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>Full</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).il" />
+ </ItemGroup>
+</Project>
diff --git a/src/tests/JIT/opt/Cloning/Runtime_61040_5.cs b/src/tests/JIT/opt/Cloning/Runtime_61040_5.cs
new file mode 100644
index 00000000000..6c94d837139
--- /dev/null
+++ b/src/tests/JIT/opt/Cloning/Runtime_61040_5.cs
@@ -0,0 +1,51 @@
+// 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.CompilerServices;
+
+unsafe class Runtime_61040_5
+{
+ private const int ArrLen = 10;
+
+ public static int Main()
+ {
+ int[] arr = new int[ArrLen];
+
+ try
+ {
+ ProblemWithBlkAsg(arr, ArrLen);
+ return 101;
+ }
+ catch (IndexOutOfRangeException) { }
+
+ try
+ {
+ ProblemWithLclFldAsg(arr, ArrLen);
+ return 102;
+ }
+ catch (IndexOutOfRangeException) { }
+
+ return 100;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ProblemWithBlkAsg(int[] arr, int idx)
+ {
+ for (int i = 0; i < ArrLen; i++)
+ {
+ Unsafe.InitBlock(&i, (byte)idx, 1);
+ arr[i] = 0;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ProblemWithLclFldAsg(int[] arr, int idx)
+ {
+ for (int i = 0; i < ArrLen; i++)
+ {
+ *(byte*)&i = (byte)idx;
+ arr[i] = 0;
+ }
+ }
+}
diff --git a/src/tests/JIT/opt/Cloning/Runtime_61040_5.csproj b/src/tests/JIT/opt/Cloning/Runtime_61040_5.csproj
new file mode 100644
index 00000000000..8c7132fd350
--- /dev/null
+++ b/src/tests/JIT/opt/Cloning/Runtime_61040_5.csproj
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <Optimize>True</Optimize>
+ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+</Project>
diff --git a/src/tests/JIT/opt/Cloning/callandindir.cs b/src/tests/JIT/opt/Cloning/callandindir.cs
new file mode 100644
index 00000000000..065c893e115
--- /dev/null
+++ b/src/tests/JIT/opt/Cloning/callandindir.cs
@@ -0,0 +1,54 @@
+// 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.CompilerServices;
+
+// Loops in F, G, H should all clone
+
+class CallAndIndir
+{
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void S() { }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void F(int[] a, int low, int high, ref int z)
+ {
+ for (int i = low; i < high; i++)
+ {
+ z += a[i];
+ S();
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void G(int[] a, int low, int high, ref int z)
+ {
+ for (int i = low; i < high; i++)
+ {
+ z += a[i];
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void H(int[] a, int low, int high, ref int z)
+ {
+ int r = 0;
+ for (int i = low; i < high; i++)
+ {
+ r += a[i];
+ S();
+ }
+ z += r;
+ }
+
+ public static int Main()
+ {
+ int[] a = new int[] { 1, 2, 3, 4 };
+ int z = 0;
+ F(a, 2, 4, ref z);
+ G(a, 2, 4, ref z);
+ H(a, 2, 4, ref z);
+ return z + 79;
+ }
+}
diff --git a/src/tests/JIT/opt/Cloning/callandindir.csproj b/src/tests/JIT/opt/Cloning/callandindir.csproj
new file mode 100644
index 00000000000..6946bed81bf
--- /dev/null
+++ b/src/tests/JIT/opt/Cloning/callandindir.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+</Project>
diff --git a/src/tests/issues.targets b/src/tests/issues.targets
index 7fc537a8c4a..b38cf417e9d 100644
--- a/src/tests/issues.targets
+++ b/src/tests/issues.targets
@@ -54,9 +54,6 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/rvastatics/RVAOrderingTest/*">
<Issue>https://github.com/dotnet/runtime/issues/55966</Issue>
</ExcludeList>
- <ExcludeList Include="$(XUnitTestBinBase)/JIT/HardwareIntrinsics/X86/X86Base/Pause*/**">
- <Issue>https://github.com/dotnet/runtime/issues/62423</Issue>
- </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Loader/binding/tracing/BinderTracingTest.Basic/*">
<Issue>https://github.com/dotnet/runtime/issues/57786</Issue>
</ExcludeList>
@@ -234,7 +231,7 @@
<Issue>https://github.com/dotnet/runtime/issues/66921</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_56953/Runtime_56953/*">
- <Issue>https://github.com/dotnet/runtime/issues/57515</Issue>
+ <Issue>https://github.com/dotnet/runtime/issues/67870</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/PInvoke/Generics/GenericsTest/*">
<Issue>https://github.com/dotnet/runtime/issues/60036</Issue>
@@ -543,12 +540,6 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/Stress/ABI/pinvokes_do/**">
<Issue>https://github.com/dotnet/runtime/issues/66745</Issue>
</ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Stress/ABI/tailcalls_d/**">
- <Issue>https://github.com/dotnet/runtime/issues/70042</Issue>
- </ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Stress/ABI/tailcalls_do/**">
- <Issue>https://github.com/dotnet/runtime/issues/70042</Issue>
- </ExcludeList>
</ItemGroup>
<!-- Windows arm64 specific excludes -->
@@ -678,18 +669,6 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_56953/Runtime_56953/*">
<Issue>https://github.com/dotnet/runtime/issues/57856</Issue>
</ExcludeList>
- <ExcludeList Include = "$(XunitTestBinBase)/JIT/Stress/ABI/tailcalls_d/**">
- <Issue>https://github.com/dotnet/runtime/issues/68837</Issue>
- </ExcludeList>
- <ExcludeList Include = "$(XunitTestBinBase)/JIT/Stress/ABI/tailcalls_do/**">
- <Issue>https://github.com/dotnet/runtime/issues/68837</Issue>
- </ExcludeList>
- <ExcludeList Include = "$(XunitTestBinBase)/JIT/Stress/ABI/pinvokes_d/**">
- <Issue>https://github.com/dotnet/runtime/issues/68837</Issue>
- </ExcludeList>
- <ExcludeList Include = "$(XunitTestBinBase)/JIT/Stress/ABI/pinvokes_do/**">
- <Issue>https://github.com/dotnet/runtime/issues/68837</Issue>
- </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/profiler/multiple/multiple/*">
<Issue>https://github.com/dotnet/runtime/issues/57875</Issue>
</ExcludeList>
@@ -1499,7 +1478,7 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/SIMD/ShiftOperations/*">
<Issue>There is a known undefined behavior with shifts and 0xFFFFFFFF overflows, so skip the test for mono.</Issue>
</ExcludeList>
-
+
<ExcludeList Include="$(XunitTestBinBase)/baseservices/TieredCompilation/BasicTestWithMcj/*">
<Issue>Tests features specific to coreclr</Issue>
</ExcludeList>
@@ -2219,6 +2198,9 @@
<ExcludeList Include="$(XunitTestBinBase)/Interop/PInvoke/BestFitMapping/Assembly_True_False/Assembly_True_False/*">
<Issue>Mono doesn't support interop BestFitMapping and ThrowOnUnmappableChar attributes</Issue>
</ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_70259/Runtime_70259/*">
+ <Issue>https://github.com/dotnet/runtime/issues/70279</Issue>
+ </ExcludeList>
</ItemGroup>
<!-- Known failures for mono runtime on Windows -->