Fix bug in nullness analysis

This commit is contained in:
Alexey Andreev 2017-01-17 00:32:31 +03:00
parent 149970f162
commit 6781dd0abb
7 changed files with 76 additions and 13 deletions

View File

@ -24,6 +24,7 @@ import com.carrotsearch.hppc.IntSet;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder;
import org.teavm.common.GraphUtils;
@ -190,6 +191,12 @@ class NullnessInformationBuilder {
BasicBlock currentBlock;
IntIntMap nullSuccessors = new IntIntOpenHashMap();
IntIntMap notNullSuccessors = new IntIntOpenHashMap();
private DominatorTree dom;
@Override
public void setDomTree(DominatorTree domTree) {
dom = domTree;
}
@Override
public State visit(BasicBlock block) {
@ -317,12 +324,12 @@ class NullnessInformationBuilder {
public void visit(BranchingInstruction insn) {
switch (insn.getCondition()) {
case NOT_NULL:
notNullSuccessors.put(insn.getConsequent().getIndex(), insn.getOperand().getIndex());
nullSuccessors.put(insn.getAlternative().getIndex(), insn.getOperand().getIndex());
setNotNullSuccessor(insn.getConsequent(), insn.getOperand());
setNullSuccessor(insn.getAlternative(), insn.getOperand());
break;
case NULL:
nullSuccessors.put(insn.getConsequent().getIndex(), insn.getOperand().getIndex());
notNullSuccessors.put(insn.getAlternative().getIndex(), insn.getOperand().getIndex());
setNullSuccessor(insn.getConsequent(), insn.getOperand());
setNotNullSuccessor(insn.getAlternative(), insn.getOperand());
break;
default:
break;
@ -341,18 +348,39 @@ class NullnessInformationBuilder {
switch (insn.getCondition()) {
case REFERENCE_EQUAL:
notNullSuccessors.put(insn.getConsequent().getIndex(), first.getIndex());
nullSuccessors.put(insn.getAlternative().getIndex(), first.getIndex());
setNotNullSuccessor(insn.getConsequent(), first);
setNullSuccessor(insn.getAlternative(), first);
break;
case REFERENCE_NOT_EQUAL:
nullSuccessors.put(insn.getConsequent().getIndex(), first.getIndex());
notNullSuccessors.put(insn.getAlternative().getIndex(), first.getIndex());
setNullSuccessor(insn.getConsequent(), first);
setNotNullSuccessor(insn.getAlternative(), first);
break;
default:
break;
}
}
private void setNullSuccessor(BasicBlock successor, Variable value) {
if (shouldSetSuccessor(successor, value)) {
nullSuccessors.put(successor.getIndex(), value.getIndex());
}
}
private void setNotNullSuccessor(BasicBlock successor, Variable value) {
if (shouldSetSuccessor(successor, value)) {
notNullSuccessors.put(successor.getIndex(), value.getIndex());
}
}
private boolean shouldSetSuccessor(BasicBlock successor, Variable value) {
for (Phi phi : successor.getPhis()) {
if (phi.getIncomings().stream().anyMatch(incoming -> incoming.getValue() == value)) {
return false;
}
}
return true;
}
private void insertNotNullInstruction(Instruction currentInstruction, Variable var) {
if (notNullVariables.get(var.getIndex())) {
return;

View File

@ -18,10 +18,6 @@ package org.teavm.model.instructions;
import org.teavm.model.Instruction;
import org.teavm.model.Variable;
/**
*
* @author Alexey Andreev
*/
public class NullCheckInstruction extends Instruction {
private Variable value;
private Variable receiver;

View File

@ -23,12 +23,13 @@ import org.teavm.model.Program;
public class DominatorWalker {
private Program program;
private DominatorTree dom;
private Graph domGraph;
public DominatorWalker(Program program) {
this.program = program;
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
DominatorTree dom = GraphUtils.buildDominatorTree(cfg);
dom = GraphUtils.buildDominatorTree(cfg);
domGraph = GraphUtils.buildDominatorGraph(dom, cfg.size());
}
@ -36,6 +37,7 @@ public class DominatorWalker {
int[] stack = new int[program.basicBlockCount() * 2];
Object[] stateStack = new Object[stack.length];
boolean[] backward = new boolean[stack.length];
callback.setDomTree(dom);
int head = 1;
while (head > 0) {

View File

@ -15,6 +15,7 @@
*/
package org.teavm.model.util;
import org.teavm.common.DominatorTree;
import org.teavm.model.BasicBlock;
/**
@ -23,6 +24,9 @@ import org.teavm.model.BasicBlock;
* @param <T> type of state that can be saved for each visited node.
*/
public interface DominatorWalkerCallback<T> {
default void setDomTree(DominatorTree domTree) {
}
/**
* Called before visiting block. This method should tell whether this block and all of its descendant blocks
* should be visited.

View File

@ -75,6 +75,11 @@ public class NullnessAnalysisTest {
test();
}
@Test
public void nonDominatedBranch() {
test();
}
private void test() {
String baseName = "model/analysis/nullness/" + name.getMethodName();
String originalResourceName = baseName + ".original.txt";

View File

@ -0,0 +1,15 @@
var @this as this
$start
@a := invokeStatic `Foo.f()LBar;`
if @a === null then goto $joint else goto $ifNonNull
$ifNonNull
@a_1 := nullCheck @a
@b := invokeStatic `Foo.g()LBar;`
if @b !== null then goto $joint else goto $ifNull
$ifNull
@b_1 := null
return @a_1
$joint
@c := phi @a from $start, @b from $ifNonNull
return @c

View File

@ -0,0 +1,13 @@
var @this as this
$start
@a := invokeStatic `Foo.f()LBar;`
if @a === null then goto $joint else goto $ifNonNull
$ifNonNull
@b := invokeStatic `Foo.g()LBar;`
if @b !== null then goto $joint else goto $ifNull
$ifNull
return @a
$joint
@c := phi @a from $start, @b from $ifNonNull
return @c