Skip to content

Commit

Permalink
Implement IMetadataResolver for LinkContext
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#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.
  • Loading branch information
sbomer committed May 19, 2021
1 parent 8f1fc25 commit d9d2c67
Show file tree
Hide file tree
Showing 18 changed files with 111 additions and 111 deletions.
12 changes: 6 additions & 6 deletions src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
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
8 changes: 4 additions & 4 deletions src/linker/Linker.Dataflow/FlowAnnotations.cs
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
8 changes: 4 additions & 4 deletions src/linker/Linker.Dataflow/MethodBodyScanner.cs
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
12 changes: 6 additions & 6 deletions src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
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/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
4 changes: 2 additions & 2 deletions src/linker/Linker.Steps/LinkAttributesParser.cs
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 d9d2c67

Please sign in to comment.