Adds exception type propagation

This commit is contained in:
konsoletyper 2014-03-01 22:19:24 +04:00
parent cb8f424339
commit 8541e40f36
4 changed files with 71 additions and 10 deletions

View File

@ -278,9 +278,13 @@ public class DependencyChecker implements DependencyInfo {
resultNode.setTag(methodRef + ":RESULT"); resultNode.setTag(methodRef + ":RESULT");
} }
} }
DependencyNode thrown = createNode();
if (shouldLog) {
thrown.setTag(methodRef + ":THROWN");
}
stack = new DependencyStack(methodRef, stack); stack = new DependencyStack(methodRef, stack);
final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, stack, method, final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, thrown,
methodRef); stack, method, methodRef);
if (method != null) { if (method != null) {
executor.execute(new Runnable() { executor.execute(new Runnable() {
@Override public void run() { @Override public void run() {

View File

@ -34,6 +34,7 @@ class DependencyGraphBuilder {
private ProgramReader program; private ProgramReader program;
private DependencyStack callerStack; private DependencyStack callerStack;
private List<Runnable> useRunners = new ArrayList<>(); private List<Runnable> useRunners = new ArrayList<>();
private ExceptionConsumer currentExceptionConsumer;
public DependencyGraphBuilder(DependencyChecker dependencyChecker) { public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
this.dependencyChecker = dependencyChecker; this.dependencyChecker = dependencyChecker;
@ -54,6 +55,7 @@ class DependencyGraphBuilder {
nodes = dep.getVariables(); nodes = dep.getVariables();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlockReader block = program.basicBlockAt(i); BasicBlockReader block = program.basicBlockAt(i);
currentExceptionConsumer = createExceptionConsumer(dep, block);
block.readAllInstructions(reader); block.readAllInstructions(reader);
for (PhiReader phi : block.readPhis()) { for (PhiReader phi : block.readPhis()) {
for (IncomingReader incoming : phi.readIncomings()) { for (IncomingReader incoming : phi.readIncomings()) {
@ -62,8 +64,7 @@ class DependencyGraphBuilder {
} }
for (final TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) { for (final TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
useRunners.add(new Runnable() { useRunners.add(new Runnable() {
@Override @Override public void run() {
public void run() {
if (tryCatch.getExceptionType() != null) { if (tryCatch.getExceptionType() != null) {
dependencyChecker.initClass(tryCatch.getExceptionType(), callerStack); dependencyChecker.initClass(tryCatch.getExceptionType(), callerStack);
} }
@ -74,7 +75,47 @@ class DependencyGraphBuilder {
dep.setUseRunner(new MultipleRunner(useRunners)); dep.setUseRunner(new MultipleRunner(useRunners));
} }
private static class VirtualCallPropagationListener implements DependencyConsumer { private ExceptionConsumer createExceptionConsumer(MethodDependency methodDep, BasicBlockReader block) {
List<? extends TryCatchBlockReader> tryCatchBlocks = block.readTryCatchBlocks();
ClassReader[] exceptions = new ClassReader[tryCatchBlocks.size()];
DependencyNode[] vars = new DependencyNode[tryCatchBlocks.size()];
for (int i = 0; i < tryCatchBlocks.size(); ++i) {
TryCatchBlockReader tryCatch = tryCatchBlocks.get(i);
if (tryCatch.getExceptionType() != null) {
exceptions[i] = dependencyChecker.getClassSource().get(tryCatch.getExceptionType());
}
vars[i] = methodDep.getVariable(i);
}
return new ExceptionConsumer(dependencyChecker, exceptions, vars, methodDep);
}
private static class ExceptionConsumer implements DependencyConsumer {
private DependencyChecker checker;
private ClassReader[] exceptions;
private DependencyNode[] vars;
private MethodDependency method;
public ExceptionConsumer(DependencyChecker checker, ClassReader[] exceptions, DependencyNode[] vars,
MethodDependency method) {
this.checker = checker;
this.exceptions = exceptions;
this.vars = vars;
this.method = method;
}
@Override
public void consume(String type) {
for (int i = 0; i < exceptions.length; ++i) {
if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i], type)) {
vars[i].propagate(type);
return;
}
}
method.getThrown().propagate(type);
}
}
private static class VirtualCallConsumer implements DependencyConsumer {
private final DependencyNode node; private final DependencyNode node;
private final ClassReader filterClass; private final ClassReader filterClass;
private final MethodDescriptor methodDesc; private final MethodDescriptor methodDesc;
@ -83,10 +124,11 @@ class DependencyGraphBuilder {
private final DependencyNode result; private final DependencyNode result;
private final DependencyStack stack; private final DependencyStack stack;
private final ConcurrentMap<MethodReference, MethodReference> knownMethods = new ConcurrentHashMap<>(); private final ConcurrentMap<MethodReference, MethodReference> knownMethods = new ConcurrentHashMap<>();
private ExceptionConsumer exceptionConsumer;
public VirtualCallPropagationListener(DependencyNode node, ClassReader filterClass, public VirtualCallConsumer(DependencyNode node, ClassReader filterClass,
MethodDescriptor methodDesc, DependencyChecker checker, DependencyNode[] parameters, MethodDescriptor methodDesc, DependencyChecker checker, DependencyNode[] parameters,
DependencyNode result, DependencyStack stack) { DependencyNode result, DependencyStack stack, ExceptionConsumer exceptionConsumer) {
this.node = node; this.node = node;
this.filterClass = filterClass; this.filterClass = filterClass;
this.methodDesc = methodDesc; this.methodDesc = methodDesc;
@ -94,6 +136,7 @@ class DependencyGraphBuilder {
this.parameters = parameters; this.parameters = parameters;
this.result = result; this.result = result;
this.stack = stack; this.stack = stack;
this.exceptionConsumer = exceptionConsumer;
} }
@Override @Override
@ -119,6 +162,7 @@ class DependencyGraphBuilder {
if (methodDep.getResult() != null) { if (methodDep.getResult() != null) {
methodDep.getResult().connect(result); methodDep.getResult().connect(result);
} }
methodDep.getThrown().addConsumer(exceptionConsumer);
} }
} }
} }
@ -288,6 +332,7 @@ class DependencyGraphBuilder {
@Override @Override
public void raise(VariableReader exception) { public void raise(VariableReader exception) {
nodes[exception.getIndex()].addConsumer(currentExceptionConsumer);
} }
@Override @Override
@ -399,6 +444,7 @@ class DependencyGraphBuilder {
if (methodDep.getResult() != null && receiver != null) { if (methodDep.getResult() != null && receiver != null) {
methodDep.getResult().connect(nodes[receiver.getIndex()]); methodDep.getResult().connect(nodes[receiver.getIndex()]);
} }
methodDep.getThrown().addConsumer(currentExceptionConsumer);
initClass(method.getClassName()); initClass(method.getClassName());
} }
@ -413,10 +459,11 @@ class DependencyGraphBuilder {
actualArgs[i + 1] = nodes[arguments.get(i).getIndex()]; actualArgs[i + 1] = nodes[arguments.get(i).getIndex()];
} }
actualArgs[0] = nodes[instance.getIndex()]; actualArgs[0] = nodes[instance.getIndex()];
DependencyConsumer listener = new VirtualCallPropagationListener(nodes[instance.getIndex()], DependencyConsumer listener = new VirtualCallConsumer(nodes[instance.getIndex()],
dependencyChecker.getClassSource().get(methodDep.getMethod().getOwnerName()), dependencyChecker.getClassSource().get(methodDep.getMethod().getOwnerName()),
method.getDescriptor(), dependencyChecker, actualArgs, method.getDescriptor(), dependencyChecker, actualArgs,
receiver != null ? nodes[receiver.getIndex()] : null, callerStack); receiver != null ? nodes[receiver.getIndex()] : null, callerStack,
currentExceptionConsumer);
nodes[instance.getIndex()].addConsumer(listener); nodes[instance.getIndex()].addConsumer(listener);
} }
@ -452,6 +499,7 @@ class DependencyGraphBuilder {
"<init>", ValueType.VOID), callerStack); "<init>", ValueType.VOID), callerStack);
} }
}); });
currentExceptionConsumer.consume("java.lang.NullPointerException");
} }
}; };
} }

