Browse Source

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

pull/2113/head
Daniel Grunwald 6 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
} }
[Test] [Test]
public void ValueTypes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) public void ValueTypes([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
{ {
RunForLibrary(cscOptions: cscOptions); RunForLibrary(cscOptions: cscOptions);
} }

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

@ -250,8 +250,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Thus, we have to ensure we're operating on an r-value. // 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 // 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). // of the rvalue (e.g. M(ref (MyStruct)obj); is invalid).
if (!IsUsedAsThisPointerInCall(loadInst, out var method)) if (IsUsedAsThisPointerInCall(loadInst, out var method)) {
return false;
switch (ClassifyExpression(inlinedExpression)) { switch (ClassifyExpression(inlinedExpression)) {
case ExpressionClassification.RValue: case ExpressionClassification.RValue:
// For struct method calls on rvalues, the C# compiler always generates temporaries. // For struct method calls on rvalues, the C# compiler always generates temporaries.
@ -266,6 +265,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
default: default:
throw new InvalidOperationException("invalid expression classification"); 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) internal static bool MethodRequiresCopyForReadonlyLValue(IMethod method)
@ -288,14 +293,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
static bool IsUsedAsThisPointerInCall(LdLoca ldloca, out IMethod method) static bool IsUsedAsThisPointerInCall(LdLoca ldloca, out IMethod method)
{ {
method = null; method = null;
if (ldloca.ChildIndex != 0)
return false;
if (ldloca.Variable.Type.IsReferenceType ?? false) if (ldloca.Variable.Type.IsReferenceType ?? false)
return false; return false;
ILInstruction inst = ldloca; ILInstruction inst = ldloca;
while (inst.Parent is LdFlda ldflda) { while (inst.Parent is LdFlda ldflda) {
inst = ldflda; inst = ldflda;
} }
if (inst.ChildIndex != 0)
return false;
switch (inst.Parent.OpCode) { switch (inst.Parent.OpCode) {
case OpCode.Call: case OpCode.Call:
case OpCode.CallVirt: case OpCode.CallVirt:
@ -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 internal enum ExpressionClassification
{ {
RValue, RValue,

Loading…
Cancel
Save