Prevent PhiUpdater from placing e-phis with source variable equal to receiver

This commit is contained in:
Alexey Andreev 2016-12-03 13:46:02 +03:00
parent 10bb4ef3da
commit ad39024795
5 changed files with 91 additions and 46 deletions

View File

@ -152,14 +152,10 @@ class LoopInversionImpl {
} }
private LoopWithExits getLoopWithExits(Map<Loop, LoopWithExits> cache, Loop loop) { private LoopWithExits getLoopWithExits(Map<Loop, LoopWithExits> cache, Loop loop) {
LoopWithExits result = cache.get(loop); return cache.computeIfAbsent(loop, k ->
if (result == null) { new LoopWithExits(loop.getHead(), loop.getParent() != null
result = new LoopWithExits(loop.getHead(), loop.getParent() != null ? getLoopWithExits(cache, loop.getParent())
? getLoopWithExits(cache, loop.getParent()) : null));
: null);
cache.put(loop, result);
}
return result;
} }
private void sortLoops(LoopWithExits loop, Set<LoopWithExits> visited, List<LoopWithExits> target) { private void sortLoops(LoopWithExits loop, Set<LoopWithExits> visited, List<LoopWithExits> target) {
@ -179,7 +175,6 @@ class LoopInversionImpl {
final IntSet nodesAndCopies = new IntOpenHashSet(); final IntSet nodesAndCopies = new IntOpenHashSet();
final IntSet exits = new IntOpenHashSet(); final IntSet exits = new IntOpenHashSet();
int bodyStart; int bodyStart;
int copyStart;
int headCopy; int headCopy;
final IntIntMap copiedNodes = new IntIntOpenHashMap(); final IntIntMap copiedNodes = new IntIntOpenHashMap();
boolean shouldSkip; boolean shouldSkip;
@ -352,7 +347,7 @@ class LoopInversionImpl {
TryCatchJoint jointCopy = new TryCatchJoint(); TryCatchJoint jointCopy = new TryCatchJoint();
jointCopy.setReceiver(joint.getReceiver()); jointCopy.setReceiver(joint.getReceiver());
jointCopy.getSourceVariables().addAll(joint.getSourceVariables()); jointCopy.getSourceVariables().addAll(joint.getSourceVariables());
tryCatchCopy.getJoints().add(joint); tryCatchCopy.getJoints().add(jointCopy);
} }
} }
} }

View File