View File

@ -28,6 +28,7 @@ public class MethodDependency implements MethodDependencyInfo {
private DependencyNode[] variableNodes; private DependencyNode[] variableNodes;
private int parameterCount; private int parameterCount;
private DependencyNode resultNode; private DependencyNode resultNode;
private DependencyNode thrown;
private DependencyStack stack; private DependencyStack stack;
private MethodReader method; private MethodReader method;
private MethodReference reference; private MethodReference reference;
@ -35,9 +36,10 @@ public class MethodDependency implements MethodDependencyInfo {
private volatile Runnable useRunner; private volatile Runnable useRunner;
MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode, MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
DependencyStack stack, MethodReader method, MethodReference reference) { DependencyNode thrown, DependencyStack stack, MethodReader method, MethodReference reference) {
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length); this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
this.parameterCount = parameterCount; this.parameterCount = parameterCount;
this.thrown = thrown;
this.resultNode = resultNode; this.resultNode = resultNode;
this.stack = stack; this.stack = stack;
this.method = method; this.method = method;
@ -69,6 +71,11 @@ public class MethodDependency implements MethodDependencyInfo {
return resultNode; return resultNode;
} }
@Override
public DependencyNode getThrown() {
return thrown;
}
public DependencyStack getStack() { public DependencyStack getStack() {
return stack; return stack;
} }

View File

@ -32,6 +32,8 @@ public interface MethodDependencyInfo {
DependencyNode getResult(); DependencyNode getResult();
DependencyNode getThrown();
MethodReference getReference(); MethodReference getReference();
boolean isUsed(); boolean isUsed();