Skip to content

Commit c104939

Browse files
authored
Proper type name parser for native AOT compiler (#83657)
* Proper type name parser for native AOT compiler * Track failure of CA search rules in the type name parser * Fix tests * Suppress new native AOT warning for libraries tests Co-authored-by: vitek-karas <10670590+vitek-karas@users.noreply.github.com> Fixes #72833
1 parent 6b0a0f3 commit c104939

File tree

13 files changed

+206
-150
lines changed

13 files changed

+206
-150
lines changed

eng/testing/tests.singlefile.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<IlcSdkPath>$(CoreCLRAotSdkDir)</IlcSdkPath>
3030
<IlcFrameworkPath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkPath>
3131
<IlcFrameworkNativePath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkNativePath>
32-
<NoWarn>$(NoWarn);IL1005;IL3000;IL3001;IL3002;IL3003</NoWarn>
32+
<NoWarn>$(NoWarn);IL1005;IL2105;IL3000;IL3001;IL3002;IL3003</NoWarn>
3333
<TrimMode>partial</TrimMode>
3434
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
3535
<SuppressAotAnalysisWarnings>true</SuppressAotAnalysisWarnings>

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Diagnostics;
67
using System.Diagnostics.CodeAnalysis;
78
using System.Reflection;
@@ -70,27 +71,34 @@ internal void MarkTypeSystemEntity(in MessageOrigin origin, TypeSystemEntity ent
7071
MarkEvent(origin, @event, reason);
7172
break;
7273
// case InterfaceImplementation
73-
// Nothing to do currently as Native AOT will presere all interfaces on a preserved type
74+
// Nothing to do currently as Native AOT will preserve all interfaces on a preserved type
7475
}
7576
}
7677

