From 9e158bbf2ef49738fcd775ca7b0b23bb34de50c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 10 Sep 2025 09:57:16 +0200 Subject: [PATCH] Delay computing display names of type system entities --- .../Compiler/Dataflow/AttributeDataFlow.cs | 6 +- .../Dataflow/GenericArgumentDataFlow.cs | 2 +- .../Compiler/Dataflow/HandleCallAction.cs | 4 +- .../Compiler/Dataflow/ReflectionMarker.cs | 60 ++++++++++++++----- .../Dataflow/ReflectionMethodBodyScanner.cs | 16 ++--- ...RequireDynamicallyAccessedMembersAction.cs | 4 +- .../Dataflow/TrimAnalysisAssignmentPattern.cs | 6 +- 7 files changed, 65 insertions(+), 33 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs index 40fe1df4b26a18..135722e6fb1703 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs @@ -102,7 +102,7 @@ private void ProcessAttributeDataflow(MethodDesc method, ImmutableArray if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { MultiValue value = GetValueForCustomAttributeArgument(arguments[parameter.MetadataIndex]); - RequireDynamicallyAccessedMembers(_diagnosticContext, value, parameterValue, method.GetDisplayName(), ref result); + RequireDynamicallyAccessedMembers(_diagnosticContext, value, parameterValue, method, ref result); } } } @@ -114,7 +114,7 @@ private void ProcessAttributeDataflow(FieldDesc field, object? value, ref Depend && fieldValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { MultiValue valueNode = GetValueForCustomAttributeArgument(value); - RequireDynamicallyAccessedMembers(_diagnosticContext, valueNode, fieldValue, field.GetDisplayName(), ref result); + RequireDynamicallyAccessedMembers(_diagnosticContext, valueNode, fieldValue, field, ref result); } } @@ -132,7 +132,7 @@ private void RequireDynamicallyAccessedMembers( in DiagnosticContext diagnosticContext, in MultiValue value, ValueWithDynamicallyAccessedMembers targetValue, - string reason, + TypeSystemEntity reason, ref DependencyList? result) { var reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlowOrigin: null, enabled: true); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs index 7ac0815a77c74c..e277683a6ca95f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs @@ -93,7 +93,7 @@ private static void ProcessGenericInstantiation(in DiagnosticContext diagnosticC var genericParameterValue = reflectionMarker.Annotations.GetGenericParameterValue(genericParameter); Debug.Assert(genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None); MultiValue genericArgumentValue = reflectionMarker.Annotations.GetTypeValueFromGenericArgument(genericArgument); - var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, genericParameter.GetDisplayName()); + var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, genericParameter); requireDynamicallyAccessedMembersAction.Invoke(genericArgumentValue, genericParameterValue); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs index 7469d7b0256476..28fb49164e7572 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs @@ -28,7 +28,7 @@ internal partial struct HandleCallAction private readonly ReflectionMarker _reflectionMarker; private ILOpcode _operation; private readonly MethodDesc _callingMethod; - private readonly string _reason; + private readonly MethodDesc _reason; public HandleCallAction( FlowAnnotations annotations, @@ -36,7 +36,7 @@ public HandleCallAction( ReflectionMarker reflectionMarker, in DiagnosticContext diagnosticContext, MethodDesc callingMethod, - string reason) + MethodDesc reason) { _reflectionMarker = reflectionMarker; _operation = operation; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs index 056032d025bfe8..c7b8f85902f059 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs @@ -48,14 +48,15 @@ public ReflectionMarker(Logger logger, NodeFactory factory, FlowAnnotations anno _enabled = enabled; } - internal void MarkTypeForDynamicallyAccessedMembers(in MessageOrigin origin, TypeDesc typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, string reason, bool declaredOnly = false) + internal void MarkTypeForDynamicallyAccessedMembers(in MessageOrigin origin, TypeDesc typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, TypeSystemEntity reason, bool declaredOnly = false) { if (!_enabled) return; + string displayName = reason.GetDisplayName(); foreach (var member in typeDefinition.GetDynamicallyAccessedMembers(requiredMemberTypes, declaredOnly)) { - MarkTypeSystemEntity(origin, member, reason, AccessKind.DynamicallyAccessedMembersMark); + MarkTypeSystemEntity(origin, member, displayName, AccessKind.DynamicallyAccessedMembersMark); } } @@ -83,7 +84,7 @@ internal void MarkTypeSystemEntity(in MessageOrigin origin, TypeSystemEntity ent } } - internal bool TryResolveTypeNameAndMark(string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, string reason, [NotNullWhen(true)] out TypeDesc? type) + internal bool TryResolveTypeNameAndMark(string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, TypeSystemEntity reason, [NotNullWhen(true)] out TypeDesc? type) { ModuleDesc? callingModule = (diagnosticContext.Origin.MemberDefinition.GetOwningType() as MetadataType)?.Module; @@ -102,14 +103,15 @@ internal bool TryResolveTypeNameAndMark(string typeName, in DiagnosticContext di if (_enabled) { + string displayName = reason.GetDisplayName(); foreach (ModuleDesc referencedModule in referencedModules) { // Also add module metadata in case this reference was through a type forward if (Factory.MetadataManager.CanGenerateMetadata(referencedModule.GetGlobalModuleType())) - _dependencies.Add(Factory.ModuleMetadata(referencedModule), reason); + _dependencies.Add(Factory.ModuleMetadata(referencedModule), displayName); } - MarkType(diagnosticContext.Origin, foundType, reason); + MarkType(diagnosticContext.Origin, foundType, displayName); } type = foundType; @@ -143,6 +145,14 @@ internal bool TryResolveTypeNameAndMark(ModuleDesc assembly, string typeName, in return true; } + internal void MarkType(in MessageOrigin origin, TypeDesc type, TypeSystemEntity reason, AccessKind accessKind = AccessKind.Unspecified) + { + if (!_enabled) + return; + + MarkType(origin, type, reason.GetDisplayName(), accessKind); + } + internal void MarkType(in MessageOrigin origin, TypeDesc type, string reason, AccessKind accessKind = AccessKind.Unspecified) { if (!_enabled) @@ -151,6 +161,14 @@ internal void MarkType(in MessageOrigin origin, TypeDesc type, string reason, Ac RootingHelpers.TryGetDependenciesForReflectedType(ref _dependencies, Factory, type, reason); } + internal void MarkMethod(in MessageOrigin origin, MethodDesc method, TypeSystemEntity reason, AccessKind accessKind = AccessKind.Unspecified) + { + if (!_enabled) + return; + + MarkMethod(origin, method, reason.GetDisplayName(), accessKind); + } + internal void MarkMethod(in MessageOrigin origin, MethodDesc method, string reason, AccessKind accessKind = AccessKind.Unspecified) { if (!_enabled) @@ -171,6 +189,14 @@ internal void MarkField(in MessageOrigin origin, FieldDesc field, string reason, RootingHelpers.TryGetDependenciesForReflectedField(ref _dependencies, Factory, field, reason); } + internal void MarkProperty(in MessageOrigin origin, PropertyPseudoDesc property, TypeSystemEntity reason, AccessKind accessKind = AccessKind.Unspecified) + { + if (!_enabled) + return; + + MarkProperty(origin, property, reason.GetDisplayName(), accessKind); + } + internal void MarkProperty(in MessageOrigin origin, PropertyPseudoDesc property, string reason, AccessKind accessKind = AccessKind.Unspecified) { if (!_enabled) @@ -193,50 +219,54 @@ private void MarkEvent(in MessageOrigin origin, EventPseudoDesc @event, string r MarkMethod(origin, @event.RemoveMethod, reason); } - internal void MarkConstructorsOnType(in MessageOrigin origin, TypeDesc type, Func? filter, string reason, BindingFlags? bindingFlags = null) + internal void MarkConstructorsOnType(in MessageOrigin origin, TypeDesc type, Func? filter, TypeSystemEntity reason, BindingFlags? bindingFlags = null) { if (!_enabled) return; + string displayName = reason.GetDisplayName(); foreach (var ctor in type.GetConstructorsOnType(filter, bindingFlags)) - MarkMethod(origin, ctor, reason); + MarkMethod(origin, ctor, displayName); } - internal void MarkFieldsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func filter, string reason, BindingFlags? bindingFlags = BindingFlags.Default) + internal void MarkFieldsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func filter, TypeSystemEntity reason, BindingFlags? bindingFlags = BindingFlags.Default) { if (!_enabled) return; + string displayName = reason.GetDisplayName(); foreach (var field in type.GetFieldsOnTypeHierarchy(filter, bindingFlags)) - MarkField(origin, field, reason); + MarkField(origin, field, displayName); } - internal void MarkPropertiesOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func filter, string reason, BindingFlags? bindingFlags = BindingFlags.Default) + internal void MarkPropertiesOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func filter, TypeSystemEntity reason, BindingFlags? bindingFlags = BindingFlags.Default) { if (!_enabled) return; + string displayName = reason.GetDisplayName(); foreach (var property in type.GetPropertiesOnTypeHierarchy(filter, bindingFlags)) - MarkProperty(origin, property, reason); + MarkProperty(origin, property, displayName); } - internal void MarkEventsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func filter, string reason, BindingFlags? bindingFlags = BindingFlags.Default) + internal void MarkEventsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func filter, TypeSystemEntity reason, BindingFlags? bindingFlags = BindingFlags.Default) { if (!_enabled) return; + string displayName = reason.GetDisplayName(); foreach (var @event in type.GetEventsOnTypeHierarchy(filter, bindingFlags)) - MarkEvent(origin, @event, reason); + MarkEvent(origin, @event, displayName); } - internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type, string reason) + internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type, TypeSystemEntity reason) { if (!_enabled) return; MethodDesc cctor = type.GetStaticConstructor(); if (cctor != null) - MarkMethod(origin, cctor, reason); + MarkMethod(origin, cctor, reason.GetDisplayName()); } internal void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystemEntity entity, AccessKind accessKind = AccessKind.Unspecified) 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 11655bc4ad7b17..1d9ca3783c95fc 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs @@ -171,7 +171,7 @@ public static DependencyList ProcessTypeGetTypeDataflow(NodeFactory factory, Flo // 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, type.BaseType, annotationToApplyToBase, type.GetDisplayName(), declaredOnly: false); + reflectionMarker.MarkTypeForDynamicallyAccessedMembers(origin, type.BaseType, annotationToApplyToBase, type, declaredOnly: false); } // Most of the DynamicallyAccessedMemberTypes don't select members on interfaces. We only need to apply @@ -186,14 +186,14 @@ public static DependencyList ProcessTypeGetTypeDataflow(NodeFactory factory, Flo // 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, iface, annotationToApplyToInterfaces, type.GetDisplayName(), declaredOnly: false); + reflectionMarker.MarkTypeForDynamicallyAccessedMembers(origin, iface, annotationToApplyToInterfaces, type, 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(new MessageOrigin(type), type, annotation, type.GetDisplayName(), declaredOnly: true); + reflectionMarker.MarkTypeForDynamicallyAccessedMembers(new MessageOrigin(type), type, annotation, type, declaredOnly: true); return reflectionMarker.Dependencies; } @@ -235,7 +235,7 @@ protected override MultiValue HandleGetField(MethodIL methodIL, int offset, Fiel return _annotations.GetFieldValue(field); } - private void HandleStoreValueWithDynamicallyAccessedMembers(MethodIL methodIL, int offset, ValueWithDynamicallyAccessedMembers targetValue, MultiValue sourceValue, int? parameterIndex, string reason) + private void HandleStoreValueWithDynamicallyAccessedMembers(MethodIL methodIL, int offset, ValueWithDynamicallyAccessedMembers targetValue, MultiValue sourceValue, int? parameterIndex, TypeSystemEntity reason) { if (targetValue.DynamicallyAccessedMemberTypes != 0) { @@ -245,13 +245,13 @@ private void HandleStoreValueWithDynamicallyAccessedMembers(MethodIL methodIL, i } protected override void HandleStoreField(MethodIL methodIL, int offset, FieldValue field, MultiValue valueToStore, int? parameterIndex) - => HandleStoreValueWithDynamicallyAccessedMembers(methodIL, offset, field, valueToStore, parameterIndex, field.Field.GetDisplayName()); + => HandleStoreValueWithDynamicallyAccessedMembers(methodIL, offset, field, valueToStore, parameterIndex, field.Field); protected override void HandleStoreParameter(MethodIL methodIL, int offset, MethodParameterValue parameter, MultiValue valueToStore, int? parameterIndex) - => HandleStoreValueWithDynamicallyAccessedMembers(methodIL, offset, parameter, valueToStore, parameterIndex, parameter.Parameter.Method.GetDisplayName()); + => HandleStoreValueWithDynamicallyAccessedMembers(methodIL, offset, parameter, valueToStore, parameterIndex, parameter.Parameter.Method.Method); protected override void HandleReturnValue(MethodIL methodIL, int offset, MethodReturnValue returnValue, MultiValue valueToStore) - => HandleStoreValueWithDynamicallyAccessedMembers(methodIL, offset, returnValue, valueToStore, null, returnValue.Method.GetDisplayName()); + => HandleStoreValueWithDynamicallyAccessedMembers(methodIL, offset, returnValue, valueToStore, null, returnValue.Method.Method); protected override void HandleTypeTokenAccess(MethodIL methodIL, int offset, TypeDesc accessedType) { @@ -342,7 +342,7 @@ public static MultiValue HandleCall( RequiresReflectionMethodBodyScannerForCallSite(reflectionMarker.Annotations, calledMethod) || annotatedMethodReturnValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None); - var handleCallAction = new HandleCallAction(reflectionMarker.Annotations, operation, reflectionMarker, diagnosticContext, callingMethodDefinition, calledMethod.GetDisplayName()); + var handleCallAction = new HandleCallAction(reflectionMarker.Annotations, operation, reflectionMarker, diagnosticContext, callingMethodDefinition, calledMethod); var intrinsicId = Intrinsics.GetIntrinsicIdForMethod(calledMethod); if (!handleCallAction.Invoke(calledMethod, instanceValue, argumentValues, intrinsicId, out MultiValue methodReturnValue)) throw new NotImplementedException($"Unhandled intrinsic {intrinsicId}"); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs index 47860a02eaf6f4..0dc20bd68ff8a4 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs @@ -13,12 +13,12 @@ namespace ILLink.Shared.TrimAnalysis internal partial struct RequireDynamicallyAccessedMembersAction { private readonly ReflectionMarker _reflectionMarker; - private readonly string _reason; + private readonly TypeSystemEntity _reason; public RequireDynamicallyAccessedMembersAction( ReflectionMarker reflectionMarker, in DiagnosticContext diagnosticContext, - string reason) + TypeSystemEntity reason) { _reflectionMarker = reflectionMarker; _diagnosticContext = diagnosticContext; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisAssignmentPattern.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisAssignmentPattern.cs index 89cebd2e73586b..de8c307e2de6ff 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisAssignmentPattern.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisAssignmentPattern.cs @@ -7,6 +7,8 @@ using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; +using Internal.TypeSystem; + using MultiValue = ILLink.Shared.DataFlow.ValueSet; #nullable enable @@ -22,9 +24,9 @@ public readonly record struct TrimAnalysisAssignmentPattern // For assignment of a method parameter, we store the parameter index to disambiguate // assignments from different out parameters of a single method call. public int? ParameterIndex { get; init; } - internal string Reason { get; init; } + internal TypeSystemEntity Reason { get; init; } - internal TrimAnalysisAssignmentPattern(MultiValue source, MultiValue target, MessageOrigin origin, int? parameterIndex, string reason) + internal TrimAnalysisAssignmentPattern(MultiValue source, MultiValue target, MessageOrigin origin, int? parameterIndex, TypeSystemEntity reason) { Source = source.DeepCopy(); Target = target.DeepCopy();