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
return HandleThreeValuedLogic(inst, BinaryOperatorType.BitwiseOr, ExpressionType.Or); 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) TranslatedExpression HandleThreeValuedLogic(BinaryInstruction inst, BinaryOperatorType op, ExpressionType eop)
{ {
var left = Translate(inst.Left); var left = Translate(inst.Left);
@ -2181,7 +2188,9 @@ namespace ICSharpCode.Decompiler.CSharp
var rr = resolver.ResolveBinaryOperator(BinaryOperatorType.NullCoalescing, value.ResolveResult, fallback.ResolveResult); var rr = resolver.ResolveBinaryOperator(BinaryOperatorType.NullCoalescing, value.ResolveResult, fallback.ResolveResult);
if (rr.IsError) { if (rr.IsError) {
IType targetType; 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()); targetType = compilation.FindType(inst.UnderlyingResultType.ToKnownTypeCode());
} else { } else {
targetType = value.Type.Equals(SpecialType.NullType) ? fallback.Type : value.Type; targetType = value.Type.Equals(SpecialType.NullType) ? fallback.Type : value.Type;

3
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -203,6 +203,9 @@ namespace ICSharpCode.Decompiler.CSharp
if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void || targetType.Kind == TypeKind.None) { 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. 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 if (Expression is TupleExpression tupleExpr && targetType is TupleType targetTupleType
&& tupleExpr.Elements.Count == targetTupleType.ElementTypes.Length) && tupleExpr.Elements.Count == targetTupleType.ElementTypes.Length)
{ {

2
ICSharpCode.Decompiler/IL/Instructions.cs

@ -4225,7 +4225,7 @@ namespace ICSharpCode.Decompiler.IL
public Throw(ILInstruction argument) : base(OpCode.Throw, argument) 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() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable; return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -250,7 +250,7 @@
new OpCode("default.value", "Returns the default value for a type.", new OpCode("default.value", "Returns the default value for a type.",
NoArguments, HasTypeOperand, ResultType("type.GetStackType()")), NoArguments, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("throw", "Throws an exception.", new OpCode("throw", "Throws an exception.",
Unary, MayThrow, UnconditionalBranch), Unary, MayThrow, HasFlag("InstructionFlags.EndPointUnreachable"), ResultType("this.resultType")),
new OpCode("rethrow", "Rethrows the current exception.", new OpCode("rethrow", "Rethrows the current exception.",
NoArguments, MayThrow, UnconditionalBranch), NoArguments, MayThrow, UnconditionalBranch),
new OpCode("sizeof", "Gets the size of a type in bytes.", 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
} }
} }
} }
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
/// } /// }
/// => /// =>
/// stloc s(if.notnull(valueInst, fallbackInst)) /// stloc s(if.notnull(valueInst, fallbackInst))
///
/// -------------------
///
/// stloc obj(valueInst)
/// if (comp(ldloc obj == ldnull)) {
/// throw(...)
/// }
/// =>
/// stloc obj(if.notnull(valueInst, throw(...)))
/// </summary> /// </summary>
bool TransformRefTypes(Block block, int pos, StatementTransformContext context) bool TransformRefTypes(Block block, int pos, StatementTransformContext context)
{ {
@ -55,15 +64,69 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst)) if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst))
return false; return false;
if (!(condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull()))
return false;
trueInst = Block.Unwrap(trueInst); trueInst = Block.Unwrap(trueInst);
if (condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull() if (trueInst.MatchStLoc(stloc.Variable, out var fallbackValue)) {
&& trueInst.MatchStLoc(stloc.Variable, out var fallbackValue)
) {
context.Step("NullCoalescingTransform (reference types)", stloc); context.Step("NullCoalescingTransform (reference types)", stloc);
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue); stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue);
block.Instructions.RemoveAt(pos + 1); // remove if instruction block.Instructions.RemoveAt(pos + 1); // remove if instruction
ILInlining.InlineOneIfPossible(block, pos, false, context); ILInlining.InlineOneIfPossible(block, pos, false, context);
return true; 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; return false;
} }

Loading…
Cancel
Save