Skip to content

Commit

Permalink
Handle Mono generated implicit delegate caching
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhentar committed Jul 9, 2017
1 parent a9a9ad4 commit f7d28dd
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 4 deletions.
7 changes: 7 additions & 0 deletions ICSharpCode.Decompiler/Ast/AstBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ public static bool MemberIsHidden(MemberReference member, DecompilerSettings set
FieldDefinition field = member as FieldDefinition;
if (field != null) {
if (field.IsCompilerGenerated()) {
if (IsDelegateMethodCacheField(field))
return true;
if (settings.AnonymousMethods && IsAnonymousMethodCacheField(field))
return true;
if (settings.AutomaticProperties && IsAutomaticPropertyBackingField(field))
Expand Down Expand Up @@ -124,6 +126,11 @@ static bool IsAnonymousMethodCacheField(FieldDefinition field)
return field.Name.StartsWith("CS$<>", StringComparison.Ordinal) || field.Name.StartsWith("<>f__am", StringComparison.Ordinal);
}

static bool IsDelegateMethodCacheField(FieldDefinition field)
{
return field.Name.StartsWith("<>f__mg", StringComparison.Ordinal);
}

static bool IsClosureType(TypeDefinition type)
{
return type.HasGeneratedName() && type.IsCompilerGenerated() && (type.Name.Contains("DisplayClass") || type.Name.Contains("AnonStorey"));
Expand Down
10 changes: 6 additions & 4 deletions ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,12 @@ void CachedDelegateInitializationWithField(ILBlock block, ref int i)
return;
if (newObj.Arguments[1].Code != ILCode.Ldftn)
return;
MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly
if (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
return;

if (!field.IsCompilerGenerated()) //If it's a compiler generated field, it's a cached delegate initialization, whether or not the method is anonymous (Mono caches method group implicit delegates)
{
MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly
if (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
return;
}
ILNode followingNode = block.Body.ElementAtOrDefault(i + 1);
if (followingNode != null && followingNode.GetSelfAndChildrenRecursive<ILExpression>().Count(
e => e.Code == ILCode.Ldsfld && ((FieldReference)e.Operand).ResolveWithinSameModule() == field) == 1)
Expand Down

0 comments on commit f7d28dd

Please sign in to comment.