From 9532f9a32b0b514c551ca1b2d7beaca670cc56d7 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 4 Jan 2017 23:46:34 +0300 Subject: [PATCH] Refactor phi updater --- .../main/java/org/teavm/model/BasicBlock.java | 5 + .../teavm/model/optimization/Inlining.java | 1 + .../java/org/teavm/model/util/PhiUpdater.java | 208 ++++++++++++------ .../phi-updater/exceptionPhi.expected.txt | 6 +- .../exceptionPhiMultiple.expected.txt | 10 +- .../teavm/junit/TeaVMTestConfiguration.java | 2 +- 6 files changed, 152 insertions(+), 80 deletions(-) diff --git a/core/src/main/java/org/teavm/model/BasicBlock.java b/core/src/main/java/org/teavm/model/BasicBlock.java index 9b0e19465..c35235701 100644 --- a/core/src/main/java/org/teavm/model/BasicBlock.java +++ b/core/src/main/java/org/teavm/model/BasicBlock.java @@ -228,6 +228,7 @@ public class BasicBlock implements BasicBlockReader, Iterable { @Override public InstructionIterator iterateInstructions() { return new InstructionIterator() { + TextLocation location; Instruction instruction = firstInstruction; Instruction readInstruction; InstructionReadVisitor visitor = new InstructionReadVisitor(null); @@ -257,6 +258,10 @@ public class BasicBlock implements BasicBlockReader, Iterable { @Override public void read(InstructionReader reader) { visitor.reader = reader; + if (!Objects.equals(readInstruction.getLocation(), location)) { + location = readInstruction.getLocation(); + reader.location(location); + } readInstruction.acceptVisitor(visitor); visitor.reader = null; } diff --git a/core/src/main/java/org/teavm/model/optimization/Inlining.java b/core/src/main/java/org/teavm/model/optimization/Inlining.java index 4153db5be..cadd78752 100644 --- a/core/src/main/java/org/teavm/model/optimization/Inlining.java +++ b/core/src/main/java/org/teavm/model/optimization/Inlining.java @@ -136,6 +136,7 @@ public class Inlining { ExitInstruction exit = (ExitInstruction) lastInsn; JumpInstruction exitReplacement = new JumpInstruction(); exitReplacement.setTarget(splitBlock); + exitReplacement.setLocation(exit.getLocation()); exit.replace(exitReplacement); if (exit.getValueToReturn() != null) { Incoming resultIncoming = new Incoming(); 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 c3541db5b..fb5e16b82 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -21,9 +21,12 @@ import com.carrotsearch.hppc.IntObjectMap; import com.carrotsearch.hppc.IntObjectOpenHashMap; import com.carrotsearch.hppc.IntOpenHashSet; import com.carrotsearch.hppc.IntSet; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; +import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -84,9 +87,13 @@ import org.teavm.model.instructions.UnwrapArrayInstruction; public class PhiUpdater { private Program program; private Graph cfg; + private DominatorTree domTree; + private Graph domGraph; private int[][] domFrontiers; private Variable[] variableMap; + private boolean[] variableDefined; private BasicBlock currentBlock; + private TryCatchBlock currentTryCatch; private Phi[][] phiMap; private int[][] phiIndexMap; private Map> jointMap = new HashMap<>(); @@ -124,8 +131,10 @@ public class PhiUpdater { phisByReceiver.clear(); jointsByReceiver.clear(); cfg = ProgramUtils.buildControlFlowGraph(program); - DominatorTree domTree = GraphUtils.buildDominatorTree(cfg); + domTree = GraphUtils.buildDominatorTree(cfg); domFrontiers = new int[cfg.size()][]; + domGraph = GraphUtils.buildDominatorGraph(domTree, program.basicBlockCount()); + variableMap = new Variable[program.variableCount()]; usedDefinitions = new boolean[program.variableCount()]; for (int i = 0; i < arguments.length; ++i) { @@ -167,13 +176,23 @@ public class PhiUpdater { private void estimatePhis() { DefinitionExtractor definitionExtractor = new DefinitionExtractor(); - for (int i = 0; i < program.basicBlockCount(); ++i) { + List> inputJoints = getInputJoints(program); + variableDefined = new boolean[program.variableCount()]; + + IntDeque stack = new IntArrayDeque(); + stack.addLast(0); + while (!stack.isEmpty()) { + int i = stack.removeLast(); currentBlock = program.basicBlockAt(i); if (currentBlock.getExceptionVariable() != null) { markAssignment(currentBlock.getExceptionVariable()); } + for (TryCatchJoint joint : inputJoints.get(currentBlock.getIndex())) { + markAssignment(joint.getReceiver()); + } + for (Phi phi : currentBlock.getPhis()) { markAssignment(phi.getReceiver()); } @@ -197,85 +216,71 @@ public class PhiUpdater { } } } + + for (int successor : domGraph.outgoingEdges(i)) { + stack.addLast(successor); + } } } private static class Task { Variable[] variables; BasicBlock block; + TryCatchBlock tryCatch; + int tryCatchIndex; } private void renameVariables() { - DominatorTree domTree = GraphUtils.buildDominatorTree(ProgramUtils.buildControlFlowGraph(program)); - Graph domGraph = GraphUtils.buildDominatorGraph(domTree, program.basicBlockCount()); - Task[] stack = new Task[cfg.size() * 2]; - int head = 0; + Deque stack = new ArrayDeque<>(); for (int i = 0; i < program.basicBlockCount(); ++i) { if (domGraph.incomingEdgesCount(i) == 0) { Task task = new Task(); task.block = program.basicBlockAt(i); task.variables = variableMap.clone(); - stack[head++] = task; + stack.push(task); } } List> phiOutputs = ProgramUtils.getPhiOutputs(program); - while (head > 0) { - Task task = stack[--head]; + while (!stack.isEmpty()) { + Task task = stack.pop(); currentBlock = task.block; + currentTryCatch = task.tryCatch; int index = currentBlock.getIndex(); variableMap = task.variables.clone(); - if (currentBlock.getExceptionVariable() != null) { - currentBlock.setExceptionVariable(define(currentBlock.getExceptionVariable())); - } + if (currentTryCatch == null) { + if (currentBlock.getExceptionVariable() != null) { + currentBlock.setExceptionVariable(define(currentBlock.getExceptionVariable())); + } - for (Phi phi : synthesizedPhisByBlock.get(index)) { - Variable var = program.createVariable(); - var.setDebugName(phi.getReceiver().getDebugName()); - var.setLabel(phi.getReceiver().getLabel()); - mapVariable(phi.getReceiver().getIndex(), var); - phisByReceiver.put(var.getIndex(), phi); - phi.setReceiver(var); - } - for (Phi phi : currentBlock.getPhis()) { - phi.setReceiver(define(phi.getReceiver())); - } + for (Phi phi : synthesizedPhisByBlock.get(index)) { + Variable var = program.createVariable(); + var.setDebugName(phi.getReceiver().getDebugName()); + var.setLabel(phi.getReceiver().getLabel()); + mapVariable(phi.getReceiver().getIndex(), var); + phisByReceiver.put(var.getIndex(), phi); + phi.setReceiver(var); + } + for (Phi phi : currentBlock.getPhis()) { + phi.setReceiver(define(phi.getReceiver())); + } - for (Instruction insn : currentBlock) { - insn.acceptVisitor(consumer); - } - - 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))); - } + for (Instruction insn : currentBlock) { + insn.acceptVisitor(consumer); + } + } else { + for (TryCatchJoint joint : currentTryCatch.getJoints()) { + 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(); - - variableMap = catchVariableMap; - for (int i = 0; i < currentBlock.getTryCatchBlocks().size(); ++i) { - TryCatchBlock tryCatch = currentBlock.getTryCatchBlocks().get(i); - catchSuccessors.add(tryCatch.getHandler().getIndex()); - for (TryCatchJoint joint : synthesizedJointsByBlock.get(index).get(i)) { + boolean tryCatchIsSuccessor = currentTryCatch != null + && domTree.immediateDominatorOf(currentTryCatch.getHandler().getIndex()) == index; + if (currentTryCatch != null) { + for (TryCatchJoint joint : synthesizedJointsByBlock.get(index).get(task.tryCatchIndex)) { Variable var = program.createVariable(); var.setDebugName(joint.getReceiver().getDebugName()); var.setLabel(joint.getReceiver().getLabel()); @@ -284,21 +289,65 @@ public class PhiUpdater { jointsByReceiver.put(var.getIndex(), joint); } } - variableMap = regularVariableMap; - int[] successors = domGraph.outgoingEdges(index); + int[] successors; + List tryCatchBlockSuccessors = new ArrayList<>(); + IntSet tryCatchSuccessors = new IntOpenHashSet(); + if (currentTryCatch != null) { + successors = tryCatchIsSuccessor ? new int[] { currentTryCatch.getHandler().getIndex() } : new int[0]; + } else { + List tryCatchBlocks = currentBlock.getTryCatchBlocks(); + for (int i = 0; i < tryCatchBlocks.size(); i++) { + TryCatchBlock tryCatch = tryCatchBlocks.get(i); + tryCatchSuccessors.add(tryCatch.getHandler().getIndex()); + tryCatchBlockSuccessors.add(tryCatch); + } + successors = Arrays.stream(domGraph.outgoingEdges(index)) + .filter(successor -> !tryCatchSuccessors.contains(successor)) + .toArray(); + } + + IntSet successorSet = IntOpenHashSet.from(successors); + for (Incoming output : phiOutputs.get(index)) { + if (successorSet.contains(output.getPhi().getBasicBlock().getIndex())) { + Variable var = output.getValue(); + output.setValue(use(var)); + } + } + if (tryCatchIsSuccessor) { + for (TryCatchJoint joint : currentTryCatch.getJoints()) { + for (int i = 0; i < joint.getSourceVariables().size(); ++i) { + joint.getSourceVariables().set(i, use(joint.getSourceVariables().get(i))); + } + } + } + for (int j = successors.length - 1; j >= 0; --j) { int successor = successors[j]; Task next = new Task(); - next.variables = (catchSuccessors.contains(successor) ? catchVariableMap : variableMap).clone(); + next.variables = variableMap.clone(); next.block = program.basicBlockAt(successor); - stack[head++] = next; + stack.push(next); } - successors = cfg.outgoingEdges(index); - for (int successor : successors) { - variableMap = catchSuccessors.contains(successor) ? catchVariableMap : regularVariableMap; - renameOutgoingPhis(successor); + for (int j = tryCatchBlockSuccessors.size() - 1; j >= 0; --j) { + TryCatchBlock tryCatch = tryCatchBlockSuccessors.get(j); + Task next = new Task(); + next.variables = variableMap.clone(); + next.block = currentBlock; + next.tryCatch = tryCatch; + next.tryCatchIndex = j; + stack.push(next); + } + + if (currentTryCatch == null) { + for (int successor : cfg.outgoingEdges(index)) { + if (!tryCatchSuccessors.contains(successor)) { + renameOutgoingPhis(successor); + } + } + } else { + renameOutgoingPhis(currentTryCatch.getHandler().getIndex()); } } } @@ -395,18 +444,22 @@ public class PhiUpdater { 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(); + if (variableDefined[var.getIndex()]) { + 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(); + } } + } else { + variableDefined[var.getIndex()] = true; } while (head > 0) { @@ -504,6 +557,19 @@ public class PhiUpdater { return mappedVar; } + private static List> getInputJoints(Program program) { + List> inputJoints = new ArrayList<>(Collections.nCopies(program.basicBlockCount(), null)); + for (int i = 0; i < program.basicBlockCount(); ++i) { + inputJoints.set(i, new ArrayList<>()); + } + for (BasicBlock block : program.getBasicBlocks()) { + for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { + inputJoints.get(tryCatch.getHandler().getIndex()).addAll(tryCatch.getJoints()); + } + } + return inputJoints; + } + private InstructionVisitor consumer = new InstructionVisitor() { @Override public void visit(EmptyInstruction insn) { 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 index b96023317..8b6075ec5 100644 --- a/core/src/test/resources/model/util/phi-updater/exceptionPhi.expected.txt +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhi.expected.txt @@ -6,8 +6,8 @@ $start @a_2 := ephi @a, @a_1 $catch @b := 1 - @a_4 := @a_2 + @b as int + @a_3 := @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 + @a_4 := phi @a_1 from $start, @a_3 from $catch + return @a_4 \ 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 index 13de5feca..f0051945a 100644 --- a/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.expected.txt +++ b/core/src/test/resources/model/util/phi-updater/exceptionPhiMultiple.expected.txt @@ -5,15 +5,15 @@ $start catch java.lang.RuntimeException goto $catch @a_2 := ephi @a, @a_1 $second - @a_3 := invokeStatic `Foo.boo()I` + @a_5 := invokeStatic `Foo.boo()I` goto $end catch java.lang.RuntimeException goto $catch - @a_4 := ephi @a_1, @a_3 + @a_6 := ephi @a_1, @a_5 $catch - @a_5 := phi @a_2 from $start, @a_4 from $second + @a_3 := phi @a_2 from $start, @a_6 from $second @b := 1 - @a_6 := @a_5 + @b as int + @a_4 := @a_3 + @b as int goto $end $end - @a_7 := phi @a_3 from $second, @a_6 from $catch + @a_7 := phi @a_4 from $catch, @a_5 from $second return @a_7 \ No newline at end of file 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 62cdd9eb8..98c0731ee 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.FULL); + vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE); } @Override