Browse Source

#3465: Fix bugs in `comp.o` handling.

null-coalescing-assignment
Daniel Grunwald 4 months ago
parent
commit
ec58d57875
  1. 3
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3465.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 14
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 18
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs

3
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3465.cs

@ -16,8 +16,7 @@ namespace Issue3465 @@ -16,8 +16,7 @@ namespace Issue3465
private static bool Test3465()
{
Program program = GetProgram();
Program program2 = programNull;
return System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref program) > System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref program2);
return System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref program) > System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref programNull);
}
}
}

4
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1112,7 +1112,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1112,7 +1112,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
// Unsafe.As<object, UIntPtr>(ref left) op Unsafe.As<object, UIntPtr>(ref right)
// TTo Unsafe.As<TFrom, TTo>(ref TFrom source)
var uintptr = compilation.FindType(KnownTypeCode.UIntPtr);
var integerType = compilation.FindType(inst.Sign == Sign.Signed ? KnownTypeCode.IntPtr : KnownTypeCode.UIntPtr);
left = WrapInUnsafeAs(left, inst.Left);
right = WrapInUnsafeAs(right, inst.Right);
@ -1120,7 +1120,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1120,7 +1120,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
var type = expr.Type;
expr = WrapInRef(expr, new ByReferenceType(type));
return CallUnsafeIntrinsic("As", [expr], uintptr, typeArguments: [type, uintptr]);
return CallUnsafeIntrinsic("As", [expr], integerType, typeArguments: [type, integerType]);
}
}
return new BinaryOperatorExpression(left.Expression, op, right.Expression)

14
ICSharpCode.Decompiler/IL/ILReader.cs

@ -1248,11 +1248,14 @@ namespace ICSharpCode.Decompiler.IL @@ -1248,11 +1248,14 @@ namespace ICSharpCode.Decompiler.IL
}
}
StackType PeekStackType(int i = 0)
StackType PeekStackType()
{
if (expressionStack.Count > i)
return expressionStack[^(i + 1)].ResultType;
return currentStack.Skip(i).FirstOrDefault()?.StackType ?? StackType.Unknown;
if (expressionStack.Count > 0)
return expressionStack.Last().ResultType;
if (currentStack.IsEmpty)
return StackType.Unknown;
else
return currentStack.Peek().StackType;
}
sealed class CollectStackVariablesVisitor : ILVisitor<ILInstruction>
@ -1842,8 +1845,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1842,8 +1845,7 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction Comparison(ComparisonKind kind, bool un = false)
{
var stackType = PeekStackType();
if (!kind.IsEqualityOrInequality() && stackType == StackType.O && stackType == PeekStackType(1))
if (!kind.IsEqualityOrInequality() && PeekStackType() == StackType.O)
{
FlushExpressionStack();
}

18
ICSharpCode.Decompiler/IL/Instructions/Comp.cs

@ -235,7 +235,23 @@ namespace ICSharpCode.Decompiler.IL @@ -235,7 +235,23 @@ namespace ICSharpCode.Decompiler.IL
// ExpressionBuilder translates comp.o(a op b) for op not in (==, !=) into
// Unsafe.As(ref a) op Unsafe.As(ref b), which requires that a and b are variables
// and not expressions. Returning false in those cases prevents inlining.
return kind.IsEqualityOrInequality() || this.InputType != StackType.O;
// However if one of the arguments is LdNull, then we don't need the Unsafe.As trickery, and can always inline.
if (kind.IsEqualityOrInequality() || this.InputType != StackType.O)
{
// OK, won't need Unsafe.As.
return true;
}
if (expressionBeingMoved is LdLoc || expressionBeingMoved.MatchLdsFld(out _))
{
// OK, can use variable/field name with Unsafe.As(ref x)
return true;
}
if (Sign != Sign.Signed && (expressionBeingMoved is LdNull || Left is LdNull || Right is LdNull))
{
// OK, this is the "compare with null" special case that doesn't need Unsafe.As()
return true;
}
return false;
}
}
}

Loading…
Cancel
Save