-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Linker to NativeAOT sync #71485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Linker to NativeAOT sync #71485
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
9e5dd8f
First
vitek-karas 13e6565
Progress
vitek-karas 59e5ddd
Small fix
vitek-karas 6702417
Improvements to warning suppression and general cleanup of diagnostic…
vitek-karas 56db859
Progress on CompilerGeneratedState
vitek-karas b9eac18
Finish CompilerGeneratedState port (at least first pass)
vitek-karas 177de44
Make the simple stuff work
vitek-karas 222acda
Fixes
vitek-karas d772322
Formatting
vitek-karas 1cd000f
Formatting
vitek-karas c34901f
Fixes - rewrite compiler generated state
vitek-karas 38520ce
Fixes
vitek-karas f29afe0
Cleanup and fixes
vitek-karas 10bbc6d
PR Feedback - just minor tweaks
vitek-karas 53800b7
Port almost latest linker changes
vitek-karas 0da4638
Merge branch 'main' into LinkerToAotSync2
vitek-karas af6d00b
Mostly PR feedback and small cleanup
vitek-karas 3a48d93
Merge branch 'LinkerToAotSync2' of https://github.com/vitek-karas/run…
vitek-karas db89134
Merge branch 'main' into LinkerToAotSync2
vitek-karas d39a7f7
Ignore single-file warnings in AOT tests
vitek-karas 381e077
Merge branch 'LinkerToAotSync2' of https://github.com/vitek-karas/run…
vitek-karas 739a5c1
Fixes a bug when compiler generated code would not run DataFlow.
vitek-karas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
140 changes: 140 additions & 0 deletions
140
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| // 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.Immutable; | ||
| using System.Diagnostics; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Reflection.Metadata; | ||
|
|
||
| using ILCompiler.DependencyAnalysis; | ||
| using ILCompiler.Logging; | ||
|
|
||
| using ILLink.Shared.TrimAnalysis; | ||
|
|
||
| using Internal.TypeSystem; | ||
|
|
||
| using CustomAttributeValue = System.Reflection.Metadata.CustomAttributeValue<Internal.TypeSystem.TypeDesc>; | ||
| using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList; | ||
| using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>; | ||
|
|
||
| #nullable enable | ||
|
|
||
| namespace ILCompiler.Dataflow | ||
| { | ||
| public readonly struct AttributeDataFlow | ||
| { | ||
| readonly Logger _logger; | ||
| readonly NodeFactory _factory; | ||
| readonly FlowAnnotations _annotations; | ||
| readonly MessageOrigin _origin; | ||
|
|
||
| public AttributeDataFlow(Logger logger, NodeFactory factory, FlowAnnotations annotations, in MessageOrigin origin) | ||
| { | ||
| _annotations = annotations; | ||
| _factory = factory; | ||
| _logger = logger; | ||
| _origin = origin; | ||
| } | ||
|
|
||
| public DependencyList? ProcessAttributeDataflow(MethodDesc method, CustomAttributeValue arguments) | ||
| { | ||
| DependencyList? result = null; | ||
|
|
||
| // First do the dataflow for the constructor parameters if necessary. | ||
| if (_annotations.RequiresDataflowAnalysis(method)) | ||
| { | ||
| var builder = ImmutableArray.CreateBuilder<object?>(arguments.FixedArguments.Length); | ||
| foreach (var argument in arguments.FixedArguments) | ||
| { | ||
| builder.Add(argument.Value); | ||
| } | ||
|
|
||
| ProcessAttributeDataflow(method, builder.ToImmutableArray(), ref result); | ||
| } | ||
|
|
||
| // Named arguments next | ||
| TypeDesc attributeType = method.OwningType; | ||
| foreach (var namedArgument in arguments.NamedArguments) | ||
| { | ||
| if (namedArgument.Kind == CustomAttributeNamedArgumentKind.Field) | ||
| { | ||
| FieldDesc field = attributeType.GetField(namedArgument.Name); | ||
| if (field != null) | ||
| { | ||
| ProcessAttributeDataflow(field, namedArgument.Value, ref result); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| Debug.Assert(namedArgument.Kind == CustomAttributeNamedArgumentKind.Property); | ||
| PropertyPseudoDesc property = ((MetadataType)attributeType).GetProperty(namedArgument.Name, null); | ||
| MethodDesc setter = property.SetMethod; | ||
| if (setter != null && setter.Signature.Length > 0 && !setter.Signature.IsStatic) | ||
| { | ||
| ProcessAttributeDataflow(setter, ImmutableArray.Create(namedArgument.Value), ref result); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| void ProcessAttributeDataflow(MethodDesc method, ImmutableArray<object?> arguments, ref DependencyList? result) | ||
| { | ||
| for (int i = 0; i < method.Signature.Length; i++) | ||
| { | ||
| var parameterValue = _annotations.GetMethodParameterValue(method, i); | ||
| if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) | ||
| { | ||
| MultiValue value = GetValueForCustomAttributeArgument(arguments[i]); | ||
| var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _logger); | ||
| RequireDynamicallyAccessedMembers(diagnosticContext, value, parameterValue, parameterValue.ParameterOrigin, ref result); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public void ProcessAttributeDataflow(FieldDesc field, object? value, ref DependencyList? result) | ||
| { | ||
| var fieldValueCandidate = _annotations.GetFieldValue(field); | ||
| if (fieldValueCandidate is ValueWithDynamicallyAccessedMembers fieldValue | ||
| && fieldValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) | ||
| { | ||
| MultiValue valueNode = GetValueForCustomAttributeArgument(value); | ||
| var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _logger); | ||
| RequireDynamicallyAccessedMembers(diagnosticContext, valueNode, fieldValue, new FieldOrigin(field), ref result); | ||
| } | ||
| } | ||
|
|
||
| MultiValue GetValueForCustomAttributeArgument(object? argument) | ||
| => argument switch | ||
| { | ||
| TypeDesc td => new SystemTypeValue(td), | ||
| string str => new KnownStringValue(str), | ||
| null => NullValue.Instance, | ||
| // We shouldn't have gotten a None annotation from flow annotations since only string/Type can have annotations | ||
| _ => throw new InvalidOperationException() | ||
| }; | ||
|
|
||
| void RequireDynamicallyAccessedMembers( | ||
| in DiagnosticContext diagnosticContext, | ||
| in MultiValue value, | ||
| ValueWithDynamicallyAccessedMembers targetValue, | ||
| Origin memberWithRequirements, | ||
| ref DependencyList? result) | ||
| { | ||
| var reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlow: false, enabled: true); | ||
| var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, memberWithRequirements); | ||
| requireDynamicallyAccessedMembersAction.Invoke(value, targetValue); | ||
|
|
||
| if (result == null) | ||
| { | ||
| result = reflectionMarker.Dependencies; | ||
| } | ||
| else | ||
| { | ||
| result.AddRange(reflectionMarker.Dependencies); | ||
| } | ||
| } | ||
| } | ||
| } | ||
77 changes: 77 additions & 0 deletions
77
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedCallGraph.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| // 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 Internal.TypeSystem; | ||
| using Internal.TypeSystem.Ecma; | ||
|
|
||
| #nullable enable | ||
|
|
||
| namespace ILCompiler.Dataflow | ||
| { | ||
| sealed class CompilerGeneratedCallGraph | ||
| { | ||
| readonly Dictionary<TypeSystemEntity, HashSet<TypeSystemEntity>> _callGraph; | ||
|
|
||
| public CompilerGeneratedCallGraph() => _callGraph = new Dictionary<TypeSystemEntity, HashSet<TypeSystemEntity>>(); | ||
|
|
||
| void TrackCallInternal(TypeSystemEntity fromMember, TypeSystemEntity toMember) | ||
| { | ||
| if (!_callGraph.TryGetValue(fromMember, out HashSet<TypeSystemEntity>? toMembers)) | ||
| { | ||
| toMembers = new HashSet<TypeSystemEntity>(); | ||
| _callGraph.Add(fromMember, toMembers); | ||
| } | ||
| toMembers.Add(toMember); | ||
| } | ||
|
|
||
| public void TrackCall(MethodDesc fromMethod, MethodDesc toMethod) | ||
vitek-karas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| Debug.Assert(fromMethod.IsTypicalMethodDefinition); | ||
| Debug.Assert(toMethod.IsTypicalMethodDefinition); | ||
| Debug.Assert(CompilerGeneratedNames.IsLambdaOrLocalFunction(toMethod.Name)); | ||
| TrackCallInternal(fromMethod, toMethod); | ||
| } | ||
|
|
||
| public void TrackCall(MethodDesc fromMethod, DefType toType) | ||
| { | ||
| Debug.Assert(fromMethod.IsTypicalMethodDefinition); | ||
| Debug.Assert(toType.IsTypeDefinition); | ||
| Debug.Assert(CompilerGeneratedNames.IsStateMachineType(toType.Name)); | ||
| TrackCallInternal(fromMethod, toType); | ||
| } | ||
|
|
||
| public void TrackCall(DefType fromType, MethodDesc toMethod) | ||
| { | ||
| Debug.Assert(fromType.IsTypeDefinition); | ||
| Debug.Assert(toMethod.IsTypicalMethodDefinition); | ||
| Debug.Assert(CompilerGeneratedNames.IsStateMachineType(fromType.Name)); | ||
| Debug.Assert(CompilerGeneratedNames.IsLambdaOrLocalFunction(toMethod.Name)); | ||
| TrackCallInternal(fromType, toMethod); | ||
| } | ||
|
|
||
| public IEnumerable<TypeSystemEntity> GetReachableMembers(MethodDesc start) | ||
| { | ||
| Queue<TypeSystemEntity> queue = new(); | ||
| HashSet<TypeSystemEntity> visited = new(); | ||
| visited.Add(start); | ||
| queue.Enqueue(start); | ||
| while (queue.TryDequeue(out TypeSystemEntity? method)) | ||
| { | ||
| if (!_callGraph.TryGetValue(method, out HashSet<TypeSystemEntity>? callees)) | ||
| continue; | ||
|
|
||
| foreach (var callee in callees) | ||
| { | ||
| if (visited.Add(callee)) | ||
| { | ||
| queue.Enqueue(callee); | ||
| yield return callee; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
74 changes: 74 additions & 0 deletions
74
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedNames.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| #nullable enable | ||
|
|
||
| namespace ILCompiler.Dataflow | ||
| { | ||
| sealed class CompilerGeneratedNames | ||
| { | ||
| internal static bool IsGeneratedMemberName(string memberName) | ||
| { | ||
| return memberName.Length > 0 && memberName[0] == '<'; | ||
| } | ||
|
|
||
| internal static bool IsLambdaDisplayClass(string className) | ||
| { | ||
| if (!IsGeneratedMemberName(className)) | ||
| return false; | ||
|
|
||
| // This is true for static lambdas (which are emitted into a class like <>c) | ||
| // and for instance lambdas (which are emitted into a class like <>c__DisplayClass1_0) | ||
| return className.StartsWith("<>c"); | ||
| } | ||
|
|
||
| internal static bool IsStateMachineType(string typeName) | ||
vitek-karas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| if (!IsGeneratedMemberName(typeName)) | ||
| return false; | ||
|
|
||
| // State machines are generated into types with names like <OwnerMethodName>d__0 | ||
| // Or if its nested in a local function the name will look like <<OwnerMethodName>g__Local>d and so on | ||
| int i = typeName.LastIndexOf('>'); | ||
| if (i == -1) | ||
| return false; | ||
|
|
||
| return typeName.Length > i + 1 && typeName[i + 1] == 'd'; | ||
| } | ||
|
|
||
| internal static bool IsGeneratedType(string name) => IsStateMachineType(name) || IsLambdaDisplayClass(name); | ||
|
|
||
| internal static bool IsLambdaOrLocalFunction(string methodName) => IsLambdaMethod(methodName) || IsLocalFunction(methodName); | ||
|
|
||
| // Lambda methods have generated names like "<UserMethod>b__0_1" where "UserMethod" is the name | ||
| // of the original user code that contains the lambda method declaration. | ||
| internal static bool IsLambdaMethod(string methodName) | ||
| { | ||
| if (!IsGeneratedMemberName(methodName)) | ||
| return false; | ||
|
|
||
| int i = methodName.IndexOf('>', 1); | ||
| if (i == -1) | ||
| return false; | ||
|
|
||
| // Ignore the method ordinal/generation and lambda ordinal/generation. | ||
| return methodName.Length > i + 1 && methodName[i + 1] == 'b'; | ||
| } | ||
|
|
||
| // Local functions have generated names like "<UserMethod>g__LocalFunction|0_1" where "UserMethod" is the name | ||
| // of the original user code that contains the lambda method declaration, and "LocalFunction" is the name of | ||
| // the local function. | ||
| internal static bool IsLocalFunction(string methodName) | ||
| { | ||
| if (!IsGeneratedMemberName(methodName)) | ||
| return false; | ||
|
|
||
| int i = methodName.IndexOf('>', 1); | ||
| if (i == -1) | ||
| return false; | ||
|
|
||
| // Ignore the method ordinal/generation and local function ordinal/generation. | ||
| return methodName.Length > i + 1 && methodName[i + 1] == 'g'; | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.