Skip to content

Commit

Permalink
Proper type name parser for native AOT compiler (#83657)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

Fixes #72833
  • Loading branch information
jkotas authored Mar 30, 2023
1 parent 6b0a0f3 commit c104939
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 150 deletions.
2 changes: 1 addition & 1 deletion eng/testing/tests.singlefile.targets
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<IlcSdkPath>$(CoreCLRAotSdkDir)</IlcSdkPath>
<IlcFrameworkPath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkPath>
<IlcFrameworkNativePath>$(NetCoreAppCurrentTestHostSharedFrameworkPath)</IlcFrameworkNativePath>
<NoWarn>$(NoWarn);IL1005;IL3000;IL3001;IL3002;IL3003</NoWarn>
<NoWarn>$(NoWarn);IL1005;IL2105;IL3000;IL3001;IL3002;IL3003</NoWarn>
<TrimMode>partial</TrimMode>
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
<SuppressAotAnalysisWarnings>true</SuppressAotAnalysisWarnings>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
Expand Down Expand Up @@ -70,27 +71,34 @@ internal void MarkTypeSystemEntity(in MessageOrigin origin, TypeSystemEntity ent
MarkEvent(origin, @event, reason);
break;
// case InterfaceImplementation
// Nothing to do currently as Native AOT will presere all interfaces on a preserved type
// Nothing to do currently as Native AOT will preserve all interfaces on a preserved type
}
}

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

// NativeAOT doesn't have a fully capable type name resolver yet
// Once this is implemented don't forget to wire up marking of type forwards which are used in generic parameters
if (!DependencyAnalysis.ReflectionMethodBodyScanner.ResolveType(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context, out TypeDesc foundType, out ModuleDesc referenceModule))
List<ModuleDesc> referencedModules = new();
TypeDesc foundType = System.Reflection.TypeNameParser.ResolveType(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context,
referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary);
if (foundType == null)
{
if (needsAssemblyName && typeWasNotFoundInAssemblyNorBaseLibrary)
diagnosticContext.AddDiagnostic(DiagnosticId.TypeWasNotFoundInAssemblyNorBaseLibrary, typeName);

type = default;
return false;
}

if (_enabled)
{
// Also add module metadata in case this reference was through a type forward
if (Factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
_dependencies.Add(Factory.ModuleMetadata(referenceModule), reason);
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);
}

MarkType(diagnosticContext.Origin, foundType, reason);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// 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.Reflection;

using Internal.TypeSystem;

