internal static bool ReplacePushPopPattern(BlockStatement b, IMetadataHost host) { Contract.Requires(b != null); Contract.Requires(host != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count-1; i++) { //First identify count consecutive push statements int count = 0; while (i+count < statements.Count-1 && statements[i+count] is PushStatement) count++; if (count == 0) continue; Contract.Assert(i+count < statements.Count); Contract.Assert(count < statements.Count); for (int j = 0; j < count; j++) { Contract.Assume(statements[i+j] is PushStatement); if (((PushStatement)statements[i+j]).ValueToPush is DupValue) goto nextIteration; } Contract.Assert(i >= 0); Contract.Assert(i < statements.Count-1); //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++) { Contract.Assume(j < statements.Count); //because i+count < statements.Count for the initial value of count and count just decreases Contract.Assume(j >= 0); //because i >= 0 and j never decreases to less than i Contract.Assume(statements[j] is PushStatement); //because i < j < i+count and i..i+count-1 are all push statements PushStatement st = (PushStatement)statements[j]; PopCounter pcc = new PopCounter(); 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(host, statements, firstPushToRemove, pcc.count-numberOfPushesToRemove); st.ValueToPush = prr.Rewrite(st.ValueToPush); statements.RemoveRange(firstPushToRemove, numberOfPushesToRemove); if (pcc.count > numberOfPushesToRemove) return true; //We've consumed all of the pushes and we're done. count -= numberOfPushesToRemove; //Fewer pushes now remain pushcount -= numberOfPushesToRemove; //Likewise fewer eligible pushes remain //Start over again at firstPushToRemove, which now indexes the first statement not yet considered. j = firstPushToRemove-1; continue; } pushcount++; } Contract.Assume(count >= 0); Contract.Assume(i+count < statements.Count); var nextStatement = statements[i + count]; Contract.Assume(nextStatement != null); if (!(nextStatement is IExpressionStatement || nextStatement is IPushStatement || nextStatement is IReturnStatement || nextStatement is IThrowStatement)) continue; PopCounter pc = new PopCounter(); pc.Traverse(nextStatement); if (pc.count == 0) continue; 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; } Contract.Assume(i < statements.Count); PopReplacer pr = new PopReplacer(host, statements, i, pc.count-count); pr.Rewrite(nextStatement); var s = nextStatement as Statement; if (s != null) s.Locations.AddRange(statements[i].Locations); Contract.Assume(count >= 0); Contract.Assert(i+count < statements.Count); statements.RemoveRange(i, count); replacedPattern = true; nextIteration: ; } return replacedPattern; }
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); }
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); statements.RemoveRange(i, count); }