Add tests for phi updater

This commit is contained in:
Alexey Andreev 2017-01-04 22:09:56 +03:00
parent 727c831467
commit a5eb9ac800
12 changed files with 226 additions and 41 deletions

View File

@ -786,7 +786,7 @@ public class ListingParser {
private void parseCatch() throws IOException, ListingParseException {
TryCatchBlock tryCatch = new TryCatchBlock();
if (lexer.getToken() == ListingToken.IDENTIFIER) {
if (lexer.getToken() == ListingToken.IDENTIFIER && !lexer.getTokenValue().equals("goto")) {
tryCatch.setExceptionType((String) lexer.getTokenValue());
lexer.nextToken();
}

View File

@ -220,7 +220,6 @@ public class PhiUpdater {
}
List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program);
List<List<TryCatchJoint>> inputJoints = getInputJoints(program);
while (head > 0) {
Task task = stack[--head];
@ -244,29 +243,31 @@ public class PhiUpdater {
for (Phi phi : currentBlock.getPhis()) {
phi.setReceiver(define(phi.getReceiver()));
}
for (TryCatchJoint joint : inputJoints.get(index)) {
joint.setReceiver(define(joint.getReceiver()));
}
for (Instruction insn : currentBlock) {
insn.acceptVisitor(consumer);
}
for (Incoming output : phiOutputs.get(index)) {
Variable var = output.getValue();
output.setValue(use(var));
}
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) {
for (TryCatchJoint joint : tryCatch.getJoints()) {
for (int i = 0; i < joint.getSourceVariables().size(); ++i) {
joint.getSourceVariables().set(i, use(joint.getSourceVariables().get(i)));
}
joint.setReceiver(define(joint.getReceiver()));
}
}
IntSet catchSuccessors = new IntOpenHashSet();
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) {
catchSuccessors.add(tryCatch.getHandler().getIndex());
}
for (Incoming output : phiOutputs.get(index)) {
if (!catchSuccessors.contains(output.getPhi().getBasicBlock().getIndex())) {
Variable var = output.getValue();
output.setValue(use(var));
}
}
Variable[] regularVariableMap = variableMap;
Variable[] catchVariableMap = variableMap.clone();
@ -296,7 +297,7 @@ public class PhiUpdater {
successors = cfg.outgoingEdges(index);
for (int successor : successors) {
variableMap = catchSuccessors.contains(successor) ? catchVariableMap : variableMap;
variableMap = catchSuccessors.contains(successor) ? catchVariableMap : regularVariableMap;
renameOutgoingPhis(successor);
}
}
@ -393,6 +394,21 @@ public class PhiUpdater {
BasicBlock[] worklist = new BasicBlock[program.basicBlockCount() * 4];
int head = 0;
worklist[head++] = currentBlock;
BasicBlock startBlock = currentBlock;
List<TryCatchBlock> tryCatchBlocks = startBlock.getTryCatchBlocks();
for (int i = 0; i < tryCatchBlocks.size(); i++) {
TryCatchBlock tryCatch = tryCatchBlocks.get(i);
TryCatchJoint joint = jointMap.computeIfAbsent(tryCatch, k -> new HashMap<>()).get(var);
if (joint == null) {
joint = new TryCatchJoint();
joint.setReceiver(var);
synthesizedJointsByBlock.get(startBlock.getIndex()).get(i).add(joint);
jointMap.get(tryCatch).put(var, joint);
worklist[head++] = tryCatch.getHandler();
}
}
while (head > 0) {
BasicBlock block = worklist[--head];
int[] frontiers = domFrontiers[block.getIndex()];
@ -422,19 +438,6 @@ public class PhiUpdater {
}
}
}
List<TryCatchBlock> tryCatchBlocks = block.getTryCatchBlocks();
for (int i = 0; i < tryCatchBlocks.size(); i++) {
TryCatchBlock tryCatch = tryCatchBlocks.get(i);
TryCatchJoint joint = jointMap.computeIfAbsent(tryCatch, k -> new HashMap<>()).get(var);
if (joint == null) {
joint = new TryCatchJoint();
joint.setReceiver(var);
synthesizedJointsByBlock.get(block.getIndex()).get(i).add(joint);
jointMap.get(tryCatch).put(var, joint);
worklist[head++] = tryCatch.getHandler();
}
}
}
}
@ -501,21 +504,6 @@ public class PhiUpdater {
return mappedVar;
}
private static List<List<TryCatchJoint>> getInputJoints(Program program) {
List<List<TryCatchJoint>> inputJoints = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) {
inputJoints.add(new ArrayList<>());
}
for (BasicBlock block : program.getBasicBlocks()) {
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
for (TryCatchJoint joint : tryCatch.getJoints()) {
inputJoints.get(tryCatch.getHandler().getIndex()).add(joint);
}
}
}
return inputJoints;
}
private InstructionVisitor consumer = new InstructionVisitor() {
@Override
public void visit(EmptyInstruction insn) {
@ -748,3 +736,4 @@ public class PhiUpdater {
}
};
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2017 Alexey Andreev.
*
* 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.
*/
package org.teavm.model.util.test;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.teavm.model.ListingParseUtils;
import org.teavm.model.Program;
import org.teavm.model.Variable;
import org.teavm.model.text.ListingBuilder;
import org.teavm.model.util.PhiUpdater;
public class PhiUpdaterTest {
private static final String PREFIX = "model/util/phi-updater/";
@Rule
public TestName name = new TestName();
@Test
public void exceptionPhi() {
doTest();
}
@Test
public void exceptionPhiMultiple() {
doTest();
}
@Test
public void exceptionPhiFromSinglePhi() {
doTest();
}
@Test
public void existingExceptionPhi() {
doTest();
}
private void doTest() {
String originalPath = PREFIX + name.getMethodName() + ".original.txt";
String expectedPath = PREFIX + name.getMethodName() + ".expected.txt";
Program original = ListingParseUtils.parseFromResource(originalPath);
Program expected = ListingParseUtils.parseFromResource(expectedPath);
new PhiUpdater().updatePhis(original, new Variable[0]);
String originalText = new ListingBuilder().buildListing(original, "");
String expectedText = new ListingBuilder().buildListing(expected, "");
Assert.assertEquals(expectedText, originalText);
new PhiUpdater().updatePhis(original, new Variable[0]);
String repeatedText = new ListingBuilder().buildListing(original, "");
Assert.assertEquals("Repeated update", originalText, repeatedText);
}
}

View File

@ -0,0 +1,13 @@
$start
@a := invokeStatic `Foo.bar()I`
@a_1 := invokeStatic `Foo.baz()I`
goto $end
catch java.lang.RuntimeException goto $catch
@a_2 := ephi @a, @a_1
$catch
@b := 1
@a_4 := @a_2 + @b as int
goto $end
$end
@a_3 := phi @a_1 from $start, @a_4 from $catch
return @a_3

View File

@ -0,0 +1,11 @@
$start
@a := invokeStatic `Foo.bar()I`
@a := invokeStatic `Foo.baz()I`
goto $end
catch java.lang.RuntimeException goto $catch
$catch
@b := 1
@a := @a + @b as int
goto $end
$end
return @a

View File

@ -0,0 +1,17 @@
$start
@cond := invokeStatic `Foo.cond()I`
if @cond == 0 then goto $zero else goto $nonzero
$zero
@a := 23
goto $joint
$nonzero
@a_1 := 42
goto $joint
$joint
@a_2 := phi @a from $zero, @a_1 from $nonzero
goto $exit
catch goto $catch
$catch
goto $exit
$exit
return @a_2

View File

@ -0,0 +1,16 @@
$start
@cond := invokeStatic `Foo.cond()I`
if @cond == 0 then goto $zero else goto $nonzero
$zero
@a := 23
goto $joint
$nonzero
@a := 42
goto $joint
$joint
goto $exit
catch goto $catch
$catch
goto $exit
$exit
return @a

View File

@ -0,0 +1,19 @@
$start
@a := invokeStatic `Foo.bar()I`
@a_1 := invokeStatic `Foo.baz()I`
goto $second
catch java.lang.RuntimeException goto $catch
@a_2 := ephi @a, @a_1
$second
@a_3 := invokeStatic `Foo.boo()I`
goto $end
catch java.lang.RuntimeException goto $catch
@a_4 := ephi @a_1, @a_3
$catch
@a_5 := phi @a_2 from $start, @a_4 from $second
@b := 1
@a_6 := @a_5 + @b as int
goto $end
$end
@a_7 := phi @a_3 from $second, @a_6 from $catch
return @a_7

View File

@ -0,0 +1,15 @@
$start
@a := invokeStatic `Foo.bar()I`
@a := invokeStatic `Foo.baz()I`
goto $second
catch java.lang.RuntimeException goto $catch
$second
@a := invokeStatic `Foo.boo()I`
goto $end
catch java.lang.RuntimeException goto $catch
$catch
@b := 1
@a := @a + @b as int
goto $end
$end
return @a

View File

@ -0,0 +1,18 @@
$start
@a := invokeStatic `Foo.bar()I`
@a_1 := invokeStatic `Foo.baz()I`
goto $second
catch goto $catch
@a_2 := ephi @a, @a_1
$second
@a_3 := invokeStatic `Foo.bar2()I`
@a_4 := invokeStatic `Foo.baz2()I`
goto $end
catch goto $catch
@a_5 := ephi @a_1, @a_3, @a_4
$catch
@a_6 := phi @a_2 from $start, @a_5 from $second
goto $end
$end
@a_7 := phi @a_4 from $second, @a_6 from $catch
return @a_7

View File

@ -0,0 +1,18 @@
$start
@a := invokeStatic `Foo.bar()I`
@a_1 := invokeStatic `Foo.baz()I`
goto $second
catch goto $catch
@a_2 := ephi @a, @a_1
$second
@a_3 := invokeStatic `Foo.bar2()I`
@a_4 := invokeStatic `Foo.baz2()I`
goto $end
catch goto $catch
@a_5 := ephi @a_1, @a_3, @a_4
$catch
@a_6 := phi @a_2 from $start, @a_5 from $second
goto $end
$end
@a_7 := phi @a_4 from $second, @a_6 from $catch
return @a_7

View File

@ -34,7 +34,7 @@ interface TeaVMTestConfiguration {
@Override
public void apply(TeaVM vm) {
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL);
}
@Override