Browse Source

#907: Avoid unnecessary casts in delegate comparisons.

pull/946/head
Daniel Grunwald 8 years ago
parent
commit
9e3fbe68f3
  1. 15
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs
  2. 64
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.il
  3. 46
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.il
  4. 42
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.roslyn.il
  5. 60
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.roslyn.il
  6. 30
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  7. 13
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

15
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs

@ -199,5 +199,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -199,5 +199,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return Math.Abs(a - b);
}
public bool CompareDelegatesByValue(Action a, Action b)
{
return a == b;
}
public bool CompareDelegatesByReference(Action a, Action b)
{
return (object)a == b;
}
public bool CompareDelegateWithNull(Action a)
{
return a == null;
}
}
}

64
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly q5z5ui4l
.assembly ph2u0axx
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module q5z5ui4l.dll
// MVID: {E0E1769A-5636-428C-B7CE-29408F5D108F}
.module ph2u0axx.dll
// MVID: {8F821F70-8053-4F18-BDF7-88A43880B754}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x024D0000
// Image base: 0x00D70000
// =============== CLASS MEMBERS DECLARATION ===================
@ -681,6 +681,60 @@ @@ -681,6 +681,60 @@
IL_000d: ret
} // end of method TypeAnalysisTests::EnumDiff
.method public hidebysig instance bool
CompareDelegatesByValue(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 13 (0xd)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: call bool [mscorlib]System.Delegate::op_Equality(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0008: stloc.0
IL_0009: br.s IL_000b
IL_000b: ldloc.0
IL_000c: ret
} // end of method TypeAnalysisTests::CompareDelegatesByValue
.method public hidebysig instance bool
CompareDelegatesByReference(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 10 (0xa)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: ceq
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method TypeAnalysisTests::CompareDelegatesByReference
.method public hidebysig instance bool
CompareDelegateWithNull(class [mscorlib]System.Action a) cil managed
{
// Code size 10 (0xa)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldnull
IL_0003: ceq
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method TypeAnalysisTests::CompareDelegateWithNull
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

46
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly '5lntuoy2'
.assembly frnxitb5
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module '5lntuoy2.dll'
// MVID: {85A70DA1-7D32-4ED1-89B1-4720D974D969}
.module frnxitb5.dll
// MVID: {DC6B1392-D29F-44A5-97D6-0C026DCD3A00}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x05730000
// Image base: 0x00D50000
// =============== CLASS MEMBERS DECLARATION ===================
@ -474,6 +474,42 @@ @@ -474,6 +474,42 @@
IL_0008: ret
} // end of method TypeAnalysisTests::EnumDiff
.method public hidebysig instance bool
CompareDelegatesByValue(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: call bool [mscorlib]System.Delegate::op_Equality(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0007: ret
} // end of method TypeAnalysisTests::CompareDelegatesByValue
.method public hidebysig instance bool
CompareDelegatesByReference(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ceq
IL_0004: ret
} // end of method TypeAnalysisTests::CompareDelegatesByReference
.method public hidebysig instance bool
CompareDelegateWithNull(class [mscorlib]System.Action a) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldnull
IL_0002: ceq
IL_0004: ret
} // end of method TypeAnalysisTests::CompareDelegateWithNull
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

42
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.opt.roslyn.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module TypeAnalysisTests.dll
// MVID: {60E6985E-8E86-4693-9F02-AD3FF7341588}
// MVID: {B6659F2C-8CAA-447B-9D1D-D59D8C40C6D7}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02440000
// Image base: 0x003E0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -476,6 +476,42 @@ @@ -476,6 +476,42 @@
IL_0008: ret
} // end of method TypeAnalysisTests::EnumDiff
.method public hidebysig instance bool
CompareDelegatesByValue(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: call bool [mscorlib]System.Delegate::op_Equality(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0007: ret
} // end of method TypeAnalysisTests::CompareDelegatesByValue
.method public hidebysig instance bool
CompareDelegatesByReference(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ceq
IL_0004: ret
} // end of method TypeAnalysisTests::CompareDelegatesByReference
.method public hidebysig instance bool
CompareDelegateWithNull(class [mscorlib]System.Action a) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldnull
IL_0002: ceq
IL_0004: ret
} // end of method TypeAnalysisTests::CompareDelegateWithNull
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

60
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.roslyn.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module TypeAnalysisTests.dll
// MVID: {389E1347-98C0-49C1-B484-EDF5FFA1CD16}
// MVID: {E25A3961-A07D-4220-AB6C-FE5B1624514C}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x027F0000
// Image base: 0x00D80000
// =============== CLASS MEMBERS DECLARATION ===================
@ -680,6 +680,60 @@ @@ -680,6 +680,60 @@
IL_000d: ret
} // end of method TypeAnalysisTests::EnumDiff
.method public hidebysig instance bool
CompareDelegatesByValue(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 13 (0xd)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: call bool [mscorlib]System.Delegate::op_Equality(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0008: stloc.0
IL_0009: br.s IL_000b
IL_000b: ldloc.0
IL_000c: ret
} // end of method TypeAnalysisTests::CompareDelegatesByValue
.method public hidebysig instance bool
CompareDelegatesByReference(class [mscorlib]System.Action a,
class [mscorlib]System.Action b) cil managed
{
// Code size 10 (0xa)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: ceq
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method TypeAnalysisTests::CompareDelegatesByReference
.method public hidebysig instance bool
CompareDelegateWithNull(class [mscorlib]System.Action a) cil managed
{
// Code size 10 (0xa)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldnull
IL_0003: ceq
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method TypeAnalysisTests::CompareDelegateWithNull
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

30
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -22,16 +22,11 @@ using System.Diagnostics; @@ -22,16 +22,11 @@ using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using ExpressionType = System.Linq.Expressions.ExpressionType;
using PrimitiveType = ICSharpCode.Decompiler.CSharp.Syntax.PrimitiveType;
using System.Threading;
namespace ICSharpCode.Decompiler.CSharp
{
@ -163,6 +158,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -163,6 +158,9 @@ namespace ICSharpCode.Decompiler.CSharp
return HandleAccessorCall(inst, target, method, arguments.ToList());
} else if (method.Name == "Invoke" && method.DeclaringType.Kind == TypeKind.Delegate) {
return new InvocationExpression(target, arguments.Select(arg => arg.Expression)).WithILInstruction(inst).WithRR(rr);
} else if (IsDelegateEqualityComparison(method, arguments)) {
return HandleDelegateEqualityComparison(method, arguments)
.WithILInstruction(inst).WithRR(rr);
} else {
bool requireTypeArguments = false;
bool targetCasted = false;
@ -215,6 +213,28 @@ namespace ICSharpCode.Decompiler.CSharp @@ -215,6 +213,28 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private bool IsDelegateEqualityComparison(IMethod method, IList<TranslatedExpression> arguments)
{
// Comparison on a delegate type is a C# builtin operator
// that compiles down to a Delegate.op_Equality call.
// We handle this as a special case to avoid inserting a cast to System.Delegate.
return method.IsOperator
&& method.DeclaringType.IsKnownType(KnownTypeCode.Delegate)
&& (method.Name == "op_Equality" || method.Name == "op_Inequality")
&& arguments.Count == 2
&& arguments[0].Type.Kind == TypeKind.Delegate
&& arguments[1].Type.Equals(arguments[0].Type);
}
private Expression HandleDelegateEqualityComparison(IMethod method, IList<TranslatedExpression> arguments)
{
return new BinaryOperatorExpression(
arguments[0],
method.Name == "op_Equality" ? BinaryOperatorType.Equality : BinaryOperatorType.InEquality,
arguments[1]
);
}
OverloadResolutionErrors IsUnambiguousCall(ILInstruction inst, TranslatedExpression target, IMethod method, IType[] typeArguments, IList<TranslatedExpression> arguments)
{
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly);

13
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -492,6 +492,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -492,6 +492,19 @@ namespace ICSharpCode.Decompiler.CSharp
left = AdjustConstantExpressionToType(left, right.Type);
right = AdjustConstantExpressionToType(right, left.Type);
if (left.Type.Kind == TypeKind.Delegate && right.Type.Kind == TypeKind.Null
|| left.Type.Kind == TypeKind.Null && right.Type.Kind == TypeKind.Delegate)
{
// When comparing a delegate with null, the C# compiler generates a reference comparison.
negateOutput = false;
return new BinaryOperatorExpression(left.Expression, inst.Kind.ToBinaryOperatorType(), right.Expression)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(
compilation.FindType(KnownTypeCode.Boolean),
inst.Kind == ComparisonKind.Equality ? ExpressionType.Equal : ExpressionType.NotEqual,
left.ResolveResult, right.ResolveResult));
}
var rr = resolver.ResolveBinaryOperator(inst.Kind.ToBinaryOperatorType(), left.ResolveResult, right.ResolveResult)
as OperatorResolveResult;
if (rr == null || rr.IsError || rr.UserDefinedOperatorMethod != null

Loading…
Cancel
Save