From a674b4cdf1b08135ba8bb38afa2f6e46947ea447 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 17 Jul 2016 23:57:06 +0900 Subject: [PATCH] Extend TransformAssignment --- .../CSharp/CSharpDecompiler.cs | 2 +- .../CSharp/ExpressionBuilder.cs | 48 ++- .../ICSharpCode.Decompiler.csproj | 2 +- .../IL/Instructions/ILInstruction.cs | 5 + .../IL/Transforms/CopyPropagation.cs | 2 +- .../IL/Transforms/ILInlining.cs | 2 + .../IL/Transforms/TransformAssignment.cs | 265 +++++++++++++ .../Transforms/TransformInlineAssignment.cs | 142 ------- .../Pretty/CompoundAssignmentTest.cs | 92 ++++- .../Pretty/CompoundAssignmentTest.il | 364 +++++++++++++++--- .../Tests/TestCases/Pretty/HelloWorld.il | 19 +- .../TestCases/Pretty/InlineAssignmentTest.cs | 20 + .../TestCases/Pretty/InlineAssignmentTest.il | 79 +++- 13 files changed, 824 insertions(+), 218 deletions(-) create mode 100644 ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs delete mode 100644 ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index c594539dc..59415d284 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler.CSharp new IntroduceExitPoints(), new ConditionDetection(), new ILInlining(), - new TransformInlineAssignment(), + new TransformAssignment(), new CopyPropagation(), new InlineCompilerGeneratedVariables(), new ExpressionTransforms(), // must run once before "the loop" to allow RemoveDeadVariablesInit diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 7a7cded22..b075659db 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -601,21 +601,21 @@ namespace ICSharpCode.Decompiler.CSharp { switch (inst.Operator) { case BinaryNumericOperator.Add: - return HandleCompoundAssigment(inst, AssignmentOperatorType.Add); + return HandleCompoundAssignment(inst, AssignmentOperatorType.Add); case BinaryNumericOperator.Sub: - return HandleCompoundAssigment(inst, AssignmentOperatorType.Subtract); + return HandleCompoundAssignment(inst, AssignmentOperatorType.Subtract); case BinaryNumericOperator.Mul: - return HandleCompoundAssigment(inst, AssignmentOperatorType.Multiply); + return HandleCompoundAssignment(inst, AssignmentOperatorType.Multiply); case BinaryNumericOperator.Div: - return HandleCompoundAssigment(inst, AssignmentOperatorType.Divide); + return HandleCompoundAssignment(inst, AssignmentOperatorType.Divide); case BinaryNumericOperator.Rem: - return HandleCompoundAssigment(inst, AssignmentOperatorType.Modulus); + return HandleCompoundAssignment(inst, AssignmentOperatorType.Modulus); case BinaryNumericOperator.BitAnd: - return HandleCompoundAssigment(inst, AssignmentOperatorType.BitwiseAnd); + return HandleCompoundAssignment(inst, AssignmentOperatorType.BitwiseAnd); case BinaryNumericOperator.BitOr: - return HandleCompoundAssigment(inst, AssignmentOperatorType.BitwiseOr); + return HandleCompoundAssignment(inst, AssignmentOperatorType.BitwiseOr); case BinaryNumericOperator.BitXor: - return HandleCompoundAssigment(inst, AssignmentOperatorType.ExclusiveOr); + return HandleCompoundAssignment(inst, AssignmentOperatorType.ExclusiveOr); case BinaryNumericOperator.ShiftLeft: return HandleCompoundShift(inst, AssignmentOperatorType.ShiftLeft); case BinaryNumericOperator.ShiftRight: @@ -625,7 +625,7 @@ namespace ICSharpCode.Decompiler.CSharp } } - TranslatedExpression HandleCompoundAssigment(CompoundAssignmentInstruction inst, AssignmentOperatorType op) + TranslatedExpression HandleCompoundAssignment(CompoundAssignmentInstruction inst, AssignmentOperatorType op) { var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow); var target = Translate(inst.Target); @@ -644,9 +644,18 @@ namespace ICSharpCode.Decompiler.CSharp value = value.ConvertTo(targetType, this); rr = resolverWithOverflowCheck.ResolveAssignment(op, target.ResolveResult, value.ResolveResult); } - var resultExpr = new AssignmentExpression(target.Expression, op, value.Expression) - .WithILInstruction(inst) - .WithRR(rr); + TranslatedExpression resultExpr; + if (inst.CompoundAssignmentType == CompoundAssignmentType.EvaluatesToOldValue) { + Debug.Assert(op == AssignmentOperatorType.Add || op == AssignmentOperatorType.Subtract); + Debug.Assert(value.ResolveResult.IsCompileTimeConstant && 1.Equals(value.ResolveResult.ConstantValue)); + resultExpr = new UnaryOperatorExpression(op == AssignmentOperatorType.Add ? UnaryOperatorType.PostIncrement : UnaryOperatorType.PostDecrement, target) + .WithILInstruction(inst) + .WithRR(rr); + } else { + resultExpr = new AssignmentExpression(target.Expression, op, value.Expression) + .WithILInstruction(inst) + .WithRR(rr); + } if (AssignmentOperatorMightCheckForOverflow(op)) resultExpr.Expression.AddAnnotation(inst.CheckForOverflow ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); return resultExpr; @@ -1290,6 +1299,8 @@ namespace ICSharpCode.Decompiler.CSharp switch (block.Type) { case BlockType.ArrayInitializer: return TranslateArrayInitializer(block); + case BlockType.CompoundOperator: + return TranslateCompoundOperator(block); default: return base.VisitBlock(block); } @@ -1355,6 +1366,19 @@ namespace ICSharpCode.Decompiler.CSharp .WithRR(new ArrayCreateResolveResult(new ArrayType(compilation, type, dimensions), newArr.Indices.Select(i => Translate(i).ResolveResult).ToArray(), elementResolveResults)); } + TranslatedExpression TranslateCompoundOperator(Block block) + { + var targetInst = (block.Instructions.ElementAtOrDefault(0) as StLoc)?.Value; + var inst = (block.Instructions.ElementAtOrDefault(1) as StLoc)?.Value as BinaryNumericInstruction; + if (targetInst == null || inst == null || (inst.Operator != BinaryNumericOperator.Add && inst.Operator != BinaryNumericOperator.Sub)) + throw new ArgumentException("given Block is invalid!"); + var op = inst.Operator == BinaryNumericOperator.Add ? UnaryOperatorType.PostIncrement : UnaryOperatorType.PostDecrement; + var target = Translate(targetInst); + return new UnaryOperatorExpression(op, target) + .WithILInstruction(block) + .WithRR(resolver.WithCheckForOverflow(inst.CheckForOverflow).ResolveUnaryOperator(op, target.ResolveResult)); + } + protected internal override TranslatedExpression VisitIfInstruction(IfInstruction inst) { var condition = TranslateCondition(inst.Condition); diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 4db9ec8e7..5976fa5d4 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -153,7 +153,7 @@ - + diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs index f31b12c7d..15553ce08 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs @@ -609,6 +609,11 @@ namespace ICSharpCode.Decompiler.IL } } + public interface IInstructionWithTypeOperand + { + ICSharpCode.NRefactory.TypeSystem.IType Type { get; } + } + public interface IInstructionWithFieldOperand { ICSharpCode.NRefactory.TypeSystem.IField Field { get; } diff --git a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs index 80c1d67d1..f9349dc70 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs @@ -97,7 +97,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } default: // All instructions without special behavior that target a stack-variable can be copied. - return value.DirectFlags == InstructionFlags.None && target.Kind == VariableKind.StackSlot; + return value.Flags == InstructionFlags.None && value.Children.Count == 0 && target.Kind == VariableKind.StackSlot; } } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index 70b69c3ed..4dd37ab42 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -254,6 +254,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms return true; case OpCode.StObj: return true; + case OpCode.CompoundAssignmentInstruction: + return true; } // decide based on the target into which we are inlining diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs new file mode 100644 index 000000000..75b72481e --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs @@ -0,0 +1,265 @@ +// Copyright (c) 2015 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.Decompiler.IL.Transforms +{ + /// + /// Description of TransformAssignment. + /// + public class TransformAssignment : IILTransform + { + ILTransformContext context; + + void IILTransform.Run(ILFunction function, ILTransformContext context) + { + this.context = context; + foreach (var block in function.Descendants.OfType()) { + for (int i = block.Instructions.Count - 1; i >= 0; i--) { + if (TransformPostIncDecOperatorOnAddress(block, i) || TransformCSharp4PostIncDecOperatorOnAddress(block, i)) { + block.Instructions.RemoveAt(i); + continue; + } + if (InlineLdAddressUsages(block, i)) { + block.Instructions.RemoveAt(i); + continue; + } + if (TransformPostIncDecOperator(block, i, function)) { + block.Instructions.RemoveAt(i); + continue; + } + TransformInlineAssignmentStObj(block, i); + } + } + } + + /// + /// stloc s(value) + /// stloc l(ldloc s) + /// stobj(..., ldloc s) + /// --> + /// stloc l(stobj (..., value)) + /// + /// -or- + /// + /// stloc s(value) + /// stobj (..., ldloc s) + /// --> + /// stloc s(stobj (..., value)) + /// + static void TransformInlineAssignmentStObj(Block block, int i) + { + var inst = block.Instructions[i] as StLoc; + if (inst == null || inst.Variable.Kind != VariableKind.StackSlot) + return; + var nextInst = block.Instructions.ElementAtOrDefault(i + 1); + ILInstruction value; + StObj fieldStore; + ILVariable local; + if (nextInst is StLoc) { // instance fields + var localStore = (StLoc)nextInst; + fieldStore = block.Instructions.ElementAtOrDefault(i + 2) as StObj; + if (fieldStore == null) { // otherwise it must local + TransformInlineAssignmentLocal(block, i); + return; + } + if (localStore.Variable.Kind == VariableKind.StackSlot || !localStore.Value.MatchLdLoc(inst.Variable) || !fieldStore.Value.MatchLdLoc(inst.Variable)) + return; + value = inst.Value; + local = localStore.Variable; + block.Instructions.RemoveAt(i + 1); + } else if (nextInst is StObj) { // static fields + fieldStore = (StObj)nextInst; + if (!fieldStore.Value.MatchLdLoc(inst.Variable)) + return; + value = inst.Value; + local = inst.Variable; + } else return; + block.Instructions.RemoveAt(i + 1); + inst.ReplaceWith(new StLoc(local, new StObj(fieldStore.Target, value, fieldStore.Type))); + } + + /// + /// stloc s(value) + /// stloc l(ldloc s) + /// --> + /// stloc s(stloc l(value)) + /// + static void TransformInlineAssignmentLocal(Block block, int i) + { + var inst = block.Instructions[i] as StLoc; + var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; + if (inst == null || nextInst == null) + return; + if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdLoc(inst.Variable)) + return; + var value = inst.Value; + var var = nextInst.Variable; + var stackVar = inst.Variable; + block.Instructions.RemoveAt(i); + nextInst.ReplaceWith(new StLoc(stackVar, new StLoc(var, value))); + } + + /// ldaddress ::= ldelema | ldflda | ldsflda; + /// + /// stloc s(ldaddress) + /// usages of ldobj(ldloc s) or stobj(ldloc s, ...) in next instruction + /// --> + /// use ldaddress instead of ldloc s + /// + static bool InlineLdAddressUsages(Block block, int i) + { + var inst = block.Instructions[i] as StLoc; + if (inst == null || inst.Variable.Kind != VariableKind.StackSlot || !(inst.Value is LdElema || inst.Value is LdFlda || inst.Value is LdsFlda)) + return false; + var valueToCopy = inst.Value; + var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1); + if (nextInstruction == null) + return false; + var affectedUsages = block.Descendants + .OfType() + .Where(ins => ins != inst) + .Where(ins => ins.Variable == inst.Variable) + .Cast().ToArray(); + if (affectedUsages.Length == 0 || affectedUsages.Any(ins => !(ins.Parent is StObj || ins.Parent is LdObj))) + return false; + foreach (var usage in affectedUsages) { + usage.ReplaceWith(valueToCopy.Clone()); + } + return true; + } + + /// + /// stloc s(ldloc l) + /// stloc l(binary.op(ldloc s, ldc.i4 1)) + /// --> + /// stloc s(block { + /// stloc s2(ldloc l) + /// stloc l(binary.op(ldloc s2, ldc.i4 1)) + /// final: ldloc s2 + /// }) + /// + static bool TransformPostIncDecOperator(Block block, int i, ILFunction function) + { + var inst = block.Instructions[i] as StLoc; + var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; + if (inst == null || nextInst == null) + return false; + var binary = nextInst.Value as BinaryNumericInstruction; + if (inst.Variable.Kind != VariableKind.StackSlot || nextInst.Variable.Kind == VariableKind.StackSlot || binary == null) + return false; + if ((binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub) || !binary.Left.MatchLdLoc(inst.Variable) || !binary.Right.MatchLdcI4(1)) + return false; + var tempStore = function.RegisterVariable(VariableKind.StackSlot, inst.Variable.Type); + var assignment = new Block(BlockType.CompoundOperator); + assignment.Instructions.Add(new StLoc(tempStore, new LdLoc(nextInst.Variable))); + assignment.Instructions.Add(new StLoc(nextInst.Variable, new BinaryNumericInstruction(binary.Operator, new LdLoc(tempStore), new LdcI4(1), binary.CheckForOverflow, binary.Sign))); + assignment.FinalInstruction = new LdLoc(tempStore); + nextInst.ReplaceWith(new StLoc(inst.Variable, assignment)); + return true; + } + + /// ldaddress ::= ldelema | ldflda | ldsflda; + /// + /// stloc s(ldaddress) + /// stloc l(ldobj(ldloc s)) + /// stobj(ldloc s, binary.op(ldloc l, ldc.i4 1)) + /// --> + /// stloc l(compound.op.old(ldobj(ldaddress), ldc.i4 1)) + /// + static bool TransformPostIncDecOperatorOnAddress(Block block, int i) + { + var inst = block.Instructions[i] as StLoc; + var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; + var stobj = block.Instructions.ElementAtOrDefault(i + 2) as StObj; + if (inst == null || nextInst == null || stobj == null) + return false; + if (!(inst.Value is LdElema || inst.Value is LdFlda || inst.Value is LdsFlda)) + return false; + ILInstruction target; + IType targetType; + if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdObj(out target, out targetType) || !target.MatchLdLoc(inst.Variable)) + return false; + if (!stobj.Target.MatchLdLoc(inst.Variable)) + return false; + var binary = stobj.Value as BinaryNumericInstruction; + if (binary == null || !binary.Left.MatchLdLoc(nextInst.Variable) || !binary.Right.MatchLdcI4(1) + || (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub)) + return false; + var assignment = new CompoundAssignmentInstruction(binary.Operator, new LdObj(inst.Value, targetType), binary.Right, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue); + stobj.ReplaceWith(new StLoc(nextInst.Variable, assignment)); + block.Instructions.RemoveAt(i + 1); + return true; + } + + /// + /// stloc s(ldflda) + /// stloc s2(ldobj(ldflda(ldloc s))) + /// stloc l(ldloc s2) + /// stobj (ldflda(ldloc s), binary.add(ldloc s2, ldc.i4 1)) + /// --> + /// stloc l(compound.op.old(ldobj(ldflda(ldflda)), ldc.i4 1)) + /// + static bool TransformCSharp4PostIncDecOperatorOnAddress(Block block, int i) + { + var baseFieldAddress = block.Instructions[i] as StLoc; + var fieldValue = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; + var fieldValueCopyToLocal = block.Instructions.ElementAtOrDefault(i + 2) as StLoc; + var stobj = block.Instructions.ElementAtOrDefault(i + 3) as StObj; + if (baseFieldAddress == null || fieldValue == null || fieldValueCopyToLocal == null || stobj == null) + return false; + if (baseFieldAddress.Variable.Kind != VariableKind.StackSlot || fieldValue.Variable.Kind != VariableKind.StackSlot || fieldValueCopyToLocal.Variable.Kind != VariableKind.Local) + return false; + IType t; + IField targetField; + ILInstruction targetFieldLoad, baseFieldAddressLoad2; + if (!fieldValue.Value.MatchLdObj(out targetFieldLoad, out t)) + return false; + ILInstruction baseAddress; + if (baseFieldAddress.Value is LdFlda) { + IField targetField2; + ILInstruction baseFieldAddressLoad3; + if (!targetFieldLoad.MatchLdFlda(out baseFieldAddressLoad2, out targetField) || !baseFieldAddressLoad2.MatchLdLoc(baseFieldAddress.Variable)) + return false; + if (!stobj.Target.MatchLdFlda(out baseFieldAddressLoad3, out targetField2) || !baseFieldAddressLoad3.MatchLdLoc(baseFieldAddress.Variable) || !targetField.Equals(targetField2)) + return false; + baseAddress = new LdFlda(baseFieldAddress.Value, targetField); + } else if (baseFieldAddress.Value is LdElema) { + if (!targetFieldLoad.MatchLdLoc(baseFieldAddress.Variable) || !stobj.Target.MatchLdLoc(baseFieldAddress.Variable)) + return false; + baseAddress = baseFieldAddress.Value; + } else { + return false; + } + BinaryNumericInstruction binary = stobj.Value as BinaryNumericInstruction; + if (binary == null || !binary.Left.MatchLdLoc(fieldValue.Variable) || !binary.Right.MatchLdcI4(1) + || (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub)) + return false; + var assignment = new CompoundAssignmentInstruction(binary.Operator, new LdObj(baseAddress, t), binary.Right, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue); + stobj.ReplaceWith(new StLoc(fieldValueCopyToLocal.Variable, assignment)); + block.Instructions.RemoveAt(i + 2); + block.Instructions.RemoveAt(i + 1); + return true; + } + } +} diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs deleted file mode 100644 index 6febd798c..000000000 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2015 Siegfried Pammer -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.TypeSystem.Implementation; - -namespace ICSharpCode.Decompiler.IL.Transforms -{ - /// - /// Description of TransformInlineAssignment. - /// - public class TransformInlineAssignment : IILTransform - { - ILTransformContext context; - - void IILTransform.Run(ILFunction function, ILTransformContext context) - { - this.context = context; - foreach (var block in function.Descendants.OfType()) { - for (int i = block.Instructions.Count - 1; i >= 0; i--) { - if (InlineLdAddressUsages(block, i)) { - block.Instructions.RemoveAt(i); - continue; - } - TransformInlineAssignmentStObj(block, i); - } - } - } - - /// - /// stloc s(value) - /// stloc l(ldloc s) - /// stobj(..., ldloc s) - /// --> - /// stloc l(stobj (..., value)) - /// - /// -or- - /// - /// stloc s(value) - /// stobj (..., ldloc s) - /// --> - /// stloc s(stobj (..., value)) - /// - static void TransformInlineAssignmentStObj(Block block, int i) - { - var inst = block.Instructions[i] as StLoc; - if (inst == null || inst.Variable.Kind != VariableKind.StackSlot) - return; - var nextInst = block.Instructions.ElementAtOrDefault(i + 1); - ILInstruction value; - StObj fieldStore; - ILVariable local; - if (nextInst is StLoc) { // instance fields - var localStore = (StLoc)nextInst; - fieldStore = block.Instructions.ElementAtOrDefault(i + 2) as StObj; - if (fieldStore == null) { // otherwise it must local - TransformInlineAssignmentLocal(block, i); - return; - } - if (localStore.Variable.Kind == VariableKind.StackSlot || !localStore.Value.MatchLdLoc(inst.Variable) || !fieldStore.Value.MatchLdLoc(inst.Variable)) - return; - value = inst.Value; - local = localStore.Variable; - block.Instructions.RemoveAt(i + 1); - } else if (nextInst is StObj) { // static fields - fieldStore = (StObj)nextInst; - if (!fieldStore.Value.MatchLdLoc(inst.Variable)) - return; - value = inst.Value; - local = inst.Variable; - } else return; - block.Instructions.RemoveAt(i + 1); - inst.ReplaceWith(new StLoc(local, new StObj(fieldStore.Target, value, fieldStore.Type))); - } - - /// - /// stloc s(value) - /// stloc l(ldloc s) - /// --> - /// stloc s(stloc l(value)) - /// - static void TransformInlineAssignmentLocal(Block block, int i) - { - var inst = block.Instructions[i] as StLoc; - var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; - if (inst == null || nextInst == null) - return; - if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdLoc(inst.Variable)) - return; - var value = inst.Value; - var var = nextInst.Variable; - var stackVar = inst.Variable; - block.Instructions.RemoveAt(i); - nextInst.ReplaceWith(new StLoc(stackVar, new StLoc(var, value))); - } - - /// ldaddress ::= ldelema | ldflda | ldsflda; - /// - /// stloc s(ldaddress) - /// usages of ldobj(ldloc s) or stobj(ldloc s, ...) in next instruction - /// --> - /// use ldaddress instead of ldloc s - /// - static bool InlineLdAddressUsages(Block block, int i) - { - var inst = block.Instructions[i] as StLoc; - if (inst == null || inst.Variable.Kind != VariableKind.StackSlot || !(inst.Value is LdElema || inst.Value is LdFlda || inst.Value is LdsFlda)) - return false; - var valueToCopy = inst.Value; - var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1); - if (nextInstruction == null) - return false; - var affectedUsages = nextInstruction.Descendants - .OfType().Where(ins => ins.Variable == inst.Variable) - .Cast().ToArray(); - if (affectedUsages.Length == 0 || affectedUsages.Any(ins => !(ins.Parent is StObj || ins.Parent is LdObj))) - return false; - foreach (var usage in affectedUsages) { - usage.ReplaceWith(valueToCopy.Clone()); - } - return true; - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.cs b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.cs index defa60d7e..caeb7c525 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.cs +++ b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.cs @@ -37,15 +37,70 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } - public void Integer(int i) + public void Int32_Local_Add(int i) { - int V_0 = 0; - if (i > 5) { - V_0 += i; - } - else { - V_0 -= i; - } + i++; + Console.WriteLine(i++); + Console.WriteLine(++i); + i += 5; + Console.WriteLine(i += 5); + } + + public void Int32_Local_Sub(int i) + { + i--; + Console.WriteLine(i--); + Console.WriteLine(--i); + i -= 5; + Console.WriteLine(i -= 5); + } + + public void Int32_Local_Mul(int i) + { + i *= 5; + Console.WriteLine(i *= 5); + } + + public void Int32_Local_Div(int i) + { + i /= 5; + Console.WriteLine(i /= 5); + } + + public void Int32_Local_Rem(int i) + { + i %= 5; + Console.WriteLine(i %= 5); + } + + public void Int32_Local_BitAnd(int i) + { + i &= 5; + Console.WriteLine(i &= 5); + } + + public void Int32_Local_BitOr(int i) + { + i |= 5; + Console.WriteLine(i |= 5); + } + + public void Int32_Local_BitXor(int i) + { + i ^= 5; + Console.WriteLine(i ^= 5); + } + + public void Int32_Local_ShiftLeft(int i) + { + i <<= 5; + Console.WriteLine(i <<= 5); + } + + public void Int32_Local_ShiftRight(int i) + { + i >>= 5; + Console.WriteLine(i >>= 5); } public void IntegerWithInline(int i) @@ -68,11 +123,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty Console.WriteLine(this.array1[i * 2] += i * 2); } + public int GetIndex() + { + return new Random().Next(0, 100); + } + + public int[] GetArray() + { + throw new NotImplementedException(); + } + + public int GetValue(int value) + { + return value; + } + + public int ArrayUsageWithMethods() + { + return this.GetArray()[this.GetIndex()]++; + } public void NestedField() { if (this.field1.HasIndex) { - this.field1.Field++; + Console.WriteLine(this.field1.Field++); } } } diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.il b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.il index f085da9d1..7bed855c0 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.il +++ b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/CompoundAssignmentTest.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly s32trvk2 +.assembly kb1brdcl { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx @@ -20,15 +20,15 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module s32trvk2.exe -// MVID: {09E6012F-15AE-4E0C-B48E-2644E4707595} +.module kb1brdcl.exe +// MVID: {FA9A1DD3-2F44-4DB4-BC5E-6EF79C457314} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01510000 +// Image base: 0x01190000 // =============== CLASS MEMBERS DECLARATION =================== @@ -56,40 +56,240 @@ } // end of method CompoundAssignmentTest::Main .method public hidebysig instance void - Integer(int32 i) cil managed + Int32_Local_Add(int32 i) cil managed { - // Code size 29 (0x1d) - .maxstack 2 - .locals init (int32 V_0, - bool V_1) + // Code size 48 (0x30) + .maxstack 8 IL_0000: nop - IL_0001: ldc.i4.0 - IL_0002: stloc.0 - IL_0003: ldarg.1 - IL_0004: ldc.i4.5 - IL_0005: cgt - IL_0007: ldc.i4.0 - IL_0008: ceq - IL_000a: stloc.1 - IL_000b: ldloc.1 - IL_000c: brtrue.s IL_0016 - - IL_000e: nop - IL_000f: ldloc.0 - IL_0010: ldarg.1 - IL_0011: add - IL_0012: stloc.0 - IL_0013: nop - IL_0014: br.s IL_001c + IL_0001: ldarg.1 + IL_0002: ldc.i4.1 + IL_0003: add + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: dup + IL_0008: ldc.i4.1 + IL_0009: add + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ldarg.1 + IL_0013: ldc.i4.1 + IL_0014: add + IL_0015: dup + IL_0016: starg.s i + IL_0018: call void [mscorlib]System.Console::WriteLine(int32) + IL_001d: nop + IL_001e: ldarg.1 + IL_001f: ldc.i4.5 + IL_0020: add + IL_0021: starg.s i + IL_0023: ldarg.1 + IL_0024: ldc.i4.5 + IL_0025: add + IL_0026: dup + IL_0027: starg.s i + IL_0029: call void [mscorlib]System.Console::WriteLine(int32) + IL_002e: nop + IL_002f: ret + } // end of method CompoundAssignmentTest::Int32_Local_Add + + .method public hidebysig instance void + Int32_Local_Sub(int32 i) cil managed + { + // Code size 48 (0x30) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.1 + IL_0003: sub + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: dup + IL_0008: ldc.i4.1 + IL_0009: sub + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ldarg.1 + IL_0013: ldc.i4.1 + IL_0014: sub + IL_0015: dup + IL_0016: starg.s i + IL_0018: call void [mscorlib]System.Console::WriteLine(int32) + IL_001d: nop + IL_001e: ldarg.1 + IL_001f: ldc.i4.5 + IL_0020: sub + IL_0021: starg.s i + IL_0023: ldarg.1 + IL_0024: ldc.i4.5 + IL_0025: sub + IL_0026: dup + IL_0027: starg.s i + IL_0029: call void [mscorlib]System.Console::WriteLine(int32) + IL_002e: nop + IL_002f: ret + } // end of method CompoundAssignmentTest::Int32_Local_Sub + + .method public hidebysig instance void + Int32_Local_Mul(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: mul + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: mul + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_Mul + + .method public hidebysig instance void + Int32_Local_Div(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: div + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: div + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_Div - IL_0016: nop - IL_0017: ldloc.0 - IL_0018: ldarg.1 - IL_0019: sub - IL_001a: stloc.0 - IL_001b: nop - IL_001c: ret - } // end of method CompoundAssignmentTest::Integer + .method public hidebysig instance void + Int32_Local_Rem(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: rem + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: rem + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_Rem + + .method public hidebysig instance void + Int32_Local_BitAnd(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: and + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: and + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_BitAnd + + .method public hidebysig instance void + Int32_Local_BitOr(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: or + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: or + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_BitOr + + .method public hidebysig instance void + Int32_Local_BitXor(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: xor + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: xor + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_BitXor + + .method public hidebysig instance void + Int32_Local_ShiftLeft(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: shl + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: shl + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_ShiftLeft + + .method public hidebysig instance void + Int32_Local_ShiftRight(int32 i) cil managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.5 + IL_0003: shr + IL_0004: starg.s i + IL_0006: ldarg.1 + IL_0007: ldc.i4.5 + IL_0008: shr + IL_0009: dup + IL_000a: starg.s i + IL_000c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0011: nop + IL_0012: ret + } // end of method CompoundAssignmentTest::Int32_Local_ShiftRight .method public hidebysig instance void IntegerWithInline(int32 i) cil managed @@ -192,12 +392,85 @@ IL_0049: ret } // end of method CompoundAssignmentTest::Array + .method public hidebysig instance int32 + GetIndex() cil managed + { + // Code size 19 (0x13) + .maxstack 3 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: newobj instance void [mscorlib]System.Random::.ctor() + IL_0006: ldc.i4.0 + IL_0007: ldc.i4.s 100 + IL_0009: callvirt instance int32 [mscorlib]System.Random::Next(int32, + int32) + IL_000e: stloc.0 + IL_000f: br.s IL_0011 + + IL_0011: ldloc.0 + IL_0012: ret + } // end of method CompoundAssignmentTest::GetIndex + + .method public hidebysig instance int32[] + GetArray() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: nop + IL_0001: newobj instance void [mscorlib]System.NotImplementedException::.ctor() + IL_0006: throw + } // end of method CompoundAssignmentTest::GetArray + + .method public hidebysig instance int32 + GetValue(int32 'value') cil managed + { + // Code size 7 (0x7) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: stloc.0 + IL_0003: br.s IL_0005 + + IL_0005: ldloc.0 + IL_0006: ret + } // end of method CompoundAssignmentTest::GetValue + + .method public hidebysig instance int32 + ArrayUsageWithMethods() cil managed + { + // Code size 39 (0x27) + .maxstack 3 + .locals init (int32 V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call instance int32[] ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::GetArray() + IL_0007: ldarg.0 + IL_0008: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::GetIndex() + IL_000d: ldelema [mscorlib]System.Int32 + IL_0012: dup + IL_0013: ldobj [mscorlib]System.Int32 + IL_0018: dup + IL_0019: stloc.1 + IL_001a: ldc.i4.1 + IL_001b: add + IL_001c: stobj [mscorlib]System.Int32 + IL_0021: ldloc.1 + IL_0022: stloc.0 + IL_0023: br.s IL_0025 + + IL_0025: ldloc.0 + IL_0026: ret + } // end of method CompoundAssignmentTest::ArrayUsageWithMethods + .method public hidebysig instance void NestedField() cil managed { - // Code size 41 (0x29) + // Code size 50 (0x32) .maxstack 3 - .locals init (bool V_0) + .locals init (bool V_0, + int32 V_1) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/StructContainer ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::field1 @@ -206,18 +479,23 @@ IL_000d: ceq IL_000f: stloc.0 IL_0010: ldloc.0 - IL_0011: brtrue.s IL_0028 + IL_0011: brtrue.s IL_0031 IL_0013: nop IL_0014: ldarg.0 IL_0015: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/StructContainer ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::field1 IL_001a: dup IL_001b: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/StructContainer::Field - IL_0020: ldc.i4.1 - IL_0021: add - IL_0022: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/StructContainer::Field - IL_0027: nop - IL_0028: ret + IL_0020: dup + IL_0021: stloc.1 + IL_0022: ldc.i4.1 + IL_0023: add + IL_0024: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/StructContainer::Field + IL_0029: ldloc.1 + IL_002a: call void [mscorlib]System.Console::WriteLine(int32) + IL_002f: nop + IL_0030: nop + IL_0031: ret } // end of method CompoundAssignmentTest::NestedField .method public hidebysig specialname rtspecialname diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/HelloWorld.il b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/HelloWorld.il index c14b8d76a..be1b80f81 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/HelloWorld.il +++ b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/HelloWorld.il @@ -1,13 +1,16 @@ + // Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929 // Copyright (c) Microsoft Corporation. All rights reserved. + + // Metadata version: v4.0.30319 .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly ndx1gr1f +.assembly xxnyzhlv { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx @@ -17,15 +20,15 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module ndx1gr1f.exe -// MVID: {8005ACF2-3B7B-47F2-8D51-C16AB15E3999} +.module xxnyzhlv.exe +// MVID: {81192B72-DC9D-4496-83E9-F42A6852B7DB} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01140000 +// Image base: 0x00BC0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -55,4 +58,10 @@ IL_0006: ret } // end of method HelloWorld::.ctor -} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.HelloWorld.HelloWorld \ No newline at end of file +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.HelloWorld.HelloWorld + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file ../../Tests/TestCases/Pretty\HelloWorld.res diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs index db6e3d8c4..67a47aa1d 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs +++ b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs @@ -85,5 +85,25 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { return this.field3[i] = 1; } + + public int GetIndex() + { + return new Random().Next(0, 100); + } + + public int[] GetArray() + { + throw new NotImplementedException(); + } + + public int GetValue(int value) + { + return value; + } + + public int ArrayUsageWithMethods() + { + return this.GetArray()[this.GetIndex()] = this.GetValue(this.GetIndex()); + } } } diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il index cf73422e8..003be1a93 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il +++ b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly siuuofgg +.assembly ddqu2emz { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx @@ -20,15 +20,15 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module siuuofgg.exe -// MVID: {7C4F4FA4-F91C-4C75-A521-2E31EFBCDAC8} +.module ddqu2emz.exe +// MVID: {E3C9CEDE-53B1-4B60-977E-6E7ECB67DB34} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x016A0000 +// Image base: 0x03080000 // =============== CLASS MEMBERS DECLARATION =================== @@ -222,6 +222,77 @@ IL_0011: ret } // end of method InlineAssignmentTest::Array2 + .method public hidebysig instance int32 + GetIndex() cil managed + { + // Code size 19 (0x13) + .maxstack 3 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: newobj instance void [mscorlib]System.Random::.ctor() + IL_0006: ldc.i4.0 + IL_0007: ldc.i4.s 100 + IL_0009: callvirt instance int32 [mscorlib]System.Random::Next(int32, + int32) + IL_000e: stloc.0 + IL_000f: br.s IL_0011 + + IL_0011: ldloc.0 + IL_0012: ret + } // end of method InlineAssignmentTest::GetIndex + + .method public hidebysig instance int32[] + GetArray() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: nop + IL_0001: newobj instance void [mscorlib]System.NotImplementedException::.ctor() + IL_0006: throw + } // end of method InlineAssignmentTest::GetArray + + .method public hidebysig instance int32 + GetValue(int32 'value') cil managed + { + // Code size 7 (0x7) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: stloc.0 + IL_0003: br.s IL_0005 + + IL_0005: ldloc.0 + IL_0006: ret + } // end of method InlineAssignmentTest::GetValue + + .method public hidebysig instance int32 + ArrayUsageWithMethods() cil managed + { + // Code size 34 (0x22) + .maxstack 4 + .locals init (int32 V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call instance int32[] ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::GetArray() + IL_0007: ldarg.0 + IL_0008: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::GetIndex() + IL_000d: ldarg.0 + IL_000e: ldarg.0 + IL_000f: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::GetIndex() + IL_0014: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::GetValue(int32) + IL_0019: dup + IL_001a: stloc.1 + IL_001b: stelem.i4 + IL_001c: ldloc.1 + IL_001d: stloc.0 + IL_001e: br.s IL_0020 + + IL_0020: ldloc.0 + IL_0021: ret + } // end of method InlineAssignmentTest::ArrayUsageWithMethods + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed {