Browse Source

Fix #3465: Translate comp.o(a op b) if op not in (==, !=) into Unsafe.As<object, UIntPtr>(ref a) op Unsafe.As<object, UIntPtr>(ref b)

fix/3465
Siegfried Pammer 8 months ago
parent
commit
6c00c138eb
  1. 15
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 17
      ICSharpCode.Decompiler/IL/ILReader.cs
  3. 8
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs

15
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1108,6 +1108,21 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1108,6 +1108,21 @@ namespace ICSharpCode.Decompiler.CSharp
left = left.ConvertTo(inputType, this);
right = right.ConvertTo(inputType, this);
}
else if (inst.InputType == StackType.O)
{
// 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);
left = WrapInUnsafeAs(left, inst.Left);
right = WrapInUnsafeAs(right, inst.Right);
TranslatedExpression WrapInUnsafeAs(TranslatedExpression expr, ILInstruction inst)
{
var type = expr.Type;
expr = WrapInRef(expr, new ByReferenceType(type));
return CallUnsafeIntrinsic("As", [expr], uintptr, typeArguments: [type, uintptr]);
}
}
return new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(compilation.FindType(TypeCode.Boolean),

17
ICSharpCode.Decompiler/IL/ILReader.cs

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

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

@ -229,5 +229,13 @@ namespace ICSharpCode.Decompiler.IL @@ -229,5 +229,13 @@ namespace ICSharpCode.Decompiler.IL
var liftingKind = isLifted ? ComparisonLiftingKind.ThreeValuedLogic : ComparisonLiftingKind.None;
return new Comp(ComparisonKind.Equality, liftingKind, StackType.I4, Sign.None, arg, new LdcI4(0));
}
internal override bool CanInlineIntoSlot(int childIndex, ILInstruction expressionBeingMoved)
{
// 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;
}
}
}

Loading…
Cancel
Save