7778
internal bool TryResolveTypeNameAndMark(string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, string reason, [NotNullWhen(true)] out TypeDesc? type)
7879
{
7980
ModuleDesc? callingModule = ((diagnosticContext.Origin.MemberDefinition as MethodDesc)?.OwningType as MetadataType)?.Module;
8081

81-
// NativeAOT doesn't have a fully capable type name resolver yet
82-
// Once this is implemented don't forget to wire up marking of type forwards which are used in generic parameters
83-
if (!DependencyAnalysis.ReflectionMethodBodyScanner.ResolveType(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context, out TypeDesc foundType, out ModuleDesc referenceModule))
82+
List<ModuleDesc> referencedModules = new();
83+
TypeDesc foundType = System.Reflection.TypeNameParser.ResolveType(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context,
84+
referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary);
85+
if (foundType == null)
8486
{
87+
if (needsAssemblyName && typeWasNotFoundInAssemblyNorBaseLibrary)
88+
diagnosticContext.AddDiagnostic(DiagnosticId.TypeWasNotFoundInAssemblyNorBaseLibrary, typeName);
89+
8590
type = default;
8691
return false;
8792
}
8893

8994
if (_enabled)
9095
{
91-
// Also add module metadata in case this reference was through a type forward
92-
if (Factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
93-
_dependencies.Add(Factory.ModuleMetadata(referenceModule), reason);
96+
foreach (ModuleDesc referencedModule in referencedModules)
97+
{
98+
// Also add module metadata in case this reference was through a type forward
99+
if (Factory.MetadataManager.CanGenerateMetadata(referencedModule.GetGlobalModuleType()))
100+
_dependencies.Add(Factory.ModuleMetadata(referencedModule), reason);
101+
}
94102

95103
MarkType(diagnosticContext.Origin, foundType, reason);
96104
}

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectionMethodBodyScanner.cs

Lines changed: 0 additions & 99 deletions
This file was deleted.
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Generic;
5+
using System.Diagnostics;
6+
using System.IO;
7+
using System.Reflection;
8+
9+
using Internal.TypeSystem;
10+
11+
namespace System.Reflection
12+
{
13+
internal unsafe ref partial struct TypeNameParser
14+
{
15+
private TypeSystemContext _context;
16+
private ModuleDesc _callingModule;
17+
private List<ModuleDesc> _referencedModules;
18+
private bool _typeWasNotFoundInAssemblyNorBaseLibrary;
19+
20+
public static TypeDesc ResolveType(string name, ModuleDesc callingModule,
21+
TypeSystemContext context, List<ModuleDesc> referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary)
22+
{
23+
var parser = new System.Reflection.TypeNameParser(name)
24+
{
25+
_context = context,
26+
_callingModule = callingModule,
27+
_referencedModules = referencedModules
28+
};
29+
30+
TypeDesc result = parser.Parse()?.Value;
31+
32+
typeWasNotFoundInAssemblyNorBaseLibrary = parser._typeWasNotFoundInAssemblyNorBaseLibrary;
33+
return result;
34+
}
35+
36+
private sealed class Type
37+
{
38+
public Type(TypeDesc type) => Value = type;
39+
public TypeDesc Value { get; }
40+
41+
public Type MakeArrayType() => new Type(Value.MakeArrayType());
42+
public Type MakeArrayType(int rank) => new Type(Value.MakeArrayType(rank));
43+
public Type MakePointerType() => new Type(Value.MakePointerType());
44+
public Type MakeByRefType() => new Type(Value.MakeByRefType());
45+
46+
public Type MakeGenericType(Type[] typeArguments)
47+
{
48+
TypeDesc[] instantiation = new TypeDesc[typeArguments.Length];
49+
for (int i = 0; i < typeArguments.Length; i++)
50+
instantiation[i] = typeArguments[i].Value;
51+
return new Type(((MetadataType)Value).MakeInstantiatedType(instantiation));
52+
}
53+
}
54+
55+
private static bool CheckTopLevelAssemblyQualifiedName() => true;
56+
57+
private Type GetType(string typeName, ReadOnlySpan<string> nestedTypeNames, string assemblyNameIfAny)
58+
{
59+
ModuleDesc module;
60+
61+
if (assemblyNameIfAny != null)
62+
{
63+
module = (TryParseAssemblyName(assemblyNameIfAny) is AssemblyName an) ?
64+
_context.ResolveAssembly(an, throwIfNotFound: false) : null;
65+
}
66+
else
67+
{
68+
module = _callingModule;
69+
}
70+
71+
Type type;
72+
73+
if (module != null)
74+
{
75+
type = GetTypeCore(module, typeName, nestedTypeNames);
76+
if (type != null)
77+
{
78+
_referencedModules?.Add(module);
79+
return type;
80+
}
81+
}
82+
83+
// If it didn't resolve and wasn't assembly-qualified, we also try core library
84+
if (assemblyNameIfAny == null)
85+
{
86+
type = GetTypeCore(_context.SystemModule, typeName, nestedTypeNames);
87+
if (type != null)
88+
{
89+
_referencedModules?.Add(_context.SystemModule);
90+
return type;
91+
}
92+
93+
_typeWasNotFoundInAssemblyNorBaseLibrary = true;
94+
}
95+
96+
return null;
97+
}
98+
99+
private static AssemblyName TryParseAssemblyName(string assemblyName)
100+
{
101+
try
102+
{
103+
return new AssemblyName(assemblyName);
104+
}
105+
catch (FileLoadException)
106+
{
107+
return null;
108+
}
109+
catch (ArgumentException)
110+
{
111+
return null;
112+
}
113+
}
114+
115+
private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan<string> nestedTypeNames)
116+
{
117+
string typeNamespace, name;
118+
119+
int separator = typeName.LastIndexOf('.');
120+
if (separator <= 0)
121+
{
122+
typeNamespace = "";
123+
name = typeName;
124+
}
125+
else
126+
{
127+
if (typeName[separator - 1] == '.')
128+
separator--;
129+
typeNamespace = typeName.Substring(0, separator);
130+
name = typeName.Substring(separator + 1);
131+
}
132+
133+
MetadataType type = module.GetType(typeNamespace, name, throwIfNotFound: false);
134+
if (type == null)
135+
return null;
136+
137+
for (int i = 0; i < nestedTypeNames.Length; i++)
138+
{
139+
type = type.GetNestedType(nestedTypeNames[i]);
140+
if (type == null)
141+
return null;
142+
}
143+
144+
return new Type(type);
145+
}
146+
147+
private static void ParseError()
148+
{
149+
}
150+
}
151+
}

src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
</ItemGroup>
3131

3232
<ItemGroup>
33+
<Compile Include="..\..\..\..\libraries\Common\src\System\Reflection\TypeNameParser.cs">
34+
<Link>TypeNameParser.cs</Link>
35+
</Compile>
36+
<Compile Include="..\..\..\..\libraries\Common\src\System\Text\ValueStringBuilder.cs">
37+
<Link>ValueStringBuilder.cs</Link>
38+
</Compile>
3339
<Compile Include="..\..\Common\TypeSystem\IL\DelegateInfo.cs">
3440
<Link>IL\DelegateInfo.cs</Link>
3541
</Compile>
@@ -406,7 +412,6 @@
406412
<Compile Include="Compiler\DependencyAnalysis\ReflectedFieldNode.cs" />
407413
<Compile Include="Compiler\DependencyAnalysis\ReflectedTypeNode.cs" />
408414
<Compile Include="Compiler\DependencyAnalysis\ReflectionInvokeSupportDependencyAlgorithm.cs" />
409-
<Compile Include="Compiler\DependencyAnalysis\ReflectionMethodBodyScanner.cs" />
410415
<Compile Include="Compiler\DependencyAnalysis\StructMarshallingDataNode.cs" />
411416
<Compile Include="Compiler\DependencyAnalysis\Target_ARM64\ARM64TentativeMethodNode.cs" />
412417
<Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMTentativeMethodNode.cs" />
@@ -416,6 +421,7 @@
416421
<Compile Include="Compiler\DependencyAnalysis\TentativeInstanceMethodNode.cs" />
417422
<Compile Include="Compiler\DependencyAnalysis\TentativeMethodNode.cs" />
418423
<Compile Include="Compiler\DependencyAnalysis\TrimmingDescriptorNode.cs" />
424+
<Compile Include="Compiler\DependencyAnalysis\TypeNameParser.cs" />
419425
<Compile Include="Compiler\DependencyAnalysis\VariantInterfaceMethodUseNode.cs" />
420426
<Compile Include="Compiler\DependencyAnalysis\CustomAttributeBasedDependencyAlgorithm.cs" />
421427
<Compile Include="Compiler\DependencyAnalysis\FieldMetadataNode.cs" />

src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,29 +83,22 @@ internal static partial class X509ResourceClient
8383
// the latter can't in turn have an explicit dependency on the former.
8484

8585
// Get the relevant types needed.
86-
Type? socketsHttpHandlerType = Type.GetType("System.Net.Http.SocketsHttpHandler, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
87-
Type? httpMessageHandlerType = Type.GetType("System.Net.Http.HttpMessageHandler, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
88-
Type? httpClientType = Type.GetType("System.Net.Http.HttpClient, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
89-
Type? httpRequestMessageType = Type.GetType("System.Net.Http.HttpRequestMessage, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
90-
Type? httpResponseMessageType = Type.GetType("System.Net.Http.HttpResponseMessage, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
91-
Type? httpResponseHeadersType = Type.GetType("System.Net.Http.Headers.HttpResponseHeaders, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
92-
Type? httpContentType = Type.GetType("System.Net.Http.HttpContent, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
86+
Type? socketsHttpHandlerType = Type.GetType("System.Net.Http.SocketsHttpHandler, System.Net.Http", throwOnError: false);
87+
Type? httpMessageHandlerType = Type.GetType("System.Net.Http.HttpMessageHandler, System.Net.Http", throwOnError: false);
88+
Type? httpClientType = Type.GetType("System.Net.Http.HttpClient, System.Net.Http", throwOnError: false);
89+
Type? httpRequestMessageType = Type.GetType("System.Net.Http.HttpRequestMessage, System.Net.Http", throwOnError: false);
90+
Type? httpResponseMessageType = Type.GetType("System.Net.Http.HttpResponseMessage, System.Net.Http", throwOnError: false);
91+
Type? httpResponseHeadersType = Type.GetType("System.Net.Http.Headers.HttpResponseHeaders, System.Net.Http", throwOnError: false);
92+
Type? httpContentType = Type.GetType("System.Net.Http.HttpContent, System.Net.Http", throwOnError: false);
93+
Type? taskOfHttpResponseMessageType = Type.GetType("System.Threading.Tasks.Task`1[[System.Net.Http.HttpResponseMessage, System.Net.Http]], System.Runtime", throwOnError: false);
9394

9495
if (socketsHttpHandlerType == null || httpMessageHandlerType == null || httpClientType == null || httpRequestMessageType == null ||
95-
httpResponseMessageType == null || httpResponseHeadersType == null || httpContentType == null)
96+
httpResponseMessageType == null || httpResponseHeadersType == null || httpContentType == null || taskOfHttpResponseMessageType == null)
9697
{
9798
Debug.Fail("Unable to load required type.");
9899
return null;
99100
}
100101

101-
// Workaround until https://github.com/dotnet/runtime/issues/72833 is fixed
102-
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
103-
Justification = "The type HttpResponseMessage is a reference type")]
104-
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
105-
static Type GetTaskOfHttpResponseMessageType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? httpResponseMessageType) => typeof(Task<>).MakeGenericType(httpResponseMessageType!);
106-
107-
Type taskOfHttpResponseMessageType = GetTaskOfHttpResponseMessageType(httpResponseMessageType);
108-
109102
// Get the methods on those types.
110103
ConstructorInfo? socketsHttpHandlerCtor = socketsHttpHandlerType.GetConstructor(Type.EmptyTypes);
111104
PropertyInfo? pooledConnectionIdleTimeoutProp = socketsHttpHandlerType.GetProperty("PooledConnectionIdleTimeout");

0 commit comments

Comments
 (0)