Browse Source

Allow inlining of compiler-generated value-type-temporaries when field accesses are involved.

pull/1600/head
Daniel Grunwald 6 years ago
parent
commit
7f8689c464
  1. 10
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs
  2. 16
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

10
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs

@ -66,6 +66,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
S s = this; S s = this;
s.SetField(); s.SetField();
} }
public void UseField(int val)
{
UseField(Get<S>().Field);
}
} }
#if CS72 #if CS72
@ -263,5 +268,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
r.Property = 2; r.Property = 2;
#endif #endif
} }
public static void CallOnFieldOfTemporary()
{
Get<S>().Field.ToString();
}
} }
} }

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

@ -272,10 +272,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (ldloca.Variable.Type.IsReferenceType ?? false) if (ldloca.Variable.Type.IsReferenceType ?? false)
return false; return false;
switch (ldloca.Parent.OpCode) { ILInstruction inst = ldloca;
while (inst.Parent is LdFlda ldflda) {
inst = ldflda;
}
switch (inst.Parent.OpCode) {
case OpCode.Call: case OpCode.Call:
case OpCode.CallVirt: case OpCode.CallVirt:
var method = ((CallInstruction)ldloca.Parent).Method; var method = ((CallInstruction)inst.Parent).Method;
if (method.IsAccessor && method.AccessorKind != MethodSemanticsAttributes.Getter) { if (method.IsAccessor && method.AccessorKind != MethodSemanticsAttributes.Getter) {
// C# doesn't allow calling setters on temporary structs // C# doesn't allow calling setters on temporary structs
return false; return false;
@ -284,7 +288,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.Await: case OpCode.Await:
return true; return true;
case OpCode.NullableUnwrap: case OpCode.NullableUnwrap:
return ((NullableUnwrap)ldloca.Parent).RefInput; return ((NullableUnwrap)inst.Parent).RefInput;
default: default:
return false; return false;
} }
@ -346,13 +350,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
switch (addr) { switch (addr) {
case LdFlda ldflda: case LdFlda ldflda:
return ldflda.Field.IsReadOnly; return ldflda.Field.IsReadOnly
|| (ldflda.Field.DeclaringType.Kind == TypeKind.Struct && IsReadonlyReference(ldflda.Target));
case LdsFlda ldsflda: case LdsFlda ldsflda:
return ldsflda.Field.IsReadOnly; return ldsflda.Field.IsReadOnly;
case LdLoc ldloc: case LdLoc ldloc:
return IsReadonlyRefLocal(ldloc.Variable); return IsReadonlyRefLocal(ldloc.Variable);
case Call call: case Call call:
return call.Method.ReturnTypeIsRefReadOnly; return call.Method.ReturnTypeIsRefReadOnly;
case AddressOf _:
// C# doesn't allow mutation of value-type temporaries
return true;
default: default:
return false; return false;
} }

Loading…
Cancel
Save