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

wip

parent ebbf18e2
Branches
No related tags found
No related merge requests found
/**
* 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.
*/
CFG ::= CfgNode*;
/** A node in a Control Flow Graph (CFG). */
abstract CfgNode;
......@@ -34,3 +20,7 @@ CfgException : CfgNode;
/** A marker node used to mark try block entry points or the end of if-statement branches. */
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 {
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. */
inh Set<? extends CfgNode> CfgBranch.succ();
......@@ -181,16 +81,9 @@ aspect SimpleCFG {
*/
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.
......@@ -327,15 +220,6 @@ aspect SimpleCFG {
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. */
syn nta CfgMarker BreakStmt.marker() = new CfgMarker();
......@@ -345,10 +229,6 @@ aspect SimpleCFG {
hasFinally()
? Collections.singleton(getFinally().entry())
: Collections.singleton(targetStmt().follow());
eq BreakStmt.marker().follow() =
hasFinally()
? getFinally().entry()
: targetStmt().follow();
eq BreakStmt.getFinally().follow() = targetStmt().follow();
......@@ -375,12 +255,6 @@ aspect SimpleCFG {
hasResult()
? Collections.singleton(getResult().entry())
: Collections.singleton(returnTarget());
eq ReturnStmt.marker().follow() =
hasResult()
? getResult().entry()
: returnTarget();
eq ReturnStmt.getResult().follow() = returnTarget();
inh CompilationUnit ReturnStmt.compilationUnit();
......@@ -389,8 +263,6 @@ aspect SimpleCFG {
? getFinally().entry()
: methodExit();
eq ReturnStmt.getFinally().follow() = methodExit();
/**
* Finds the CFG exit node for the enclosing method, constructor, or
* initializer.
......@@ -403,10 +275,6 @@ aspect SimpleCFG {
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
* interrupts the call.
......@@ -468,44 +336,22 @@ aspect SimpleCFG {
? getArg(0).entry()
: 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.
eq ConstructorAccess.entry() =
getNumArg() > 0
? getArg(0).entry()
: 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() =
getNumArg() > 0
? getArg(0).entry()
: getAccess().entry();
eq ClassInstanceExpr.getArg(int index).follow() =
index+1 < getNumArg()
? getArg(index+1).entry()
: getAccess().entry();
eq ArrayInit.entry() =
getNumInit() > 0
? getInit(0).entry()
: 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. */
inh boolean MethodAccess.isInsideTryBlockOrResource();
inh boolean Stmt.isInsideTryBlockOrResource();
......@@ -524,8 +370,6 @@ aspect SimpleCFG {
eq AssignExpr.entry() = getSource().entry();
eq AssignExpr.getSource().follow() = getDest().entry();
eq Literal.entry() = follow();
eq ArrayCreationExpr.entry() =
......@@ -534,10 +378,8 @@ aspect SimpleCFG {
: follow();
eq Binary.entry() = getLeftOperand().entry();
eq Binary.getLeftOperand().follow() = getRightOperand().entry();
eq Dot.entry() = getLeft().entry();
eq Dot.getLeft().follow() = getRight().entry();
/** The branch node for this conditional expression. */
syn nta CfgBranch ConditionalExpr.branch() = new CfgBranch();
......@@ -555,11 +397,6 @@ aspect SimpleCFG {
syn nta CfgMarker ConditionalExpr.elseEndMarker() = new CfgMarker();
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.elseEndMarker().succ() = Collections.singleton(follow());
......@@ -577,11 +414,6 @@ aspect SimpleCFG {
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.elseEndMarker().succ() = Collections.singleton(follow());
......@@ -601,25 +433,6 @@ aspect SimpleCFG {
? getInitStmt(0).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() =
getNumUpdateStmt() > 0
? Collections.singleton(getUpdateStmt(0).entry())
......@@ -646,12 +459,6 @@ aspect SimpleCFG {
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());
/** The branch node for this statement. */
......@@ -662,12 +469,6 @@ aspect SimpleCFG {
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.branch().succ() {
......@@ -688,14 +489,9 @@ aspect SimpleCFG {
eq DoStmt.entry() = doEntryMarker();
eq DoStmt.doEntryMarker().follow() = getStmt().entry();
eq DoStmt.doEntryMarker().succ() = Collections.singleton(getStmt().entry());
eq DoStmt.getStmt().follow() = getCondition().entry();
eq DoStmt.getCondition().follow() = branch();
// Loop back.
eq DoStmt.branch().succ() {
if (getCondition().isTrue()) {
......@@ -711,8 +507,6 @@ aspect SimpleCFG {
eq SwitchStmt.entry() = getExpr().entry();
eq SwitchStmt.getExpr().follow() = branch();
eq SwitchStmt.branch().succ() {
Set<CfgNode> set = Collections.newSetFromMap(
new IdentityHashMap<CfgNode, Boolean>());
......@@ -731,22 +525,12 @@ aspect SimpleCFG {
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();
eq BlockLambdaBody.entry() = new CfgEntry(getBlock().entry());
eq ExprLambdaBody.entry() = new CfgEntry(getExpr().entry());
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. */
inh MethodAccess CfgMethodCall.methodAccess();
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