From a5eb9ac8007a98b050616d0c51e0c34bfc3d104f Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 4 Jan 2017 22:09:56 +0300 Subject: [PATCH] Add tests for phi updater --- .../org/teavm/model/text/ListingParser.java | 2 +- .../java/org/teavm/model/util/PhiUpdater.java | 67 ++++++++---------- .../teavm/model/util/test/PhiUpdaterTest.java | 69 +++++++++++++++++++ .../phi-updater/exceptionPhi.expected.txt | 13 ++++ .../phi-updater/exceptionPhi.original.txt | 11 +++ .../exceptionPhiFromSinglePhi.expected.txt | 17 +++++ .../exceptionPhiFromSinglePhi.original.txt | 16 +++++ .../exceptionPhiMultiple.expected.txt | 19 +++++ .../exceptionPhiMultiple.original.txt | 15 ++++ .../existingExceptionPhi.expected.txt | 18 +++++ .../existingExceptionPhi.original.txt | 18 +++++ .../teavm/junit/TeaVMTestConfiguration.java | 2 +- 12 files changed, 226 insertions(+), 41 deletions(-) create mode 100644 core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java create mode 100644 core/src/test/resources/model/util/phi-updater/exceptionPhi.expected.txt create mode 100644 core/src/test/resources/model/util/phi-updater/exceptionPhi.original.txt create mode 100644 core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.expected.txt create mode 100644 core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.original.txt create mode 100644 core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.expected.txt create mode 100644 core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.original.txt create mode 100644 core/src/test/resources/model/util/phi-updater/existingExceptionPhi.expected.txt create mode 100644 core/src/test/resources/model/util/phi-updater/existingExceptionPhi.original.txt diff --git a/core/src/main/java/org/teavm/model/text/ListingParser.java b/core/src/main/java/org/teavm/model/text/ListingParser.java index 3e28d1a11..88d85db5f 100644 --- a/core/src/main/java/org/teavm/model/text/ListingParser.java +++ b/core/src/main/java/org/teavm/model/text/ListingParser.java @@ -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(); } diff --git a/core/src/main/java/org/teavm/model/util/PhiUpdater.java b/core/src/main/java/org/teavm/model/util/PhiUpdater.java index a73f2b05e..c3541db5b 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -220,7 +220,6 @@ public class PhiUpdater { } List> phiOutputs = ProgramUtils.getPhiOutputs(program); - List> 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 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 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> getInputJoints(Program program) { - List> 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 { } }; } + diff --git a/core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java b/core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java new file mode 100644 index 000000000..bf22ae506 --- /dev/null +++ b/core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java @@ -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); + } +} diff --git a/core/src/test/resources/model/util/phi-updater/exceptionPhi.expected.txt b/core/src/test/resources/model/util/phi-updater/exceptionPhi.expected.txt new file mode 100644 index 000000000..b96023317 --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhi.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/exceptionPhi.original.txt b/core/src/test/resources/model/util/phi-updater/exceptionPhi.original.txt new file mode 100644 index 000000000..eaf992714 --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhi.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.expected.txt b/core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.expected.txt new file mode 100644 index 000000000..b3944525a --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.original.txt b/core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.original.txt new file mode 100644 index 000000000..90c8b1ca1 --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhiFromSinglePhi.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.expected.txt b/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.expected.txt new file mode 100644 index 000000000..13de5feca --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.original.txt b/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.original.txt new file mode 100644 index 000000000..444048dba --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/existingExceptionPhi.expected.txt b/core/src/test/resources/model/util/phi-updater/existingExceptionPhi.expected.txt new file mode 100644 index 000000000..b5225b749 --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/existingExceptionPhi.expected.txt @@ -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 diff --git a/core/src/test/resources/model/util/phi-updater/existingExceptionPhi.original.txt b/core/src/test/resources/model/util/phi-updater/existingExceptionPhi.original.txt new file mode 100644 index 000000000..b5225b749 --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/existingExceptionPhi.original.txt @@ -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 diff --git a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java index 98c0731ee..62cdd9eb8 100644 --- a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java +++ b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestConfiguration.java @@ -34,7 +34,7 @@ interface TeaVMTestConfiguration { @Override public void apply(TeaVM vm) { - vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE); + vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL); } @Override