@ -244,7 +244,7 @@ public class PhiUpdater {
TryCatchBlock tryCatch = currentBlock.getTryCatchBlocks().get(i); TryCatchBlock tryCatch = currentBlock.getTryCatchBlocks().get(i);
catchSuccessors.add(tryCatch.getHandler().getIndex()); catchSuccessors.add(tryCatch.getHandler().getIndex());
for (TryCatchJoint joint : synthesizedJoints.get(index).get(i)) { for (TryCatchJoint joint : synthesizedJoints.get(index).get(i)) {
joint.setReceiver(define(joint.getReceiver())); joint.setReceiver(defineForExceptionPhi(joint.getReceiver()));
} }
} }
variableMap = regularVariableMap; variableMap = regularVariableMap;
@ -308,36 +308,55 @@ public class PhiUpdater {
while (head > 0) { while (head > 0) {
BasicBlock block = worklist[--head]; BasicBlock block = worklist[--head];
int[] frontiers = domFrontiers[block.getIndex()]; int[] frontiers = domFrontiers[block.getIndex()];
if (frontiers == null) {
continue; if (frontiers != null) {
for (int frontier : frontiers) {
BasicBlock frontierBlock = program.basicBlockAt(frontier);
if (frontierBlock.getExceptionVariable() == var) {
continue;
}
boolean exists = frontierBlock.getPhis().stream()
.flatMap(phi -> phi.getIncomings().stream())
.anyMatch(incoming -> incoming.getSource() == block && incoming.getValue() == var);
if (exists) {
continue;
}
Phi phi = phiMap[frontier][var.getIndex()];
if (phi == null) {
phi = new Phi();
phi.setReceiver(var);
phiIndexMap[frontier][synthesizedPhis.get(frontier).size()] = var.getIndex();
synthesizedPhis.get(frontier).add(phi);
phiMap[frontier][var.getIndex()] = phi;
worklist[head++] = frontierBlock;
}
}
} }
for (int frontier : frontiers) { List<TryCatchBlock> tryCatchBlocks = block.getTryCatchBlocks();
BasicBlock frontierBlock = program.basicBlockAt(frontier); for (int i = 0; i < tryCatchBlocks.size(); i++) {
if (frontierBlock.getExceptionVariable() == var) { TryCatchBlock tryCatch = tryCatchBlocks.get(i);
continue; TryCatchJoint joint = jointMap.computeIfAbsent(tryCatch, k -> new HashMap<>()).get(var);
} if (joint == null) {
joint = new TryCatchJoint();
boolean exists = frontierBlock.getPhis().stream() joint.setReceiver(var);
.flatMap(phi -> phi.getIncomings().stream()) synthesizedJoints.get(block.getIndex()).get(i).add(joint);
.anyMatch(incoming -> incoming.getSource() == block && incoming.getValue() == var); jointMap.get(tryCatch).put(var, joint);
if (exists) { worklist[head++] = tryCatch.getHandler();
continue;
}
Phi phi = phiMap[frontier][var.getIndex()];
if (phi == null) {
phi = new Phi();
phi.setReceiver(var);
phiIndexMap[frontier][synthesizedPhis.get(frontier).size()] = var.getIndex();
synthesizedPhis.get(frontier).add(phi);
phiMap[frontier][var.getIndex()] = phi;
worklist[head++] = frontierBlock;
} }
} }
} }
} }
private Variable defineForExceptionPhi(Variable var) {
Variable original = var;
var = introduce(var);
mapVariable(original.getIndex(), var);
return var;
}
private Variable define(Variable var) { private Variable define(Variable var) {
Variable old = variableMap[var.getIndex()]; Variable old = variableMap[var.getIndex()];
Variable original = var; Variable original = var;
@ -354,15 +373,13 @@ public class PhiUpdater {
continue; continue;
} }
Map<Variable, TryCatchJoint> joints = jointMap.computeIfAbsent(tryCatch, k -> new HashMap<>()); Map<Variable, TryCatchJoint> joints = jointMap.get(tryCatch);
if (joints == null) {
continue;
}
TryCatchJoint joint = joints.get(original); TryCatchJoint joint = joints.get(original);
if (joint == null) { if (joint == null) {
joint = new TryCatchJoint();
joint.setReceiver(original);
joints.put(original, joint);
synthesizedJoints.get(currentBlock.getIndex()).get(i).add(joint);
}
if (joint.getReceiver() == var) {
continue; continue;
} }

View File

@ -18,6 +18,8 @@ package org.teavm.vm;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.teavm.jso.JSBody;
import org.teavm.junit.SkipJVM;
import org.teavm.junit.TeaVMTestRunner; import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
@ -132,6 +134,27 @@ public class VMTest {
assertEquals("ok", AsyncClinitClass.state); assertEquals("ok", AsyncClinitClass.state);
} }
@Test
@SkipJVM
public void loopAndExceptionPhi() {
int[] a = createArray();
int s = 0;
for (int i = 0; i < 10; ++i) {
int x = 0;
try {
x += 2;
x += 3;
} catch (RuntimeException e) {
fail("Unexpected exception caught: " + x);
}
s += a[0] + a[1];
}
assertEquals(30, s);
}
@JSBody(params = {}, script = "return [1, 2]")
private static native int[] createArray();
static int initCount = 0; static int initCount = 0;
private static class AsyncClinitClass { private static class AsyncClinitClass {

View File

@ -15,7 +15,9 @@
<root url="jar://$MODULE_DIR$/lib/teavm-all.jar!/" /> <root url="jar://$MODULE_DIR$/lib/teavm-all.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES>
<root url="file://$MODULE_DIR$/../../core/src/main/java" />
</SOURCES>
</library> </library>
</orderEntry> </orderEntry>
</component> </component>

View File

@ -228,11 +228,19 @@ public class TeaVMTestRunner extends Runner implements Filterable {
}); });
for (TeaVMTestConfiguration configuration : configurations) { for (TeaVMTestConfiguration configuration : configurations) {
TestRun run = compileByTeaVM(child, notifier, expectedExceptions, configuration, onSuccess.get(0)); try {
if (run != null) { TestRun run = compileByTeaVM(child, notifier, expectedExceptions, configuration, onSuccess.get(0));
runs.add(run); if (run != null) {
} else { runs.add(run);
} else {
notifier.fireTestFinished(description);
latch.countDown();
return;
}
} catch (Throwable e) {
notifier.fireTestFailure(new Failure(description, e));
notifier.fireTestFinished(description); notifier.fireTestFinished(description);
latch.countDown();
return; return;
} }
} }