Browse Source

Work for throw expressions.

pull/1600/head
Andreas Weizel 7 years ago
parent
commit
a254913624
  1. 11
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 3
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  3. 2
      ICSharpCode.Decompiler/IL/Instructions.cs
  4. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  5. 5
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  6. 69
      ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs

11
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -746,6 +746,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -746,6 +746,13 @@ namespace ICSharpCode.Decompiler.CSharp
return HandleThreeValuedLogic(inst, BinaryOperatorType.BitwiseOr, ExpressionType.Or);
}
protected internal override TranslatedExpression VisitThrow(Throw inst, TranslationContext context)
{
return new ThrowExpression(Translate(inst.Argument))
.WithILInstruction(inst)
.WithRR(new ResolveResult(SpecialType.NoType));
}
TranslatedExpression HandleThreeValuedLogic(BinaryInstruction inst, BinaryOperatorType op, ExpressionType eop)
{
var left = Translate(inst.Left);
@ -2181,7 +2188,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2181,7 +2188,9 @@ namespace ICSharpCode.Decompiler.CSharp
var rr = resolver.ResolveBinaryOperator(BinaryOperatorType.NullCoalescing, value.ResolveResult, fallback.ResolveResult);
if (rr.IsError) {
IType targetType;
if (!value.Type.Equals(SpecialType.NullType) && !fallback.Type.Equals(SpecialType.NullType) && !value.Type.Equals(fallback.Type)) {
if (fallback.Expression is ThrowExpression && fallback.Type.Equals(SpecialType.NoType)) {
targetType = value.Type;
} else if (!value.Type.Equals(SpecialType.NullType) && !fallback.Type.Equals(SpecialType.NullType) && !value.Type.Equals(fallback.Type)) {
targetType = compilation.FindType(inst.UnderlyingResultType.ToKnownTypeCode());
} else {
targetType = value.Type.Equals(SpecialType.NullType) ? fallback.Type : value.Type;

3
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -203,6 +203,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -203,6 +203,9 @@ namespace ICSharpCode.Decompiler.CSharp
if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void || targetType.Kind == TypeKind.None) {
return this; // don't attempt to insert cast to '?' or 'void' as these are not valid.
}
if (Expression is ThrowExpression) {
return this; // Throw expressions have no type and are implicitly convertible to any type
}
if (Expression is TupleExpression tupleExpr && targetType is TupleType targetTupleType
&& tupleExpr.Elements.Count == targetTupleType.ElementTypes.Length)
{

2
ICSharpCode.Decompiler/IL/Instructions.cs

@ -4225,7 +4225,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4225,7 +4225,7 @@ namespace ICSharpCode.Decompiler.IL
public Throw(ILInstruction argument) : base(OpCode.Throw, argument)
{
}
public override StackType ResultType { get { return StackType.Void; } }
public override StackType ResultType { get { return this.resultType; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -250,7 +250,7 @@ @@ -250,7 +250,7 @@
new OpCode("default.value", "Returns the default value for a type.",
NoArguments, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("throw", "Throws an exception.",
Unary, MayThrow, UnconditionalBranch),
Unary, MayThrow, HasFlag("InstructionFlags.EndPointUnreachable"), ResultType("this.resultType")),
new OpCode("rethrow", "Rethrows the current exception.",
NoArguments, MayThrow, UnconditionalBranch),
new OpCode("sizeof", "Gets the size of a type in bytes.",

5
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -366,4 +366,9 @@ namespace ICSharpCode.Decompiler.IL @@ -366,4 +366,9 @@ namespace ICSharpCode.Decompiler.IL
}
}
}
public partial class Throw
{
internal StackType resultType = StackType.Void;
}
}

69
ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs

@ -46,6 +46,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -46,6 +46,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// }
/// =>
/// stloc s(if.notnull(valueInst, fallbackInst))
///
/// -------------------
///
/// stloc obj(valueInst)
/// if (comp(ldloc obj == ldnull)) {
/// throw(...)
/// }
/// =>
/// stloc obj(if.notnull(valueInst, throw(...)))
/// </summary>
bool TransformRefTypes(Block block, int pos, StatementTransformContext context)
{
@ -55,15 +64,69 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -55,15 +64,69 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst))
return false;
if (!(condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull()))
return false;
trueInst = Block.Unwrap(trueInst);
if (condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull()
&& trueInst.MatchStLoc(stloc.Variable, out var fallbackValue)
) {
if (trueInst.MatchStLoc(stloc.Variable, out var fallbackValue)) {
context.Step("NullCoalescingTransform (reference types)", stloc);
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue);
block.Instructions.RemoveAt(pos + 1); // remove if instruction
ILInlining.InlineOneIfPossible(block, pos, false, context);
return true;
} else if (trueInst is Throw throwInst) {
context.Step("NullCoalescingTransform (throw expression)", stloc);
throwInst.resultType = StackType.O;
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, throwInst);
block.Instructions.RemoveAt(pos + 1); // remove if instruction
ILInlining.InlineOneIfPossible(block, pos, false, context);
return true;
}
return false;
}
/// <summary>
/// Handles NullCoalescingInstruction case 1: reference types.
///
/// stloc s(valueInst)
/// if (comp(ldloc s == ldnull)) {
/// stloc s(fallbackInst)
/// }
/// =>
/// stloc s(if.notnull(valueInst, fallbackInst))
///
/// -------------------
///
/// stloc obj(valueInst)
/// if (comp(ldloc obj == ldnull)) {
/// throw(...)
/// }
/// =>
/// stloc obj(if.notnull(valueInst, throw(...)))
/// </summary>
bool TransformRefTypesA(Block block, int pos, StatementTransformContext context)
{
if (!(block.Instructions[pos] is StLoc stloc))
return false;
if (stloc.Variable.Kind != VariableKind.StackSlot)
return false;
if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst))
return false;
if (!(condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull()))
return false;
trueInst = Block.Unwrap(trueInst);
if (trueInst.MatchStLoc(stloc.Variable, out var fallbackValue)) {
context.Step("NullCoalescingTransform (reference types)", stloc);
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue);
block.Instructions.RemoveAt(pos + 1); // remove if instruction
ILInlining.InlineOneIfPossible(block, pos, false, context);
return true;
} else if (trueInst is Throw throwInst) {
context.Step("NullCoalescingTransform (throw expression)", stloc);
throwInst.resultType = StackType.O;
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, throwInst);
block.Instructions.RemoveAt(pos + 1); // remove if instruction
ILInlining.InlineOneIfPossible(block, pos, false, context);
return true;
}
return false;
}

Loading…
Cancel
Save