namespace System.Reflection
{
internal unsafe ref partial struct TypeNameParser
{
private TypeSystemContext _context;
private ModuleDesc _callingModule;
private List<ModuleDesc> _referencedModules;
private bool _typeWasNotFoundInAssemblyNorBaseLibrary;

public static TypeDesc ResolveType(string name, ModuleDesc callingModule,
TypeSystemContext context, List<ModuleDesc> referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary)
{
var parser = new System.Reflection.TypeNameParser(name)
{
_context = context,
_callingModule = callingModule,
_referencedModules = referencedModules
};

TypeDesc result = parser.Parse()?.Value;

typeWasNotFoundInAssemblyNorBaseLibrary = parser._typeWasNotFoundInAssemblyNorBaseLibrary;
return result;
}

private sealed class Type
{
public Type(TypeDesc type) => Value = type;
public TypeDesc Value { get; }

public Type MakeArrayType() => new Type(Value.MakeArrayType());
public Type MakeArrayType(int rank) => new Type(Value.MakeArrayType(rank));
public Type MakePointerType() => new Type(Value.MakePointerType());
public Type MakeByRefType() => new Type(Value.MakeByRefType());

public Type MakeGenericType(Type[] typeArguments)
{
TypeDesc[] instantiation = new TypeDesc[typeArguments.Length];
for (int i = 0; i < typeArguments.Length; i++)
instantiation[i] = typeArguments[i].Value;
return new Type(((MetadataType)Value).MakeInstantiatedType(instantiation));
}
}

private static bool CheckTopLevelAssemblyQualifiedName() => true;

private Type GetType(string typeName, ReadOnlySpan<string> nestedTypeNames, string assemblyNameIfAny)
{
ModuleDesc module;

if (assemblyNameIfAny != null)
{
module = (TryParseAssemblyName(assemblyNameIfAny) is AssemblyName an) ?
_context.ResolveAssembly(an, throwIfNotFound: false) : null;
}
else
{
module = _callingModule;
}

Type type;

if (module != null)
{
type = GetTypeCore(module, typeName, nestedTypeNames);
if (type != null)
{
_referencedModules?.Add(module);
return type;
}
}

// If it didn't resolve and wasn't assembly-qualified, we also try core library
if (assemblyNameIfAny == null)
{
type = GetTypeCore(_context.SystemModule, typeName, nestedTypeNames);
if (type != null)
{
_referencedModules?.Add(_context.SystemModule);
return type;
}

_typeWasNotFoundInAssemblyNorBaseLibrary = true;
}

return null;
}

private static AssemblyName TryParseAssemblyName(string assemblyName)
{
try
{
return new AssemblyName(assemblyName);
}
catch (FileLoadException)
{
return null;
}
catch (ArgumentException)
{
return null;
}
}

private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan<string> nestedTypeNames)
{
string typeNamespace, name;

int separator = typeName.LastIndexOf('.');
if (separator <= 0)
{
typeNamespace = "";
name = typeName;
}
else
{
if (typeName[separator - 1] == '.')
separator--;
typeNamespace = typeName.Substring(0, separator);
name = typeName.Substring(separator + 1);
}

MetadataType type = module.GetType(typeNamespace, name, throwIfNotFound: false);
if (type == null)
return null;

for (int i = 0; i < nestedTypeNames.Length; i++)
{
type = type.GetNestedType(nestedTypeNames[i]);
if (type == null)
return null;
}

return new Type(type);
}

private static void ParseError()
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
</ItemGroup>

<ItemGroup>
<Compile Include="..\..\..\..\libraries\Common\src\System\Reflection\TypeNameParser.cs">
<Link>TypeNameParser.cs</Link>
</Compile>
<Compile Include="..\..\..\..\libraries\Common\src\System\Text\ValueStringBuilder.cs">
<Link>ValueStringBuilder.cs</Link>
</Compile>
<Compile Include="..\..\Common\TypeSystem\IL\DelegateInfo.cs">
<Link>IL\DelegateInfo.cs</Link>
</Compile>
Expand Down Expand Up @@ -406,7 +412,6 @@
<Compile Include="Compiler\DependencyAnalysis\ReflectedFieldNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReflectedTypeNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReflectionInvokeSupportDependencyAlgorithm.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReflectionMethodBodyScanner.cs" />
<Compile Include="Compiler\DependencyAnalysis\StructMarshallingDataNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\Target_ARM64\ARM64TentativeMethodNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMTentativeMethodNode.cs" />
Expand All @@ -416,6 +421,7 @@
<Compile Include="Compiler\DependencyAnalysis\TentativeInstanceMethodNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\TentativeMethodNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\TrimmingDescriptorNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\TypeNameParser.cs" />
<Compile Include="Compiler\DependencyAnalysis\VariantInterfaceMethodUseNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\CustomAttributeBasedDependencyAlgorithm.cs" />
<Compile Include="Compiler\DependencyAnalysis\FieldMetadataNode.cs" />
Expand Down
25 changes: 9 additions & 16 deletions src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,22 @@ internal static partial class X509ResourceClient
// the latter can't in turn have an explicit dependency on the former.

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

if (socketsHttpHandlerType == null || httpMessageHandlerType == null || httpClientType == null || httpRequestMessageType == null ||
httpResponseMessageType == null || httpResponseHeadersType == null || httpContentType == null)
httpResponseMessageType == null || httpResponseHeadersType == null || httpContentType == null || taskOfHttpResponseMessageType == null)
{
Debug.Fail("Unable to load required type.");
return null;
}

// Workaround until https://github.com/dotnet/runtime/issues/72833 is fixed
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The type HttpResponseMessage is a reference type")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
static Type GetTaskOfHttpResponseMessageType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? httpResponseMessageType) => typeof(Task<>).MakeGenericType(httpResponseMessageType!);

Type taskOfHttpResponseMessageType = GetTaskOfHttpResponseMessageType(httpResponseMessageType);

// Get the methods on those types.
ConstructorInfo? socketsHttpHandlerCtor = socketsHttpHandlerType.GetConstructor(Type.EmptyTypes);
PropertyInfo? pooledConnectionIdleTimeoutProp = socketsHttpHandlerType.GetProperty("PooledConnectionIdleTimeout");
Expand Down
Loading

0 comments on commit c104939

Please sign in to comment.