private bool ReplaceChainedShortCircuitBooleanPattern(List <IStatement> statements, int i) { ConditionalStatement conditionalStatement = (ConditionalStatement)statements[i]; if (!this.ReplaceShortCircuitPattern(statements, i + 1)) { if (!this.ReplaceShortCircuitPatternCreatedByCCI2(statements, i + 1)) { return(false); } } //if (!this.ReplaceShortCircuitPattern(statements, i+1)) return false; PushStatement /*?*/ push = statements[i + 1] as PushStatement; if (push == null) { return(false); } Conditional /*?*/ chainedConditional = push.ValueToPush as Conditional; if (chainedConditional == null) { return(false); } return(this.ReplaceShortCircuitPattern(statements, i)); }
public override IExpression Visit(IExpression expression) { Pop pop = expression as Pop; if (pop != null) { if (this.numberOfPopsToIgnore-- > 0) { return(expression); } PushStatement push = (PushStatement)this.statements[this.i++]; if (pop is PopAsUnsigned) { return(new ConvertToUnsigned(push.ValueToPush)); } else { return(push.ValueToPush); } } return(base.Visit(expression)); }
public override IStatement Visit(IStatement statement) { IGotoStatement gotoStatement = statement as IGotoStatement; if (gotoStatement != null) { this.visitedUnconditionalBranch = true; foreach (object ob in this.path) { if (ob is IConditionalStatement) { this.visitedUnconditionalBranch = false; } } StackOfLocals newStack = null; if (this.stackFor.TryGetValue(gotoStatement.TargetStatement, out newStack)) { return(this.TransferStack(gotoStatement, newStack)); } this.stackFor.Add(gotoStatement.TargetStatement, this.operandStack.Clone(this.block)); return(gotoStatement); } ILabeledStatement labeledStatement = statement as ILabeledStatement; if (labeledStatement != null) { StackOfLocals newStack = null; if (this.stackFor.TryGetValue(labeledStatement, out newStack)) { return(this.TransferStack(labeledStatement, newStack)); } this.stackFor.Add(labeledStatement, this.operandStack.Clone(this.block)); return(labeledStatement); } PushStatement /*?*/ push = statement as PushStatement; if (push != null) { push.ValueToPush = this.Visit(push.ValueToPush); this.tempCounter = this.body.localVariablesAndTemporaries.Count; var temp = new TempVariable() { Name = this.body.host.NameTable.GetNameFor("__temp_" + this.tempCounter++) }; temp.Type = push.ValueToPush.Type; this.operandStack.Push(temp); this.body.numberOfReferences.Add(temp, 0); var ctc = push.ValueToPush as ICompileTimeConstant; // "push null" doesn't tell us enough to know what type it really is if (ctc != null && ctc.Value == null) // REVIEW: need to make sure the type is a reference type? { temp.isPolymorphic = true; } var be = push.ValueToPush as IBoundExpression; if (be != null) { var sourceLocal = be.Definition as TempVariable; if (sourceLocal != null && sourceLocal.isPolymorphic) { temp.isPolymorphic = true; } } if (push.ValueToPush.Type is IManagedPointerTypeReference) { temp.turnIntoPopValueExpression = true; return(statement); } this.body.localVariablesAndTemporaries.Add(temp); if (this.block.LocalVariables == null) { this.block.LocalVariables = new List <ILocalDefinition>(); } this.block.LocalVariables.Add(temp); this.body.numberOfAssignments.Add(temp, 1); return(new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Definition = temp }, Source = push.ValueToPush }, Locations = push.Locations }); } if (statement is EndFilter || statement is EndFinally) { this.visitedUnconditionalBranch = true; return(statement); } if (statement is SwitchInstruction) { return(statement); } return(base.Visit(statement)); }
private void ReplaceLocalArrayInitializerPattern(List <IStatement> statements, int i) { if (i > statements.Count - 4) { return; } PushStatement /*?*/ push = statements[i] as PushStatement; if (push == null) { return; } var pushDup = statements[i + 1] as PushStatement; if (pushDup == null || !(pushDup.ValueToPush is Dup)) { return; } CreateArray /*?*/ createArray = push.ValueToPush as CreateArray; if (createArray == null) { return; } ExpressionStatement /*?*/ expressionStatement = statements[i + 2] as ExpressionStatement; if (expressionStatement == null) { return; } MethodCall /*?*/ methodCall = expressionStatement.Expression as MethodCall; if (methodCall == null || !methodCall.IsStaticCall || methodCall.IsJumpCall || methodCall.Arguments.Count != 2) { return; } var pop = methodCall.Arguments[0] as Pop; if (pop == null) { return; } TokenOf /*?*/ tokenOf = methodCall.Arguments[1] as TokenOf; if (tokenOf == null) { return; } IFieldDefinition /*?*/ initialValueField = tokenOf.Definition as IFieldDefinition; if (initialValueField == null || !initialValueField.IsMapped) { return; } if (methodCall.MethodToCall.Name.UniqueKey != this.InitializeArray.UniqueKey) { return; } List <ulong> sizes = new List <ulong>(); foreach (IExpression expr in createArray.Sizes) { IMetadataConstant mdc = expr as IMetadataConstant; if (mdc == null) { return; } sizes.Add(ConvertToUlong(mdc)); } AddArrayInitializers(createArray, initialValueField, sizes.ToArray()); expressionStatement = statements[i + 3] as ExpressionStatement; if (expressionStatement != null) { Assignment /*?*/ assignment = expressionStatement.Expression as Assignment; if (assignment != null) { var pop2 = assignment.Source as Pop; if (pop2 != null) { assignment.Source = createArray; statements[i] = expressionStatement; statements.RemoveRange(i + 1, 3); return; } } } push.ValueToPush = createArray; statements.RemoveRange(i + 1, 2); }
private void ReplacePushPopPattern(List <IStatement> statements, int i) { if (i > statements.Count - 2) { return; } //First identify count consecutive push statements int count = 0; while (i + count < statements.Count - 1 && statements[i + count] is PushStatement) { count++; } while (i > 1 && statements[i - 1] is PushStatement) { i--; count++; } if (count == 0) { return; } for (int j = 0; j < count; j++) { if (((PushStatement)statements[j + i]).ValueToPush is Dup) { return; } } //If any of the push statements (other than the first one) contains pop expressions, replace them with the corresponding push values and remove the pushes. int pushcount = 1; //the number of push statements that are eligble for removal at this point. for (int j = i + 1; j < i + count; j++) { PushStatement st = (PushStatement)statements[j]; PopCounter pcc = new PopCounter(); new CodeTraverser() { PreorderVisitor = pcc }.Traverse(st.ValueToPush); int numberOfPushesToRemove = pushcount; if (pcc.count > 0) { if (pcc.count < numberOfPushesToRemove) { numberOfPushesToRemove = pcc.count; } int firstPushToRemove = j - numberOfPushesToRemove; PopReplacer prr = new PopReplacer(this.sourceMethodBody.host, statements, firstPushToRemove, pcc.count - numberOfPushesToRemove); st.ValueToPush = prr.Visit(st.ValueToPush); statements.RemoveRange(firstPushToRemove, numberOfPushesToRemove); j = j - pcc.count; count = count - pcc.count; pushcount = pushcount - pcc.count; } pushcount++; } //If the next statement is an expression statement that pops some of the just pushed values, replace those pops with the pushed values and remove the pushes. ExpressionStatement /*?*/ expressionStatement = statements[i + count] as ExpressionStatement; if (expressionStatement == null) { return; } PopCounter pc = new PopCounter(); new CodeTraverser() { PreorderVisitor = pc }.Traverse(expressionStatement.Expression); if (pc.count == 0) { return; } if (pc.count < count) { i += count - pc.count; //adjust i to point to the first push statement to remove because of subsequent pops. count = pc.count; } PopReplacer pr = new PopReplacer(this.sourceMethodBody.host, statements, i, pc.count - count); expressionStatement.Expression = pr.Visit(expressionStatement.Expression); expressionStatement.Locations.AddRange(statements[i].Locations); statements.RemoveRange(i, count); }
/// <summary> /// Finds the following pattern: /// i : c ? A : B; // either A or B must be an empty statement and the other is "goto L1;" /// i+1 : push x; /// i+2 : goto L2; /// i+3 : Block1 /// 0 : L1; /// 1 : push y; /// 2 : goto L2; /// 3 : Block2 /// 0 : whatever (but presumably it is the label L2) /// /// Transforms it into: /// i : push d ? X : Y; /// i+1 : goto L1; /// i+2 : Block 2 /// /// Where if A is the empty statement, /// d == c, X == x, Y == y /// If B is the empty statement and y is zero /// d == !c, X == x, Y == y /// If B is the empty statement and y is not zero /// d == c, X == y, Y == x /// And Block1 is deleted from the list. /// </summary> private bool ReplaceShortCircuitPatternCreatedByCCI2(List <IStatement> statements, int i) { if (i > statements.Count - 4) { return(false); } ConditionalStatement /*?*/ conditionalStatement = statements[i] as ConditionalStatement; if (conditionalStatement == null) { return(false); } PushStatement /*?*/ push1 = statements[i + 1] as PushStatement; if (push1 == null) { return(false); } GotoStatement /*?*/ Goto = statements[i + 2] as GotoStatement; if (Goto == null) { return(false); } BasicBlock /*?*/ block1 = statements[i + 3] as BasicBlock; if (block1 == null) { return(false); } if (block1.Statements.Count < 4) { return(false); } LabeledStatement /*?*/ label = block1.Statements[0] as LabeledStatement; if (label == null) { return(false); } List <IGotoStatement> branchesToThisLabel; if (this.predecessors.TryGetValue(label, out branchesToThisLabel)) { if (1 < branchesToThisLabel.Count) { return(false); } } // TODO? Should we make sure that one of the branches in the conditionalStatement is // to label? PushStatement /*?*/ push2 = block1.Statements[1] as PushStatement; if (push2 == null) { return(false); } GotoStatement /*?*/ Goto2 = block1.Statements[2] as GotoStatement; if (Goto2 == null) { return(false); } if (Goto.TargetStatement != Goto2.TargetStatement) { return(false); } BasicBlock /*?*/ block2 = block1.Statements[3] as BasicBlock; if (block2 == null) { return(false); } if (conditionalStatement.TrueBranch is EmptyStatement) { Conditional conditional = new Conditional(); conditional.Condition = conditionalStatement.Condition; conditional.ResultIfTrue = push1.ValueToPush; conditional.ResultIfFalse = push2.ValueToPush; conditional.Type = TypeHelper.MergedType(TypeHelper.StackType(conditional.ResultIfTrue.Type), TypeHelper.StackType(conditional.ResultIfFalse.Type)); push1.ValueToPush = conditional; push1.Locations = conditionalStatement.Locations; statements[i] = push1; statements[i + 1] = statements[i + 2]; // move the goto up statements[i + 2] = block2; statements.RemoveRange(i + 3, 1); return(true); } if (conditionalStatement.FalseBranch is EmptyStatement) { Conditional conditional = new Conditional(); if (ExpressionHelper.IsIntegralZero(push2.ValueToPush)) { conditional.Condition = InvertCondition(conditionalStatement.Condition); conditional.ResultIfTrue = push1.ValueToPush; conditional.ResultIfFalse = push2.ValueToPush; } else { conditional.Condition = conditionalStatement.Condition; conditional.ResultIfTrue = push2.ValueToPush; conditional.ResultIfFalse = push1.ValueToPush; } conditional.Locations = conditionalStatement.Locations; conditional.Type = TypeHelper.MergedType(TypeHelper.StackType(conditional.ResultIfTrue.Type), TypeHelper.StackType(conditional.ResultIfFalse.Type)); push1.ValueToPush = conditional; push1.Locations = conditionalStatement.Locations; statements[i] = push1; statements[i + 1] = statements[i + 2]; // move the goto up statements[i + 2] = block2; statements.RemoveRange(i + 3, 1); return(true); } return(false); }
/// <summary> /// Finds the following pattern: /// i : if (c) A else B; // either A or B must be an empty statement and the other is "goto L1;" /// i+1 : push x; /// i+2 : goto L2; /// i+3 : Block1 /// 0 : L1; /// 1 : push y; /// 2 : Block2 /// 0 : L2; /// 1 : (rest of statements in Block2) /// /// Transforms it into: /// i : push (d ? X : Y); /// i+1 : (rest of statements in Block2, preceded by L2 if there are more branches to L2 than just the one that was at i+2) /// /// Where if A is the empty statement, then /// d == c, X == x, Y == y /// If B is the empty statement, then if y is zero, /// d == !c, X == x, Y == y /// If B is the empty statement, then if y is not zero, /// d == c, X == y, Y == x /// </summary> private bool ReplaceShortCircuitPattern(List <IStatement> statements, int i) { if (i > statements.Count - 4) { return(false); } ConditionalStatement /*?*/ conditionalStatement = statements[i] as ConditionalStatement; if (conditionalStatement == null) { return(false); } if (statements[i + 1] is ConditionalStatement) { return(this.ReplaceChainedShortCircuitBooleanPattern(statements, i)); } GotoStatement /*?*/ gotoL1 = null; if (conditionalStatement.TrueBranch is EmptyStatement) { gotoL1 = conditionalStatement.FalseBranch as GotoStatement; } else if (conditionalStatement.FalseBranch is EmptyStatement) { gotoL1 = conditionalStatement.TrueBranch as GotoStatement; } if (gotoL1 == null) { return(false); } PushStatement /*?*/ push = statements[i + 1] as PushStatement; if (push == null) { return(false); } GotoStatement /*?*/ gotoL2 = statements[i + 2] as GotoStatement; if (gotoL2 == null) { return(false); } BasicBlock /*?*/ block = statements[i + 3] as BasicBlock; if (block == null) { return(false); } if (block.Statements.Count < 3) { return(false); } LabeledStatement /*?*/ l1 = block.Statements[0] as LabeledStatement; if (l1 == null) { return(false); } if (l1 != gotoL1.TargetStatement) { return(false); } List <IGotoStatement> branchesToThisLabel; if (this.predecessors.TryGetValue(l1, out branchesToThisLabel)) { if (branchesToThisLabel.Count > 1) { return(false); } } PushStatement /*?*/ push2 = block.Statements[1] as PushStatement; if (push2 == null) { return(false); } BasicBlock /*?*/ block2 = block.Statements[2] as BasicBlock; if (block2 == null || block2.Statements.Count < 1 || block2.Statements[0] != gotoL2.TargetStatement) { return(false); } Conditional conditional = new Conditional(); if (conditionalStatement.TrueBranch is EmptyStatement) { conditional.Condition = conditionalStatement.Condition; conditional.ResultIfTrue = push.ValueToPush; conditional.ResultIfFalse = push2.ValueToPush; } else if (conditionalStatement.FalseBranch is EmptyStatement) { if (ExpressionHelper.IsIntegralZero(push2.ValueToPush)) { conditional.Condition = InvertCondition(conditionalStatement.Condition); conditional.ResultIfTrue = push.ValueToPush; conditional.ResultIfFalse = push2.ValueToPush; } else { conditional.Condition = conditionalStatement.Condition; conditional.ResultIfTrue = push2.ValueToPush; conditional.ResultIfFalse = push.ValueToPush; } } conditional.Type = TypeHelper.MergedType(TypeHelper.StackType(conditional.ResultIfTrue.Type), TypeHelper.StackType(conditional.ResultIfFalse.Type)); conditional.Locations = conditionalStatement.Locations; push.ValueToPush = conditional; push.Locations = conditional.Locations; statements[i] = push; statements.RemoveRange(i + 1, 3); var l2 = gotoL2.TargetStatement; this.predecessors.TryGetValue(l2, out branchesToThisLabel); branchesToThisLabel.Remove(gotoL2); if (branchesToThisLabel.Count == 0) { block2.Statements.RemoveAt(0); } statements.InsertRange(i + 1, block2.Statements); return(true); }
private ILocalDefinition ExtractExceptionContainer(DecompiledBlock nestedBlock, ITypeReference exceptionType) { Contract.Requires(nestedBlock != null); Contract.Requires(exceptionType != null); Contract.Ensures(Contract.Result <ILocalDefinition>() != null); Contract.Assume(nestedBlock.Statements.Count > 0); int i = 0; while (nestedBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < nestedBlock.Statements.Count); } ; var firstStatement = nestedBlock.Statements[i++]; var firstBlock = firstStatement as DecompiledBlock; while (firstBlock != null) { Contract.Assume(firstBlock.Statements.Count > 0); i = 0; while (firstBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < firstBlock.Statements.Count); } ; firstStatement = firstBlock.Statements[i++]; nestedBlock = firstBlock; firstBlock = firstStatement as DecompiledBlock; } //Ignoring any local declarations inserted for lexical scopes, any decompiled block that does not start with a nested block, starts with a label. Contract.Assume(firstStatement is LabeledStatement); if (nestedBlock.Statements.Count > i) { var exprStatement = nestedBlock.Statements[i] as ExpressionStatement; if (exprStatement != null) { nestedBlock.Statements.RemoveRange(i - 1, 2); if (exprStatement.Expression is PopValue) { return(Dummy.LocalVariable); } var assignment = exprStatement.Expression as Assignment; if (assignment != null && assignment.Source is PopValue) { var local = assignment.Target.Definition as ILocalDefinition; if (local != null) { return(local); //if not, this is not a recognized code pattern. } } } // can't find the local, so just introduce one and leave its value on the stack var ld = new LocalDefinition() { Type = exceptionType, }; var pushStatement = new PushStatement() { ValueToPush = new BoundExpression() { Definition = ld, Type = exceptionType, }, }; nestedBlock.Statements.Insert(0, pushStatement); return(ld); } else { //Valid IL should always have at least one instruction to consume the exception value as well as a branch out of the handler block. Contract.Assume(false); return(Dummy.LocalVariable); } }