Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unified handling of Resolve calls #1979

Merged
merged 4 commits into from
Apr 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal static class DynamicallyAccessedMembersBinder
// Returns the members of the type bound by memberTypes. For MemberTypes.All, this returns a single null result.
// This sentinel value allows callers to handle the case where MemberTypes.All conceptually binds to the entire type
// including all recursive nested members.
public static IEnumerable<IMemberDefinition> GetDynamicallyAccessedMembers (this TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes memberTypes)
public static IEnumerable<IMemberDefinition> GetDynamicallyAccessedMembers (this TypeDefinition typeDefinition, LinkContext context, DynamicallyAccessedMemberTypes memberTypes)
{
if (memberTypes == DynamicallyAccessedMemberTypes.All) {
yield return null;
Expand All @@ -38,22 +38,22 @@ public static IEnumerable<IMemberDefinition> GetDynamicallyAccessedMembers (this
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicMethods)) {
foreach (var m in typeDefinition.GetMethodsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic))
foreach (var m in typeDefinition.GetMethodsOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.NonPublic))
yield return m;
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicMethods)) {
foreach (var m in typeDefinition.GetMethodsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public))
foreach (var m in typeDefinition.GetMethodsOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.Public))
yield return m;
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicFields)) {
foreach (var f in typeDefinition.GetFieldsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic))
foreach (var f in typeDefinition.GetFieldsOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.NonPublic))
yield return f;
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicFields)) {
foreach (var f in typeDefinition.GetFieldsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public))
foreach (var f in typeDefinition.GetFieldsOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.Public))
yield return f;
}

Expand All @@ -68,22 +68,22 @@ public static IEnumerable<IMemberDefinition> GetDynamicallyAccessedMembers (this
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicProperties)) {
foreach (var p in typeDefinition.GetPropertiesOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic))
foreach (var p in typeDefinition.GetPropertiesOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.NonPublic))
yield return p;
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicProperties)) {
foreach (var p in typeDefinition.GetPropertiesOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public))
foreach (var p in typeDefinition.GetPropertiesOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.Public))
yield return p;
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicEvents)) {
foreach (var e in typeDefinition.GetEventsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic))
foreach (var e in typeDefinition.GetEventsOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.NonPublic))
yield return e;
}

if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicEvents)) {
foreach (var e in typeDefinition.GetEventsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public))
foreach (var e in typeDefinition.GetEventsOnTypeHierarchy (context, filter: null, bindingFlags: BindingFlags.Public))
yield return e;
}
}
Expand Down Expand Up @@ -113,7 +113,7 @@ public static IEnumerable<MethodDefinition> GetConstructorsOnType (this TypeDefi
}
}

public static IEnumerable<MethodDefinition> GetMethodsOnTypeHierarchy (this TypeDefinition type, Func<MethodDefinition, bool> filter, BindingFlags? bindingFlags = null)
public static IEnumerable<MethodDefinition> GetMethodsOnTypeHierarchy (this TypeDefinition type, LinkContext context, Func<MethodDefinition, bool> filter, BindingFlags? bindingFlags = null)
{
bool onBaseType = false;
while (type != null) {
Expand Down Expand Up @@ -148,12 +148,12 @@ public static IEnumerable<MethodDefinition> GetMethodsOnTypeHierarchy (this Type
yield return method;
}

type = type.BaseType?.Resolve ();
type = context.TryResolveTypeDefinition (type.BaseType);
onBaseType = true;
}
}

public static IEnumerable<FieldDefinition> GetFieldsOnTypeHierarchy (this TypeDefinition type, Func<FieldDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
public static IEnumerable<FieldDefinition> GetFieldsOnTypeHierarchy (this TypeDefinition type, LinkContext context, Func<FieldDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
{
bool onBaseType = false;
while (type != null) {
Expand Down Expand Up @@ -184,7 +184,7 @@ public static IEnumerable<FieldDefinition> GetFieldsOnTypeHierarchy (this TypeDe
yield return field;
}

type = type.BaseType?.Resolve ();
type = context.TryResolveTypeDefinition (type.BaseType);
onBaseType = true;
}
}
Expand All @@ -209,7 +209,7 @@ public static IEnumerable<TypeDefinition> GetNestedTypesOnType (this TypeDefinit
}
}

public static IEnumerable<PropertyDefinition> GetPropertiesOnTypeHierarchy (this TypeDefinition type, Func<PropertyDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
public static IEnumerable<PropertyDefinition> GetPropertiesOnTypeHierarchy (this TypeDefinition type, LinkContext context, Func<PropertyDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
{
bool onBaseType = false;
while (type != null) {
Expand Down Expand Up @@ -249,12 +249,12 @@ public static IEnumerable<PropertyDefinition> GetPropertiesOnTypeHierarchy (this
yield return property;
}

type = type.BaseType?.Resolve ();
type = context.TryResolveTypeDefinition (type.BaseType);
onBaseType = true;
}
}

public static IEnumerable<EventDefinition> GetEventsOnTypeHierarchy (this TypeDefinition type, Func<EventDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
public static IEnumerable<EventDefinition> GetEventsOnTypeHierarchy (this TypeDefinition type, LinkContext context, Func<EventDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
{
bool onBaseType = false;
while (type != null) {
Expand Down Expand Up @@ -294,7 +294,7 @@ public static IEnumerable<EventDefinition> GetEventsOnTypeHierarchy (this TypeDe
yield return @event;
}

type = type.BaseType?.Resolve ();
type = context.TryResolveTypeDefinition (type.BaseType);
onBaseType = true;
}
}
Expand Down
21 changes: 13 additions & 8 deletions src/linker/Linker.Dataflow/FlowAnnotations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ class FlowAnnotations
{
readonly LinkContext _context;
readonly Dictionary<TypeDefinition, TypeAnnotations> _annotations = new Dictionary<TypeDefinition, TypeAnnotations> ();
readonly TypeHierarchyCache _hierarchyInfo = new TypeHierarchyCache ();
readonly TypeHierarchyCache _hierarchyInfo;

public FlowAnnotations (LinkContext context)
{
_context = context;
_hierarchyInfo = new TypeHierarchyCache (context);
}

public bool RequiresDataFlowAnalysis (MethodDefinition method)
Expand Down Expand Up @@ -76,15 +77,15 @@ public DynamicallyAccessedMemberTypes GetTypeAnnotation (TypeDefinition type)

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

return DynamicallyAccessedMemberTypes.None;
}

MethodDefinition declaringMethod = genericParameter.DeclaringMethod?.Resolve ();
MethodDefinition declaringMethod = _context.ResolveMethodDefinition (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 @@ -349,7 +350,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type)
return new TypeAnnotations (type, typeAnnotation, annotatedMethods.ToArray (), annotatedFields.ToArray (), typeGenericParameterAnnotations);
}

static bool ScanMethodBodyForFieldAccess (MethodBody body, bool write, out FieldDefinition found)
bool ScanMethodBodyForFieldAccess (MethodBody body, bool write, out FieldDefinition found)
{
// Tries to find the backing field for a property getter/setter.
// Returns true if this is a method body that we can unambiguously analyze.
Expand Down Expand Up @@ -383,7 +384,7 @@ static bool ScanMethodBodyForFieldAccess (MethodBody body, bool write, out Field
return true;
}

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

if (found == null) {
// If the field doesn't resolve, it can't be a field on the current type
Expand All @@ -405,9 +406,13 @@ static bool ScanMethodBodyForFieldAccess (MethodBody body, bool write, out Field

bool IsTypeInterestingForDataflow (TypeReference typeReference)
{
return typeReference.MetadataType == MetadataType.String ||
_hierarchyInfo.IsSystemType (typeReference) ||
_hierarchyInfo.IsSystemReflectionIReflect (typeReference);
if (typeReference.MetadataType == MetadataType.String)
return true;

TypeDefinition type = _context.TryResolveTypeDefinition (typeReference);
return type != null && (
_hierarchyInfo.IsSystemType (type) ||
_hierarchyInfo.IsSystemReflectionIReflect (type));
}

internal void ValidateMethodAnnotationsAreSame (MethodDefinition method, MethodDefinition baseMethod)
Expand Down
28 changes: 23 additions & 5 deletions src/linker/Linker.Dataflow/MethodBodyScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ public StackSlot (ValueNode value, bool isByRef = false)

abstract partial class MethodBodyScanner
{
protected readonly LinkContext _context;

protected MethodBodyScanner (LinkContext context)
{
this._context = context;
}

internal ValueNode MethodReturnValue { private set; get; }

protected virtual void WarnAboutInvalidILInMethod (MethodBody method, int ilOffset)
Expand Down Expand Up @@ -706,7 +713,7 @@ private void ScanLdloc (
}
}

private static void ScanLdtoken (Instruction operation, Stack<StackSlot> currentStack)
void ScanLdtoken (Instruction operation, Stack<StackSlot> currentStack)
{
if (operation.Operand is GenericParameter genericParameter) {
StackSlot slot = new StackSlot (new RuntimeTypeHandleForGenericParameterValue (genericParameter));
Expand All @@ -715,14 +722,14 @@ private static void ScanLdtoken (Instruction operation, Stack<StackSlot> current
}

if (operation.Operand is TypeReference typeReference) {
var resolvedReference = typeReference.ResolveToMainTypeDefinition ();
var resolvedReference = ResolveToTypeDefinition (typeReference);
if (resolvedReference != null) {
StackSlot slot = new StackSlot (new RuntimeTypeHandleValue (resolvedReference));
currentStack.Push (slot);
return;
}
} else if (operation.Operand is MethodReference methodReference) {
var resolvedMethod = methodReference.Resolve ();
var resolvedMethod = _context.TryResolveMethodDefinition (methodReference);
if (resolvedMethod != null) {
StackSlot slot = new StackSlot (new RuntimeMethodHandleValue (resolvedMethod));
currentStack.Push (slot);
Expand Down Expand Up @@ -782,7 +789,7 @@ private void ScanLdfld (

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

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

FieldDefinition field = (operation.Operand as FieldReference)?.Resolve ();
FieldDefinition field = _context.TryResolveFieldDefinition (operation.Operand as FieldReference);
if (field != null) {
HandleStoreField (thisMethod, field, operation, valueToStoreSlot.Value);
}
Expand Down Expand Up @@ -901,6 +908,17 @@ private void HandleCall (
}
}

// Array types that are dynamically accessed should resolve to System.Array instead of its element type - which is what Cecil resolves to.
// Any data flow annotations placed on a type parameter which receives an array type apply to the array itself. None of the members in its
// element type should be marked.
public TypeDefinition ResolveToTypeDefinition (TypeReference typeReference)
{
if (typeReference is ArrayType)
return BCL.FindPredefinedType ("System", "Array", _context);

return _context.TryResolveTypeDefinition (typeReference);
}

public abstract bool HandleCall (
MethodBody callingMethodBody,
MethodReference calledMethod,
Expand Down
Loading