Skip to content

Commit

Permalink
Implement IMetadataResolver for LinkContext (dotnet/linker#2045)
Browse files Browse the repository at this point in the history
This will allow extension methods that take an `IMetadataResolver` like
in dotnet/java-interop#842 to use the
LinkContext Resolve cache.

Context: dotnet/android#5748 (comment)

The Resolve cache added in dotnet/linker#1979
requires calling `Resolve*Definition` methods directly on `LinkContext`,
which means that any extension methods that do resolution logic need to
take a `LinkContext`. This doesn't work well with the layering in
xamarin-android, where java.interop uses a resolution cache with cecil,
but doesn't depend on the linker. Instead it uses a custom
`TypeResolutionCache` for extension methods like `GetBaseDefinition`:
https://github.com/xamarin/java.interop/blob/main/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs#L16
These extension methods are also used from xamarin-android, but there's
a desire to use the `LinkContext` cache in this case.

@jonpryor had the idea to change the extension methods to use cecil's
`IMetadataResolver`, which can be implemented by `TypeDefinitionCache`
and by `LinkContext`. Java.interop will continue using their `TypeDefinitionCache`,
and xamarin-android will use `LinkContext`.

One limitation of this approach is that `LinkContext.TryResolve*Definition`
(renamed to just `TryResolve` for consistency) methods aren't usable from
the extension methods.

Commit migrated from dotnet/linker@aaf4880
  • Loading branch information
sbomer authored May 20, 2021
1 parent 2917fc8 commit 68cd3e2
Show file tree
Hide file tree
Showing 18 changed files with 111 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public static IEnumerable<MethodDefinition> GetMethodsOnTypeHierarchy (this Type
yield return method;
}

type = context.TryResolveTypeDefinition (type.BaseType);
type = context.TryResolve (type.BaseType);
onBaseType = true;
}
}
Expand Down Expand Up @@ -196,7 +196,7 @@ public static IEnumerable<FieldDefinition> GetFieldsOnTypeHierarchy (this TypeDe
yield return field;
}

type = context.TryResolveTypeDefinition (type.BaseType);
type = context.TryResolve (type.BaseType);
onBaseType = true;
}
}
Expand Down Expand Up @@ -261,7 +261,7 @@ public static IEnumerable<PropertyDefinition> GetPropertiesOnTypeHierarchy (this
yield return property;
}

type = context.TryResolveTypeDefinition (type.BaseType);
type = context.TryResolve (type.BaseType);
onBaseType = true;
}
}
Expand Down Expand Up @@ -306,7 +306,7 @@ public static IEnumerable<EventDefinition> GetEventsOnTypeHierarchy (this TypeDe
yield return @event;
}

type = context.TryResolveTypeDefinition (type.BaseType);
type = context.TryResolve (type.BaseType);
onBaseType = true;
}
}
Expand All @@ -317,14 +317,14 @@ public static IEnumerable<InterfaceImplementation> GetAllInterfaceImplementation
foreach (var i in type.Interfaces) {
yield return i;

TypeDefinition interfaceType = context.TryResolveTypeDefinition (i.InterfaceType);
TypeDefinition interfaceType = context.TryResolve (i.InterfaceType);
if (interfaceType != null) {
foreach (var innerInterface in interfaceType.GetAllInterfaceImplementations (context))
yield return innerInterface;
}
}

