Skip to content

Commit

Permalink
Fix #167 - infinite loop representation
Browse files Browse the repository at this point in the history
  • Loading branch information
leibnitz27 committed May 17, 2020
1 parent 7fba9d8 commit 57b396b
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ private List<Op04StructuredStatement> getIfBlock(Op04StructuredStatement maybeBl
public StructuredStatement transform(StructuredStatement in, StructuredScope scope) {
in.transformStructuredChildren(this, scope);

if (!(in instanceof StructuredDo)) return in;

StructuredDo structuredDo = (StructuredDo) in;
BlockIdentifier blockIdent = structuredDo.getBlock();
// Either a do or a while with no condition is acceptable.
if (!(in instanceof AbstractStructuredConditionalLoopStatement)) {
return in;
}
AbstractStructuredConditionalLoopStatement asl = (AbstractStructuredConditionalLoopStatement)in;
if (!asl.isInfinite()) return in;

if (structuredDo.getCondition() != null) return in;
Op04StructuredStatement body = asl.getBody();
BlockIdentifier blockIdent = asl.getBlock();

List<Op04StructuredStatement> statements = getIfBlock(((StructuredDo) in).getBody());
List<Op04StructuredStatement> statements = getIfBlock(body);
/*
* If the FIRST statement is a conditional, which is either a break or a return, then we can
* transform the entire loop into a while (!conditional) instead, which is much nicer.
Expand Down Expand Up @@ -73,9 +76,9 @@ public StructuredStatement transform(StructuredStatement in, StructuredScope sco
}

statements.remove(0);
ConditionalExpression condition = ifStatement.getConditionalExpression().getNegated().simplify();
ConditionalExpression newCondition = ifStatement.getConditionalExpression().getNegated().simplify();

StructuredWhile structuredWhile = new StructuredWhile(condition, structuredDo.getBody(), blockIdent);
StructuredWhile structuredWhile = new StructuredWhile(newCondition, body, blockIdent);
if (!liftTestBody) return structuredWhile;

Block lifted = Block.getBlockFor(false, structuredWhile, structuredExit);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers;

import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement;
import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.ExpressionReplacingRewriter;
import org.benf.cfr.reader.bytecode.analysis.parse.Expression;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.*;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.BoolOp;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.BooleanExpression;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.BooleanOperation;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.ConditionalExpression;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.LValueExpression;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.NotOperation;
import org.benf.cfr.reader.bytecode.analysis.parse.lvalue.StaticVariable;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.BlockIdentifier;
import org.benf.cfr.reader.bytecode.analysis.parse.wildcard.WildcardMatch;
import org.benf.cfr.reader.bytecode.analysis.structured.StructuredScope;
import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement;
import org.benf.cfr.reader.bytecode.analysis.structured.statement.*;
import org.benf.cfr.reader.bytecode.analysis.structured.statement.AbstractStructuredBlockStatement;
import org.benf.cfr.reader.bytecode.analysis.structured.statement.Block;
import org.benf.cfr.reader.bytecode.analysis.structured.statement.StructuredDo;
import org.benf.cfr.reader.bytecode.analysis.structured.statement.StructuredIf;
import org.benf.cfr.reader.bytecode.analysis.structured.statement.StructuredThrow;
import org.benf.cfr.reader.bytecode.analysis.structured.statement.StructuredWhile;
import org.benf.cfr.reader.bytecode.analysis.types.TypeConstants;

import java.util.List;
Expand All @@ -26,11 +36,6 @@ public class InfiniteAssertRewriter implements StructuredStatementTransformer

public InfiniteAssertRewriter(StaticVariable assertionStatic) {

// new BooleanOperation(
// new NotOperation(new BooleanExpression(new LValueExpression(assertionStatic))),
// wcm1.getConditionalExpressionWildcard("condition"),
// BoolOp.AND);

match1 = new BooleanExpression(new LValueExpression(assertionStatic));
match2 = new BooleanOperation(new BooleanExpression(new LValueExpression(assertionStatic)),
wcm1.getConditionalExpressionWildcard("condition"),
Expand Down Expand Up @@ -65,7 +70,7 @@ public StructuredStatement transform(StructuredStatement in, StructuredScope sco
wcm1.reset();
ConditionalExpression ce = sw.getCondition();
if (match1.equals(ce) || match2.equals(ce)) {
replaceThrow(next, stm, ce);
replaceThrow(next, stm, sw.getBlock(), ce);
}
continue;
}
Expand All @@ -77,7 +82,7 @@ public StructuredStatement transform(StructuredStatement in, StructuredScope sco
wcm1.reset();
ConditionalExpression ce = sw.getCondition();
if (match2.equals(ce)) {
replaceThrow(next, stm, ce);
replaceThrow(next, stm, sw.getBlock(), ce);
}
continue;
}
Expand All @@ -86,11 +91,11 @@ public StructuredStatement transform(StructuredStatement in, StructuredScope sco
}


private void replaceThrow(Op04StructuredStatement thrw, Op04StructuredStatement whil, ConditionalExpression cond) {
whil.getStatement().rewriteExpressions(new ExpressionReplacingRewriter(cond, BooleanExpression.TRUE));
private void replaceThrow(Op04StructuredStatement thrw, Op04StructuredStatement whil, BlockIdentifier ident, ConditionalExpression cond) {
StructuredStatement throwInner = thrw.getStatement();
AbstractStructuredBlockStatement sw = (AbstractStructuredBlockStatement)whil.getStatement();
Op04StructuredStatement body = sw.getBody();
whil.replaceStatement(StructuredDo.create(null, body, ident));
StructuredStatement bodyContent = body.getStatement();
if (!(bodyContent instanceof Block)) {
bodyContent = new Block(new Op04StructuredStatement(bodyContent));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.benf.cfr.reader.bytecode.analysis.structured.statement;

import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.ConditionalExpression;
import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.ExpressionRewriter;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.BlockIdentifier;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.scope.LValueScopeDiscoverer;
import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement;
import org.benf.cfr.reader.state.TypeUsageCollector;

import java.util.List;

// do / while.
public abstract class AbstractStructuredConditionalLoopStatement extends AbstractStructuredBlockStatement {
protected ConditionalExpression condition;
protected final BlockIdentifier block;

AbstractStructuredConditionalLoopStatement(ConditionalExpression condition, BlockIdentifier block, Op04StructuredStatement body) {
super(body);
this.condition = condition;
this.block = block;
}

public BlockIdentifier getBlock() {
return block;
}

public ConditionalExpression getCondition() {
return condition;
}

@Override
public BlockIdentifier getBreakableBlockOrNull() {
return block;
}

@Override
public boolean supportsBreak() {
return true;
}

@Override
public void collectTypeUsages(TypeUsageCollector collector) {
collector.collectFrom(condition);
super.collectTypeUsages(collector);
}

public boolean isInfinite() {
return condition == null;
}

@Override
public boolean isScopeBlock() {
return true;
}

@Override
public boolean supportsContinueBreak() {
return true;
}

@Override
public void traceLocalVariableScope(LValueScopeDiscoverer scopeDiscoverer) {
if (condition != null) {
condition.collectUsedLValues(scopeDiscoverer);
}
scopeDiscoverer.processOp04Statement(getBody());
}

@Override
public void linearizeInto(List<StructuredStatement> out) {
out.add(this);
getBody().linearizeStatementsInto(out);
}

@Override
public void rewriteExpressions(ExpressionRewriter expressionRewriter) {
if (condition != null) {
condition = expressionRewriter.rewriteExpression(condition, null, this.getContainer(), null);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,14 @@
import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil.MatchIterator;
import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil.MatchResultCollector;
import org.benf.cfr.reader.bytecode.analysis.parse.expression.ConditionalExpression;
import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.ExpressionRewriter;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.BlockIdentifier;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.scope.LValueScopeDiscoverer;
import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement;
import org.benf.cfr.reader.state.TypeUsageCollector;
import org.benf.cfr.reader.util.output.Dumper;

import java.util.List;
public class StructuredDo extends AbstractStructuredConditionalLoopStatement {

public class StructuredDo extends AbstractStructuredBlockStatement {
private ConditionalExpression condition;
private final BlockIdentifier block;

public StructuredDo(ConditionalExpression condition, Op04StructuredStatement body, BlockIdentifier block) {
super(body);
this.condition = condition;
this.block = block;
private StructuredDo(ConditionalExpression condition, Op04StructuredStatement body, BlockIdentifier block) {
super(condition, block, body);
}

@Override
Expand All @@ -38,59 +29,6 @@ public Dumper dump(Dumper dumper) {
return dumper.print(");").newln();
}

@Override
public void collectTypeUsages(TypeUsageCollector collector) {
collector.collectFrom(condition);
super.collectTypeUsages(collector);
}

@Override
public boolean isScopeBlock() {
return true;
}

@Override
public boolean supportsContinueBreak() {
return true;
}

@Override
public void traceLocalVariableScope(LValueScopeDiscoverer scopeDiscoverer) {
if (condition != null) condition.collectUsedLValues(scopeDiscoverer);
scopeDiscoverer.processOp04Statement(getBody());
}

@Override
public void linearizeInto(List<StructuredStatement> out) {
out.add(this);
getBody().linearizeStatementsInto(out);
}

@Override
public void rewriteExpressions(ExpressionRewriter expressionRewriter) {
if (condition != null) {
condition = expressionRewriter.rewriteExpression(condition, null, this.getContainer(), null);
}
}

public BlockIdentifier getBlock() {
return block;
}

public ConditionalExpression getCondition() {
return condition;
}

@Override
public BlockIdentifier getBreakableBlockOrNull() {
return block;
}

@Override
public boolean supportsBreak() {
return true;
}

@Override
public boolean match(MatchIterator<StructuredStatement> matchIterator, MatchResultCollector matchResultCollector) {
StructuredStatement o = matchIterator.getCurrent();
Expand All @@ -107,4 +45,15 @@ public boolean match(MatchIterator<StructuredStatement> matchIterator, MatchResu
return true;
}

// https://github.com/leibnitz27/cfr/issues/167
// At great personal cost, I concur that the majority of developers are crazy, and prefer
// while(true) {}
// to
// do {} while (true).
public static AbstractStructuredConditionalLoopStatement create(ConditionalExpression condition, Op04StructuredStatement body, BlockIdentifier block) {
if (condition == null) {
return new StructuredWhile(null, body, block);
}
return new StructuredDo(condition, body, block);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,71 +13,25 @@

import java.util.List;

public class StructuredWhile extends AbstractStructuredBlockStatement {
private ConditionalExpression condition;
private final BlockIdentifier block;

public class StructuredWhile extends AbstractStructuredConditionalLoopStatement {
public StructuredWhile(ConditionalExpression condition, Op04StructuredStatement body, BlockIdentifier block) {
super(body);
this.condition = condition;
this.block = block;
}

@Override
public void collectTypeUsages(TypeUsageCollector collector) {
collector.collectFrom(condition);
super.collectTypeUsages(collector);
super(condition, block, body);
}

@Override
public Dumper dump(Dumper dumper) {
if (block.hasForeignReferences()) dumper.print(block.getName() + " : ");
dumper.print("while (").dump(condition).print(") ");
if (block.hasForeignReferences()) dumper.label(block.getName(), true);
dumper.print("while (");
if (condition == null) {
dumper.print("true");
} else {
dumper.dump(condition);
}
dumper.print(") ");
getBody().dump(dumper);
return dumper;
}

public BlockIdentifier getBlock() {
return block;
}

@Override
public boolean isScopeBlock() {
return true;
}

@Override
public boolean supportsContinueBreak() {
return true;
}

@Override
public BlockIdentifier getBreakableBlockOrNull() {
return block;
}

@Override
public boolean supportsBreak() {
return true;
}

@Override
public void linearizeInto(List<StructuredStatement> out) {
out.add(this);
getBody().linearizeStatementsInto(out);
}

@Override
public void traceLocalVariableScope(LValueScopeDiscoverer scopeDiscoverer) {
condition.collectUsedLValues(scopeDiscoverer);
scopeDiscoverer.processOp04Statement(getBody());
}

@Override
public void rewriteExpressions(ExpressionRewriter expressionRewriter) {
condition = expressionRewriter.rewriteExpression(condition, null, this.getContainer(), null);
}

@Override
public boolean match(MatchIterator<StructuredStatement> matchIterator, MatchResultCollector matchResultCollector) {
StructuredStatement o = matchIterator.getCurrent();
Expand All @@ -93,8 +47,4 @@ public boolean match(MatchIterator<StructuredStatement> matchIterator, MatchResu
matchIterator.advance();
return true;
}

public ConditionalExpression getCondition() {
return condition;
}
}
Loading

0 comments on commit 57b396b

Please sign in to comment.