Browse Source

Add ILInlining.IsUsedAsThisPointerInCall().

pull/877/head
Daniel Grunwald 8 years ago
parent
commit
6988260ea3
  1. 1
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Using.cs
  2. 23
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/ValueTypeCall.cs
  3. 33
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  4. 2
      ICSharpCode.Decompiler/TypeSystem/NullableType.cs

1
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Using.cs

@ -45,6 +45,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
NoUsingDueToByRefCall(); NoUsingDueToByRefCall();
NoUsingDueToContinuedDisposableUse(); NoUsingDueToContinuedDisposableUse();
ContinuedObjectUse(); ContinuedObjectUse();
VariableAlreadyUsedBefore();
UsingObject(); UsingObject();
} }

23
ICSharpCode.Decompiler.Tests/TestCases/Correctness/ValueTypeCall.cs

@ -94,9 +94,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
static void Box() static void Box()
{ {
Console.WriteLine("Box");
object o = new MutValueType { val = 300 }; object o = new MutValueType { val = 300 };
((MutValueType)o).Increment(); ((MutValueType)o).Increment();
((MutValueType)o).Increment(); ((MutValueType)o).Increment();
MutValueType unboxed1 = (MutValueType)o;
unboxed1.Increment();
unboxed1.Increment();
((MutValueType)o).Increment();
MutValueType unboxed2 = (MutValueType)o;
unboxed2.val = 100;
((MutValueType)o).Dispose();
} }
MutValueType instanceField; MutValueType instanceField;
@ -111,11 +119,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
} }
static void Using() static void Using()
{
Using1();
Using2();
Using3();
}
static void Using1()
{ {
Console.WriteLine("Using:"); Console.WriteLine("Using:");
using (var x = new MutValueType()) { using (var x = new MutValueType()) {
x.Increment(); x.Increment();
} }
}
static void Using2()
{
Console.WriteLine("Not using:"); Console.WriteLine("Not using:");
var y = new MutValueType(); var y = new MutValueType();
try { try {
@ -124,6 +143,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
MutValueType x = y; MutValueType x = y;
x.Dispose(); x.Dispose();
} }
}
static void Using3()
{
Console.WriteLine("Using with variable declared outside:"); Console.WriteLine("Using with variable declared outside:");
MutValueType z; MutValueType z;
using (z = new MutValueType()) { using (z = new MutValueType()) {

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

@ -164,7 +164,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction loadInst; ILInstruction loadInst;
if (FindLoadInNext(next, v, inlinedExpression, out loadInst) == true) { if (FindLoadInNext(next, v, inlinedExpression, out loadInst) == true) {
if (loadInst.OpCode == OpCode.LdLoca) { if (loadInst.OpCode == OpCode.LdLoca) {
if (!IsGeneratedValueTypeTemporary(next, loadInst.Parent, loadInst.ChildIndex, v, inlinedExpression)) if (!IsGeneratedValueTypeTemporary(next, (LdLoca)loadInst, v, inlinedExpression))
return false; return false;
} else { } else {
Debug.Assert(loadInst.OpCode == OpCode.LdLoc); Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
@ -192,32 +192,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Is this a temporary variable generated by the C# compiler for instance method calls on value type values /// Is this a temporary variable generated by the C# compiler for instance method calls on value type values
/// </summary> /// </summary>
/// <param name="next">The next top-level expression</param> /// <param name="next">The next top-level expression</param>
/// <param name="parent">The direct parent of the load within 'next'</param> /// <param name="loadInst">The load instruction (a descendant within 'next')</param>
/// <param name="pos">Index of the load within 'parent'</param>
/// <param name="v">The variable being inlined.</param> /// <param name="v">The variable being inlined.</param>
static bool IsGeneratedValueTypeTemporary(ILInstruction next, ILInstruction parent, int pos, ILVariable v, ILInstruction inlinedExpression) static bool IsGeneratedValueTypeTemporary(ILInstruction next, LdLoca loadInst, ILVariable v, ILInstruction inlinedExpression)
{ {
if (pos == 0 && v.Type != null && v.Type.IsReferenceType == false) { Debug.Assert(loadInst.Variable == v);
// Inlining a value type variable is allowed only if the resulting code will maintain the semantics // Inlining a value type variable is allowed only if the resulting code will maintain the semantics
// that the method is operating on a copy. // that the method is operating on a copy.
// Thus, we have to disallow inlining of other locals, fields, array elements, dereferenced pointers // Thus, we have to ensure we're operating on an r-value.
if (IsLValue(inlinedExpression)) { // Additionally, we cannot inline in cases where the C# compiler prohibits the direct use
return false; // of the rvalue (e.g. M(ref (MyStruct)obj); is invalid).
return IsUsedAsThisPointerInCall(loadInst) && !IsLValue(inlinedExpression);
} }
// inline the compiler-generated variable that are used when accessing a member on a value type: internal static bool IsUsedAsThisPointerInCall(LdLoca ldloca)
switch (parent.OpCode) { {
if (ldloca.ChildIndex != 0)
return false;
if (ldloca.Variable.Type.IsReferenceType != false)
return false;
switch (ldloca.Parent.OpCode) {
case OpCode.Call: case OpCode.Call:
return !((Call)parent).Method.IsStatic;
case OpCode.CallVirt: case OpCode.CallVirt:
return !((CallVirt)parent).Method.IsStatic; return !((CallInstruction)ldloca.Parent).Method.IsStatic;
case OpCode.LdFlda:
case OpCode.Await: case OpCode.Await:
return true; return true;
} default:
}
return false; return false;
} }
}
/// <summary> /// <summary>
/// Gets whether the instruction, when converted into C#, turns into an l-value that can /// Gets whether the instruction, when converted into C#, turns into an l-value that can

2
ICSharpCode.Decompiler/TypeSystem/NullableType.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (type == null) if (type == null)
throw new ArgumentNullException("type"); throw new ArgumentNullException("type");
ParameterizedType pt = type as ParameterizedType; ParameterizedType pt = type as ParameterizedType;
if (pt != null && pt.TypeParameterCount == 1 && pt.FullName == "System.Nullable") if (pt != null && pt.TypeParameterCount == 1 && pt.GetDefinition().KnownTypeCode == KnownTypeCode.NullableOfT)
return pt.GetTypeArgument(0); return pt.GetTypeArgument(0);
else else
return type; return type;

Loading…
Cancel
Save