-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Integrate changes from NativeAOT branch
- Loading branch information
1 parent
c1767af
commit c7901ed
Showing
10 changed files
with
755 additions
and
341 deletions.
There are no files selected for viewing
This file contains 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
51 changes: 51 additions & 0 deletions
51
src/coreclr/tools/Common/Compiler/Logging/CompilerGeneratedState.cs
This file contains 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,51 @@ | ||
// 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.Collections.Generic; | ||
|
||
using Internal.TypeSystem; | ||
using Internal.TypeSystem.Ecma; | ||
|
||
namespace ILCompiler.Logging | ||
{ | ||
// Currently this is implemented using heuristics | ||
public class CompilerGeneratedState | ||
{ | ||
private static bool HasRoslynCompilerGeneratedName(DefType type) => | ||
type.Name.Contains('<') || (type.ContainingType != null && HasRoslynCompilerGeneratedName(type.ContainingType)); | ||
|
||
public static MethodDesc GetUserDefinedMethodForCompilerGeneratedMember(MethodDesc sourceMember) | ||
{ | ||
var compilerGeneratedType = sourceMember.OwningType.GetTypeDefinition() as EcmaType; | ||
if (compilerGeneratedType == null) | ||
return null; | ||
|
||
// Only handle async or iterator state machine | ||
// So go to the declaring type and check if it's compiler generated (as a perf optimization) | ||
if (!HasRoslynCompilerGeneratedName(compilerGeneratedType) || compilerGeneratedType.ContainingType == null) | ||
return null; | ||
|
||
// Now go to its declaring type and search all methods to find the one which points to the type as its | ||
// state machine implementation. | ||
foreach (EcmaMethod method in compilerGeneratedType.ContainingType.GetMethods()) | ||
{ | ||
var decodedAttribute = method.GetDecodedCustomAttribute("System.Runtime.CompilerServices", "AsyncIteratorStateMachineAttribute") | ||
?? method.GetDecodedCustomAttribute("System.Runtime.CompilerServices", "AsyncStateMachineAttribute") | ||
?? method.GetDecodedCustomAttribute("System.Runtime.CompilerServices", "IteratorStateMachineAttribute"); | ||
|
||
if (!decodedAttribute.HasValue) | ||
continue; | ||
|
||
if (decodedAttribute.Value.FixedArguments.Length != 1 | ||
|| decodedAttribute.Value.FixedArguments[0].Value is not TypeDesc stateMachineType) | ||
continue; | ||
|
||
if (stateMachineType == compilerGeneratedType) | ||
return method; | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
} |
This file contains 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 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
94 changes: 94 additions & 0 deletions
94
src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/CompilerGeneratedState.cs
This file contains 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,94 @@ | ||
// 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.Collections.Generic; | ||
using Mono.Cecil; | ||
|
||
namespace Mono.Linker | ||
{ | ||
// Currently this is implemented using heuristics | ||
public class CompilerGeneratedState | ||
{ | ||
readonly LinkContext _context; | ||
readonly Dictionary<TypeDefinition, MethodDefinition> _compilerGeneratedTypeToUserCodeMethod; | ||
readonly HashSet<TypeDefinition> _typesWithPopulatedCache; | ||
|
||
public CompilerGeneratedState (LinkContext context) | ||
{ | ||
_context = context; | ||
_compilerGeneratedTypeToUserCodeMethod = new Dictionary<TypeDefinition, MethodDefinition> (); | ||
_typesWithPopulatedCache = new HashSet<TypeDefinition> (); | ||
} | ||
|
||
static bool HasRoslynCompilerGeneratedName (TypeDefinition type) => | ||
type.Name.Contains ('<') || (type.DeclaringType != null && HasRoslynCompilerGeneratedName (type.DeclaringType)); | ||
|
||
void PopulateCacheForType (TypeDefinition type) | ||
{ | ||
// Avoid repeat scans of the same type | ||
if (!_typesWithPopulatedCache.Add (type)) | ||
return; | ||
|
||
foreach (MethodDefinition method in type.Methods) { | ||
if (!method.HasCustomAttributes) | ||
continue; | ||
|
||
foreach (var attribute in method.CustomAttributes) { | ||
if (attribute.AttributeType.Namespace != "System.Runtime.CompilerServices") | ||
continue; | ||
|
||
switch (attribute.AttributeType.Name) { | ||
case "AsyncIteratorStateMachineAttribute": | ||
case "AsyncStateMachineAttribute": | ||
case "IteratorStateMachineAttribute": | ||
TypeDefinition stateMachineType = GetFirstConstructorArgumentAsType (attribute); | ||
if (stateMachineType != null) { | ||
if (!_compilerGeneratedTypeToUserCodeMethod.TryAdd (stateMachineType, method)) { | ||
var alreadyAssociatedMethod = _compilerGeneratedTypeToUserCodeMethod[stateMachineType]; | ||
_context.LogWarning ( | ||
$"Methods '{method.GetDisplayName ()}' and '{alreadyAssociatedMethod.GetDisplayName ()}' are both associated with state machine type '{stateMachineType.GetDisplayName ()}'. This is currently unsupported and may lead to incorrectly reported warnings.", | ||
2107, | ||
new MessageOrigin (method), | ||
MessageSubCategory.TrimAnalysis); | ||
} | ||
} | ||
|
||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
static TypeDefinition GetFirstConstructorArgumentAsType (CustomAttribute attribute) | ||
{ | ||
if (!attribute.HasConstructorArguments) | ||
return null; | ||
|
||
return attribute.ConstructorArguments[0].Value as TypeDefinition; | ||
} | ||
|
||
public MethodDefinition GetUserDefinedMethodForCompilerGeneratedMember (IMemberDefinition sourceMember) | ||
{ | ||
if (sourceMember == null) | ||
return null; | ||
|
||
TypeDefinition compilerGeneratedType = (sourceMember as TypeDefinition) ?? sourceMember.DeclaringType; | ||
if (_compilerGeneratedTypeToUserCodeMethod.TryGetValue (compilerGeneratedType, out MethodDefinition userDefinedMethod)) | ||
return userDefinedMethod; | ||
|
||
// Only handle async or iterator state machine | ||
// So go to the declaring type and check if it's compiler generated (as a perf optimization) | ||
if (!HasRoslynCompilerGeneratedName (compilerGeneratedType) || compilerGeneratedType.DeclaringType == null) | ||
return null; | ||
|
||
// Now go to its declaring type and search all methods to find the one which points to the type as its | ||
// state machine implementation. | ||
PopulateCacheForType (compilerGeneratedType.DeclaringType); | ||
if (_compilerGeneratedTypeToUserCodeMethod.TryGetValue (compilerGeneratedType, out userDefinedMethod)) | ||
return userDefinedMethod; | ||
|
||
return null; | ||
} | ||
} | ||
} |
Oops, something went wrong.