type = context.TryResolveTypeDefinition (type.BaseType);
type = context.TryResolve (type.BaseType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ public DynamicallyAccessedMemberTypes GetTypeAnnotation (TypeDefinition type)

public DynamicallyAccessedMemberTypes GetGenericParameterAnnotation (GenericParameter genericParameter)
{
TypeDefinition declaringType = _context.ResolveTypeDefinition (genericParameter.DeclaringType);
TypeDefinition declaringType = _context.Resolve (genericParameter.DeclaringType);
if (declaringType != null) {
if (GetAnnotations (declaringType).TryGetAnnotation (genericParameter, out var annotation))
return annotation;

return DynamicallyAccessedMemberTypes.None;
}

MethodDefinition declaringMethod = _context.ResolveMethodDefinition (genericParameter.DeclaringMethod);
MethodDefinition declaringMethod = _context.Resolve (genericParameter.DeclaringMethod);
if (declaringMethod != null && GetAnnotations (declaringMethod.DeclaringType).TryGetAnnotation (declaringMethod, out var methodTypeAnnotations) &&
methodTypeAnnotations.TryGetAnnotation (genericParameter, out var methodAnnotation))
return methodAnnotation;
Expand Down Expand Up @@ -384,7 +384,7 @@ bool ScanMethodBodyForFieldAccess (MethodBody body, bool write, out FieldDefinit
return true;
}

found = _context.ResolveFieldDefinition (foundReference);
found = _context.Resolve (foundReference);

if (found == null) {
// If the field doesn't resolve, it can't be a field on the current type
Expand All @@ -409,7 +409,7 @@ bool IsTypeInterestingForDataflow (TypeReference typeReference)
if (typeReference.MetadataType == MetadataType.String)
return true;

TypeDefinition type = _context.TryResolveTypeDefinition (typeReference);
TypeDefinition type = _context.TryResolve (typeReference);
return type != null && (
_hierarchyInfo.IsSystemType (type) ||
_hierarchyInfo.IsSystemReflectionIReflect (type));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ void ScanLdtoken (Instruction operation, Stack<StackSlot> currentStack)
return;
}
} else if (operation.Operand is MethodReference methodReference) {
var resolvedMethod = _context.TryResolveMethodDefinition (methodReference);
var resolvedMethod = _context.TryResolve (methodReference);
if (resolvedMethod != null) {
StackSlot slot = new StackSlot (new RuntimeMethodHandleValue (resolvedMethod));
currentStack.Push (slot);
Expand Down Expand Up @@ -789,7 +789,7 @@ private void ScanLdfld (

bool isByRef = code == Code.Ldflda || code == Code.Ldsflda;

FieldDefinition field = _context.TryResolveFieldDefinition (operation.Operand as FieldReference);
FieldDefinition field = _context.TryResolve (operation.Operand as FieldReference);
if (field != null) {
StackSlot slot = new StackSlot (GetFieldValue (thisMethod, field), isByRef);
currentStack.Push (slot);
Expand Down Expand Up @@ -817,7 +817,7 @@ private void ScanStfld (
if (operation.OpCode.Code == Code.Stfld)
PopUnknown (currentStack, 1, methodBody, operation.Offset);

FieldDefinition field = _context.TryResolveFieldDefinition (operation.Operand as FieldReference);
FieldDefinition field = _context.TryResolve (operation.Operand as FieldReference);
if (field != null) {
HandleStoreField (thisMethod, field, operation, valueToStoreSlot.Value);
}
Expand Down Expand Up @@ -916,7 +916,7 @@ public TypeDefinition ResolveToTypeDefinition (TypeReference typeReference)
if (typeReference is ArrayType)
return BCL.FindPredefinedType ("System", "Array", _context);

return _context.TryResolveTypeDefinition (typeReference);
return _context.TryResolve (typeReference);
}

public abstract bool HandleCall (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static DynamicallyAccessedMemberTypes[] GetAllDynamicallyAccessedMemberTypes ()

public static bool RequiresReflectionMethodBodyScannerForCallSite (LinkContext context, MethodReference calledMethod)
{
MethodDefinition methodDefinition = context.TryResolveMethodDefinition (calledMethod);
MethodDefinition methodDefinition = context.TryResolve (calledMethod);
if (methodDefinition == null)
return false;

Expand All @@ -51,7 +51,7 @@ public static bool RequiresReflectionMethodBodyScannerForMethodBody (FlowAnnotat

public static bool RequiresReflectionMethodBodyScannerForAccess (LinkContext context, FieldReference field)
{
FieldDefinition fieldDefinition = context.TryResolveFieldDefinition (field);
FieldDefinition fieldDefinition = context.TryResolve (field);
if (fieldDefinition == null)
return false;

Expand Down Expand Up @@ -637,7 +637,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c
return false;

var callingMethodDefinition = callingMethodBody.Method;
var calledMethodDefinition = _context.TryResolveMethodDefinition (calledMethod);
var calledMethodDefinition = _context.TryResolve (calledMethod);
if (calledMethodDefinition == null)
return false;

Expand Down Expand Up @@ -1306,7 +1306,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c

methodReturnValue = MergePointValue.MergeValues (methodReturnValue, CreateMethodReturnValue (calledMethod, propagatedMemberTypes));
} else if (value is SystemTypeValue systemTypeValue) {
TypeDefinition baseTypeDefinition = _context.TryResolveTypeDefinition (systemTypeValue.TypeRepresented.BaseType);
TypeDefinition baseTypeDefinition = _context.TryResolve (systemTypeValue.TypeRepresented.BaseType);
if (baseTypeDefinition != null)
methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new SystemTypeValue (baseTypeDefinition));
else
Expand Down Expand Up @@ -1863,7 +1863,7 @@ void ProcessCreateInstanceByName (ref ReflectionPatternContext reflectionContext
}

var typeRef = _context.TypeNameResolver.ResolveTypeName (resolvedAssembly, typeNameStringValue.Contents);
var resolvedType = _context.TryResolveTypeDefinition (typeRef);
var resolvedType = _context.TryResolve (typeRef);
if (resolvedType == null || typeRef is ArrayType) {
// It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case
// Note that we did find the assembly, so it's not a linker config problem, it's either intentional, or wrong versions of assemblies
Expand Down Expand Up @@ -2219,7 +2219,7 @@ void MarkTypeForDynamicallyAccessedMembers (ref ReflectionPatternContext reflect
void MarkType (ref ReflectionPatternContext reflectionContext, TypeReference typeReference, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
{
var source = reflectionContext.Source;
TypeDefinition type = _context.TryResolveTypeDefinition (typeReference);
TypeDefinition type = _context.TryResolve (typeReference);
reflectionContext.RecordRecognizedPattern (type, () => _markStep.MarkTypeVisibleToReflection (typeReference, type, new DependencyInfo (dependencyKind, source), source));
}

Expand Down
6 changes: 3 additions & 3 deletions src/tools/illink/src/linker/Linker.Steps/CodeRewriterStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ MethodBody CreateStubBody (MethodDefinition method)

var il = body.GetILProcessor ();
if (method.IsInstanceConstructor () && !method.DeclaringType.IsValueType) {
var baseType = Context.ResolveTypeDefinition (method.DeclaringType.BaseType);
var baseType = Context.Resolve (method.DeclaringType.BaseType);
if (baseType is null)
return body;

Expand Down Expand Up @@ -218,14 +218,14 @@ public static Instruction CreateConstantResultInstruction (LinkContext context,
{
switch (rtype.MetadataType) {
case MetadataType.ValueType:
var definition = context.TryResolveTypeDefinition (rtype);
var definition = context.TryResolve (rtype);
if (definition?.IsEnum == true) {
rtype = definition.GetEnumUnderlyingType ();
}

break;
case MetadataType.GenericInstance:
rtype = context.TryResolveTypeDefinition (rtype);
rtype = context.TryResolve (rtype);
break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ CustomAttributeArgument[] ReadCustomAttributeArguments (XPathNodeIterator iterat
return new CustomAttributeArgument (typeref, ConvertStringValue (svalue, typeref));

case MetadataType.ValueType:
var enumType = _context.ResolveTypeDefinition (typeref);
var enumType = _context.Resolve (typeref);
if (enumType?.IsEnum != true)
goto default;

Expand Down Expand Up @@ -377,7 +377,7 @@ bool GetAttributeType (XPathNodeIterator iterator, string attributeFullName, out
return false;
}

attributeType = _context.TryResolveTypeDefinition (assembly, attributeFullName);
attributeType = _context.TryResolve (assembly, attributeFullName);
}

if (attributeType == null) {
Expand Down
Loading

0 comments on commit 68cd3e2

Please sign in to comment.