Skip to content
Snippets Groups Projects
Commit b64ab782 authored by Johannes Mey's avatar Johannes Mey
Browse files

wip

parent ebbf18e2
No related branches found
No related tags found
No related merge requests found
/** CFG ::= CfgNode*;
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** A node in a Control Flow Graph (CFG). */ /** A node in a Control Flow Graph (CFG). */
abstract CfgNode; abstract CfgNode;
...@@ -34,3 +20,7 @@ CfgException : CfgNode; ...@@ -34,3 +20,7 @@ CfgException : CfgNode;
/** A marker node used to mark try block entry points or the end of if-statement branches. */ /** A marker node used to mark try block entry points or the end of if-statement branches. */
CfgMarker : CfgNode; CfgMarker : CfgNode;
rel CfgNode.successor <-> CfgNode.predecessor ;
rel CfgEntry ->
aspect ReusableCfg {
/**
* Set that contains either one or two unique objects. The objects are
* compared with reference equality.
*/
class IdentityTupleSet<E> implements Set<E> {
final E a, b;
public IdentityTupleSet(E a, E b) {
this.a = a;
this.b = b;
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends E> e) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(Object o) {
return o == a || o == b;
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return a.hashCode() + b.hashCode();
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
int index = 0;
@Override
public boolean hasNext() {
return (a == b && index < 1)
|| (a != b && index < 2);
}
@Override
public E next() {
return ++index == 1 ? a : b;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return a == b ? 1 : 2;
}
@Override
public Object[] toArray() {
return new Object[] { a, b };
}
@Override
public <T> T[] toArray(T[] array) {
array[0] = (T) a;
array[1] = (T) b;
return array;
}
@Override
public String toString() {
if (a == b) {
return "[" + a + "]";
} else {
return "[" + a + ", " + b + "]";
}
}
}
}
class ReusableCfg {
/**
* Find the next CFG node representing the next branch, or the next
* method access following this statement.
*/
inh CfgNode Stmt.follow();
inh CfgNode Expr.follow();
// Needed for completeness, but never used by anything relevant.
eq Program.getChild().follow() = new CfgExit();
eq TryStmt.getBlock().follow() =
hasNonEmptyFinally()
? getFinally().entry()
: follow();
eq TryStmt.getCatchClause(int index).follow() =
hasNonEmptyFinally()
? getFinally().entry()
: follow();
eq BreakStmt.marker().follow() =
hasFinally()
? getFinally().entry()
: targetStmt().follow();
eq ReturnStmt.marker().follow() =
hasResult()
? getResult().entry()
: returnTarget();
eq ReturnStmt.getResult().follow() = returnTarget();
eq ReturnStmt.getFinally().follow() = methodExit();
// Since we not have precise type lookups we need to approximate the possible
// exception branches.
eq ThrowStmt.getExpr().follow() = exceptionNode();
eq ClassInstanceExpr.getArg(int index).follow() =
index+1 < getNumArg()
? getArg(index+1).entry()
: getAccess().entry();
// If we have arguments the CfgMethodCall is placed after the last argument.
eq MethodAccess.getArg(int index).follow() =
index+1 < getNumArg()
? getArg(index+1).entry()
: call();
// If we have arguments the CfgMethodCall is placed after the last argument.
eq ConstructorAccess.getArg(int index).follow() =
index+1 < getNumArg()
? getArg(index+1).entry()
: follow();
eq ArrayInit.getInit(int index).follow() =
index+1 < getNumInit()
? getInit(index+1).entry()
: follow();
eq AssignExpr.getSource().follow() = getDest().entry();
eq Binary.getLeftOperand().follow() = getRightOperand().entry();
eq Dot.getLeft().follow() = getRight().entry();
eq ConditionalExpr.getCondition().follow() = branch();
eq ConditionalExpr.getTrueExpr().follow() = thenEndMarker();
eq ConditionalExpr.getFalseExpr().follow() = elseEndMarker();
eq ConditionalExpr.thenEndMarker().follow() = follow();
eq ConditionalExpr.elseEndMarker().follow() = follow();
eq IfStmt.getCondition().follow() = branch();
eq IfStmt.getThen().follow() = thenEndMarker();
eq IfStmt.getElse().follow() = elseEndMarker();
eq IfStmt.thenEndMarker().follow() = follow();
eq IfStmt.elseEndMarker().follow() = follow();
eq ForStmt.getInitStmt(int index).follow() =
index+1 < getNumInitStmt()
? getInitStmt(index+1).entry()
: getCondition().entry();
eq ForStmt.getCondition().follow() = branch();
eq ForStmt.getUpdateStmt(int index).follow() =
index+1 < getNumUpdateStmt()
? getUpdateStmt(index+1).entry()
: getCondition().entry();
eq ForStmt.getStmt().follow() = loopEndMarker();
eq ForStmt.loopEndMarker().follow() =
getNumUpdateStmt() > 0
? getUpdateStmt(0).entry()
: getCondition().entry();
eq EnhancedForStmt.getExpr().follow() = branch();
eq EnhancedForStmt.getStmt().follow() = loopEndMarker();
eq EnhancedForStmt.loopEndMarker().follow() = entry(); // Loop back.
eq WhileStmt.getCondition().follow() = branch();
eq WhileStmt.getStmt().follow() = loopEndMarker();
eq WhileStmt.loopEndMarker().follow() = entry(); // Loop back.
eq DoStmt.doEntryMarker().follow() = getStmt().entry();
eq DoStmt.getStmt().follow() = getCondition().entry();
eq DoStmt.getCondition().follow() = branch();
eq SwitchStmt.getExpr().follow() = branch();
eq BodyDecl.getChild().follow() = exit();
eq Block.getStmt(int index).follow() =
index+1 < getNumStmt()
? getStmt(index+1).entry()
: follow();
eq BlockLambdaBody.getBlock().follow() = exit();
eq ExprLambdaBody.getExpr().follow() = exit();
}
...@@ -59,106 +59,6 @@ aspect SimpleCFG { ...@@ -59,106 +59,6 @@ aspect SimpleCFG {
eq CfgMarker.successors() = succ(); eq CfgMarker.successors() = succ();
/**
* Set that contains either one or two unique objects. The objects are
* compared with reference equality.
*/
class IdentityTupleSet<E> implements Set<E> {
final E a, b;
public IdentityTupleSet(E a, E b) {
this.a = a;
this.b = b;
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends E> e) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(Object o) {
return o == a || o == b;
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return a.hashCode() + b.hashCode();
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
int index = 0;
@Override
public boolean hasNext() {
return (a == b && index < 1)
|| (a != b && index < 2);
}
@Override
public E next() {
return ++index == 1 ? a : b;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return a == b ? 1 : 2;
}
@Override
public Object[] toArray() {
return new Object[] { a, b };
}
@Override
public <T> T[] toArray(T[] array) {
array[0] = (T) a;
array[1] = (T) b;
return array;
}
@Override
public String toString() {
if (a == b) {
return "[" + a + "]";
} else {
return "[" + a + ", " + b + "]";
}
}
}
/** Successors to this branch node. */ /** Successors to this branch node. */
inh Set<? extends CfgNode> CfgBranch.succ(); inh Set<? extends CfgNode> CfgBranch.succ();
...@@ -181,16 +81,9 @@ aspect SimpleCFG { ...@@ -181,16 +81,9 @@ aspect SimpleCFG {
*/ */
syn CfgNode Stmt.entry() = follow(); syn CfgNode Stmt.entry() = follow();
/**
* Find the next CFG node representing the next branch, or the next
* method access following this statement.
*/
inh CfgNode Stmt.follow();
inh CfgNode Expr.follow();
// Needed for completeness, but never used by anything relevant.
eq Program.getChild().follow() = new CfgExit();
/** /**
* The entry node in a filtered CFG. * The entry node in a filtered CFG.
...@@ -327,15 +220,6 @@ aspect SimpleCFG { ...@@ -327,15 +220,6 @@ aspect SimpleCFG {
return set; return set;
} }
eq TryStmt.getBlock().follow() =
hasNonEmptyFinally()
? getFinally().entry()
: follow();
eq TryStmt.getCatchClause(int index).follow() =
hasNonEmptyFinally()
? getFinally().entry()
: follow();
/** The CFG marker for this break statement. */ /** The CFG marker for this break statement. */
syn nta CfgMarker BreakStmt.marker() = new CfgMarker(); syn nta CfgMarker BreakStmt.marker() = new CfgMarker();
...@@ -345,10 +229,6 @@ aspect SimpleCFG { ...@@ -345,10 +229,6 @@ aspect SimpleCFG {
hasFinally() hasFinally()
? Collections.singleton(getFinally().entry()) ? Collections.singleton(getFinally().entry())
: Collections.singleton(targetStmt().follow()); : Collections.singleton(targetStmt().follow());
eq BreakStmt.marker().follow() =
hasFinally()
? getFinally().entry()
: targetStmt().follow();
eq BreakStmt.getFinally().follow() = targetStmt().follow(); eq BreakStmt.getFinally().follow() = targetStmt().follow();
...@@ -375,12 +255,6 @@ aspect SimpleCFG { ...@@ -375,12 +255,6 @@ aspect SimpleCFG {
hasResult() hasResult()
? Collections.singleton(getResult().entry()) ? Collections.singleton(getResult().entry())
: Collections.singleton(returnTarget()); : Collections.singleton(returnTarget());
eq ReturnStmt.marker().follow() =
hasResult()
? getResult().entry()
: returnTarget();
eq ReturnStmt.getResult().follow() = returnTarget();
inh CompilationUnit ReturnStmt.compilationUnit(); inh CompilationUnit ReturnStmt.compilationUnit();
...@@ -389,8 +263,6 @@ aspect SimpleCFG { ...@@ -389,8 +263,6 @@ aspect SimpleCFG {
? getFinally().entry() ? getFinally().entry()
: methodExit(); : methodExit();
eq ReturnStmt.getFinally().follow() = methodExit();
/** /**
* Finds the CFG exit node for the enclosing method, constructor, or * Finds the CFG exit node for the enclosing method, constructor, or
* initializer. * initializer.
...@@ -403,10 +275,6 @@ aspect SimpleCFG { ...@@ -403,10 +275,6 @@ aspect SimpleCFG {
eq ThrowStmt.entry() = getExpr().entry(); eq ThrowStmt.entry() = getExpr().entry();
// Since we not have precise type lookups we need to approximate the possible
// exception branches.
eq ThrowStmt.getExpr().follow() = exceptionNode();
/** /**
* This node represents the control flow path taken when an exception * This node represents the control flow path taken when an exception
* interrupts the call. * interrupts the call.
...@@ -468,44 +336,22 @@ aspect SimpleCFG { ...@@ -468,44 +336,22 @@ aspect SimpleCFG {
? getArg(0).entry() ? getArg(0).entry()
: call(); : call();
// If we have arguments the CfgMethodCall is placed after the last argument.
eq MethodAccess.getArg(int index).follow() =
index+1 < getNumArg()
? getArg(index+1).entry()
: call();
// If there are arguments control flow passes to the arguments first. // If there are arguments control flow passes to the arguments first.
eq ConstructorAccess.entry() = eq ConstructorAccess.entry() =
getNumArg() > 0 getNumArg() > 0
? getArg(0).entry() ? getArg(0).entry()
: follow(); : follow();
// If we have arguments the CfgMethodCall is placed after the last argument.
eq ConstructorAccess.getArg(int index).follow() =
index+1 < getNumArg()
? getArg(index+1).entry()
: follow();
eq ClassInstanceExpr.entry() = eq ClassInstanceExpr.entry() =
getNumArg() > 0 getNumArg() > 0
? getArg(0).entry() ? getArg(0).entry()
: getAccess().entry(); : getAccess().entry();
eq ClassInstanceExpr.getArg(int index).follow() =
index+1 < getNumArg()
? getArg(index+1).entry()
: getAccess().entry();
eq ArrayInit.entry() = eq ArrayInit.entry() =
getNumInit() > 0 getNumInit() > 0
? getInit(0).entry() ? getInit(0).entry()
: follow(); : follow();
eq ArrayInit.getInit(int index).follow() =
index+1 < getNumInit()
? getInit(index+1).entry()
: follow();
/** @return {@code true} if this statement is inside a try block. */ /** @return {@code true} if this statement is inside a try block. */
inh boolean MethodAccess.isInsideTryBlockOrResource(); inh boolean MethodAccess.isInsideTryBlockOrResource();
inh boolean Stmt.isInsideTryBlockOrResource(); inh boolean Stmt.isInsideTryBlockOrResource();
...@@ -524,8 +370,6 @@ aspect SimpleCFG { ...@@ -524,8 +370,6 @@ aspect SimpleCFG {
eq AssignExpr.entry() = getSource().entry(); eq AssignExpr.entry() = getSource().entry();
eq AssignExpr.getSource().follow() = getDest().entry();
eq Literal.entry() = follow(); eq Literal.entry() = follow();
eq ArrayCreationExpr.entry() = eq ArrayCreationExpr.entry() =
...@@ -534,10 +378,8 @@ aspect SimpleCFG { ...@@ -534,10 +378,8 @@ aspect SimpleCFG {
: follow(); : follow();
eq Binary.entry() = getLeftOperand().entry(); eq Binary.entry() = getLeftOperand().entry();
eq Binary.getLeftOperand().follow() = getRightOperand().entry();
eq Dot.entry() = getLeft().entry(); eq Dot.entry() = getLeft().entry();
eq Dot.getLeft().follow() = getRight().entry();
/** The branch node for this conditional expression. */ /** The branch node for this conditional expression. */
syn nta CfgBranch ConditionalExpr.branch() = new CfgBranch(); syn nta CfgBranch ConditionalExpr.branch() = new CfgBranch();
...@@ -555,11 +397,6 @@ aspect SimpleCFG { ...@@ -555,11 +397,6 @@ aspect SimpleCFG {
syn nta CfgMarker ConditionalExpr.elseEndMarker() = new CfgMarker(); syn nta CfgMarker ConditionalExpr.elseEndMarker() = new CfgMarker();
eq ConditionalExpr.entry() = getCondition().entry(); eq ConditionalExpr.entry() = getCondition().entry();
eq ConditionalExpr.getCondition().follow() = branch();
eq ConditionalExpr.getTrueExpr().follow() = thenEndMarker();
eq ConditionalExpr.getFalseExpr().follow() = elseEndMarker();
eq ConditionalExpr.thenEndMarker().follow() = follow();
eq ConditionalExpr.elseEndMarker().follow() = follow();
eq ConditionalExpr.thenEndMarker().succ() = Collections.singleton(follow()); eq ConditionalExpr.thenEndMarker().succ() = Collections.singleton(follow());
eq ConditionalExpr.elseEndMarker().succ() = Collections.singleton(follow()); eq ConditionalExpr.elseEndMarker().succ() = Collections.singleton(follow());
...@@ -577,11 +414,6 @@ aspect SimpleCFG { ...@@ -577,11 +414,6 @@ aspect SimpleCFG {
eq IfStmt.entry() = getCondition().entry(); eq IfStmt.entry() = getCondition().entry();
eq IfStmt.getCondition().follow() = branch();
eq IfStmt.getThen().follow() = thenEndMarker();
eq IfStmt.getElse().follow() = elseEndMarker();
eq IfStmt.thenEndMarker().follow() = follow();
eq IfStmt.elseEndMarker().follow() = follow();
eq IfStmt.thenEndMarker().succ() = Collections.singleton(follow()); eq IfStmt.thenEndMarker().succ() = Collections.singleton(follow());
eq IfStmt.elseEndMarker().succ() = Collections.singleton(follow()); eq IfStmt.elseEndMarker().succ() = Collections.singleton(follow());
...@@ -601,25 +433,6 @@ aspect SimpleCFG { ...@@ -601,25 +433,6 @@ aspect SimpleCFG {
? getInitStmt(0).entry() ? getInitStmt(0).entry()
: getCondition().entry(); : getCondition().entry();
eq ForStmt.getInitStmt(int index).follow() =
index+1 < getNumInitStmt()
? getInitStmt(index+1).entry()
: getCondition().entry();
eq ForStmt.getCondition().follow() = branch();
eq ForStmt.getUpdateStmt(int index).follow() =
index+1 < getNumUpdateStmt()
? getUpdateStmt(index+1).entry()
: getCondition().entry();
eq ForStmt.getStmt().follow() = loopEndMarker();
eq ForStmt.loopEndMarker().follow() =
getNumUpdateStmt() > 0
? getUpdateStmt(0).entry()
: getCondition().entry();
eq ForStmt.loopEndMarker().succ() = eq ForStmt.loopEndMarker().succ() =
getNumUpdateStmt() > 0 getNumUpdateStmt() > 0
? Collections.singleton(getUpdateStmt(0).entry()) ? Collections.singleton(getUpdateStmt(0).entry())
...@@ -646,12 +459,6 @@ aspect SimpleCFG { ...@@ -646,12 +459,6 @@ aspect SimpleCFG {
eq EnhancedForStmt.entry() = getExpr().entry(); eq EnhancedForStmt.entry() = getExpr().entry();
eq EnhancedForStmt.getExpr().follow() = branch();
eq EnhancedForStmt.getStmt().follow() = loopEndMarker();
eq EnhancedForStmt.loopEndMarker().follow() = entry(); // Loop back.
eq EnhancedForStmt.loopEndMarker().succ() = Collections.singleton(entry()); eq EnhancedForStmt.loopEndMarker().succ() = Collections.singleton(entry());
/** The branch node for this statement. */ /** The branch node for this statement. */
...@@ -662,12 +469,6 @@ aspect SimpleCFG { ...@@ -662,12 +469,6 @@ aspect SimpleCFG {
eq WhileStmt.entry() = getCondition().entry(); eq WhileStmt.entry() = getCondition().entry();
eq WhileStmt.getCondition().follow() = branch();
eq WhileStmt.getStmt().follow() = loopEndMarker();
eq WhileStmt.loopEndMarker().follow() = entry(); // Loop back.
eq WhileStmt.loopEndMarker().succ() = Collections.singleton(entry()); eq WhileStmt.loopEndMarker().succ() = Collections.singleton(entry());
eq WhileStmt.branch().succ() { eq WhileStmt.branch().succ() {
...@@ -688,14 +489,9 @@ aspect SimpleCFG { ...@@ -688,14 +489,9 @@ aspect SimpleCFG {
eq DoStmt.entry() = doEntryMarker(); eq DoStmt.entry() = doEntryMarker();
eq DoStmt.doEntryMarker().follow() = getStmt().entry();
eq DoStmt.doEntryMarker().succ() = Collections.singleton(getStmt().entry()); eq DoStmt.doEntryMarker().succ() = Collections.singleton(getStmt().entry());
eq DoStmt.getStmt().follow() = getCondition().entry();
eq DoStmt.getCondition().follow() = branch();
// Loop back. // Loop back.
eq DoStmt.branch().succ() { eq DoStmt.branch().succ() {
if (getCondition().isTrue()) { if (getCondition().isTrue()) {
...@@ -711,8 +507,6 @@ aspect SimpleCFG { ...@@ -711,8 +507,6 @@ aspect SimpleCFG {
eq SwitchStmt.entry() = getExpr().entry(); eq SwitchStmt.entry() = getExpr().entry();
eq SwitchStmt.getExpr().follow() = branch();
eq SwitchStmt.branch().succ() { eq SwitchStmt.branch().succ() {
Set<CfgNode> set = Collections.newSetFromMap( Set<CfgNode> set = Collections.newSetFromMap(
new IdentityHashMap<CfgNode, Boolean>()); new IdentityHashMap<CfgNode, Boolean>());
...@@ -731,22 +525,12 @@ aspect SimpleCFG { ...@@ -731,22 +525,12 @@ aspect SimpleCFG {
return set; return set;
} }
eq BodyDecl.getChild().follow() = exit();
eq Block.getStmt(int index).follow() =
index+1 < getNumStmt()
? getStmt(index+1).entry()
: follow();
syn lazy CfgEntry LambdaBody.entry(); syn lazy CfgEntry LambdaBody.entry();
eq BlockLambdaBody.entry() = new CfgEntry(getBlock().entry()); eq BlockLambdaBody.entry() = new CfgEntry(getBlock().entry());
eq ExprLambdaBody.entry() = new CfgEntry(getExpr().entry()); eq ExprLambdaBody.entry() = new CfgEntry(getExpr().entry());
syn nta CfgExit LambdaBody.exit() = new CfgExit(); syn nta CfgExit LambdaBody.exit() = new CfgExit();
eq BlockLambdaBody.getBlock().follow() = exit();
eq ExprLambdaBody.getExpr().follow() = exit();
/** Find the method access which this call node is associated with. */ /** Find the method access which this call node is associated with. */
inh MethodAccess CfgMethodCall.methodAccess(); inh MethodAccess CfgMethodCall.methodAccess();
eq MethodAccess.call().methodAccess() = this; eq MethodAccess.call().methodAccess() = this;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment