Browse Source

Fix #1555: Eliminate value-type temporaries emitted by mcs on field reads.

pull/2113/head
Daniel Grunwald 5 years ago
parent
commit
c9f65d3b5e
  1. 2
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  2. 24
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

2
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -289,7 +289,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -289,7 +289,7 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public void ValueTypes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
public void ValueTypes([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}

24
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -250,8 +250,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -250,8 +250,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Thus, we have to ensure we're operating on an r-value.
// Additionally, we cannot inline in cases where the C# compiler prohibits the direct use
// of the rvalue (e.g. M(ref (MyStruct)obj); is invalid).
if (!IsUsedAsThisPointerInCall(loadInst, out var method))
return false;
if (IsUsedAsThisPointerInCall(loadInst, out var method)) {
switch (ClassifyExpression(inlinedExpression)) {
case ExpressionClassification.RValue:
// For struct method calls on rvalues, the C# compiler always generates temporaries.
@ -266,6 +265,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -266,6 +265,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
default:
throw new InvalidOperationException("invalid expression classification");
}
} else if (IsUsedAsThisPointerInFieldRead(loadInst)) {
// mcs generated temporaries for field reads on rvalues (#1555)
return ClassifyExpression(inlinedExpression) == ExpressionClassification.RValue;
} else {
return false;
}
}
internal static bool MethodRequiresCopyForReadonlyLValue(IMethod method)
@ -288,14 +293,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -288,14 +293,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
static bool IsUsedAsThisPointerInCall(LdLoca ldloca, out IMethod method)
{
method = null;
if (ldloca.ChildIndex != 0)
return false;
if (ldloca.Variable.Type.IsReferenceType ?? false)
return false;
ILInstruction inst = ldloca;
while (inst.Parent is LdFlda ldflda) {
inst = ldflda;
}
if (inst.ChildIndex != 0)
return false;
switch (inst.Parent.OpCode) {
case OpCode.Call:
case OpCode.CallVirt:
@ -322,6 +327,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -322,6 +327,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
static bool IsUsedAsThisPointerInFieldRead(LdLoca ldloca)
{
if (ldloca.Variable.Type.IsReferenceType ?? false)
return false;
ILInstruction inst = ldloca;
while (inst.Parent is LdFlda ldflda) {
inst = ldflda;
}
return inst != ldloca && inst.Parent is LdObj;
}
internal enum ExpressionClassification
{
RValue,

Loading…
Cancel
Save