From 84aeb20321a4aca98456c807ad636331c061fca9 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Fri, 6 Mar 2015 22:56:01 +0300 Subject: [PATCH] Handle irreducible loops after async program splitting --- .../teavm/common/DominatorTreeBuilder.java | 4 +- .../model/util/AsyncProgramSplitter.java | 37 ++++++++++ .../teavm/model/util/BasicBlockMapper.java | 33 +++++---- .../util/ProgramNodeSplittingBackend.java | 74 +++++++++++++++++++ 4 files changed, 132 insertions(+), 16 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java diff --git a/teavm-core/src/main/java/org/teavm/common/DominatorTreeBuilder.java b/teavm-core/src/main/java/org/teavm/common/DominatorTreeBuilder.java index 06626673a..0ac1dfe5e 100644 --- a/teavm-core/src/main/java/org/teavm/common/DominatorTreeBuilder.java +++ b/teavm-core/src/main/java/org/teavm/common/DominatorTreeBuilder.java @@ -58,7 +58,9 @@ class DominatorTreeBuilder { } for (int v : graph.incomingEdges(w)) { int u = eval(v); - semidominators[w] = Math.min(semidominators[w], semidominators[u]); + if (semidominators[u] >= 0) { + semidominators[w] = Math.min(semidominators[w], semidominators[u]); + } } addToBucket(vertices[semidominators[w]], w); link(parents[w], w); diff --git a/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index a657c2c45..b817fd3a7 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -16,6 +16,7 @@ package org.teavm.model.util; import java.util.*; +import org.teavm.common.*; import org.teavm.model.*; import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.JumpInstruction; @@ -147,6 +148,18 @@ public class AsyncProgramSplitter { } } + for (Part part : parts) { + IntegerArray blockSuccessors = IntegerArray.of(part.blockSuccessors); + AsyncProgramSplittingBackend splittingBackend = new AsyncProgramSplittingBackend( + new ProgramNodeSplittingBackend(part.program), blockSuccessors); + Graph graph = ProgramUtils.buildControlFlowGraphWithTryCatch(part.program); + int[] weights = new int[graph.size()]; + for (int i = 0; i < part.program.basicBlockCount(); ++i) { + weights[i] = part.program.basicBlockAt(i).getInstructions().size(); + } + GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend); + part.blockSuccessors = splittingBackend.blockSuccessors.getAll(); + } partMap.clear(); } @@ -207,4 +220,28 @@ public class AsyncProgramSplitter { Part targetPart; int source; } + + private static class AsyncProgramSplittingBackend implements GraphSplittingBackend { + private GraphSplittingBackend inner; + private IntegerArray blockSuccessors; + + public AsyncProgramSplittingBackend(GraphSplittingBackend inner, IntegerArray blockSuccessors) { + this.inner = inner; + this.blockSuccessors = blockSuccessors; + } + + @Override + public int[] split(int[] domain, int[] nodes) { + int[] copies = inner.split(domain, nodes); + for (int i = 0; i < copies.length; ++i) { + int copy = copies[i]; + int node = nodes[i]; + if (blockSuccessors.size() <= copy) { + blockSuccessors.add(-1); + } + blockSuccessors.set(copy, blockSuccessors.get(node)); + } + return copies; + } + } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java b/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java index 8162a454f..6a9ab85c3 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java +++ b/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java @@ -27,17 +27,20 @@ public abstract class BasicBlockMapper implements InstructionVisitor { public void transform(Program program) { for (int i = 0; i < program.basicBlockCount(); ++i) { - BasicBlock block = program.basicBlockAt(i); - block.getLastInstruction().acceptVisitor(this); - for (Phi phi : block.getPhis()) { - for (Incoming incoming : phi.getIncomings()) { - incoming.setSource(map(incoming.getSource())); - } - } - for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { - tryCatch.setHandler(map(tryCatch.getHandler())); + transform(program.basicBlockAt(i)); + } + } + + public void transform(BasicBlock block) { + block.getLastInstruction().acceptVisitor(this); + for (Phi phi : block.getPhis()) { + for (Incoming incoming : phi.getIncomings()) { + incoming.setSource(map(incoming.getSource())); } } + for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { + tryCatch.setHandler(map(tryCatch.getHandler())); + } } @Override @@ -187,15 +190,15 @@ public abstract class BasicBlockMapper implements InstructionVisitor { @Override public void visit(MonitorEnterInstruction insn) { - + } @Override public void visit(MonitorExitInstruction insn) { - + } - - - - + + + + } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java b/teavm-core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java new file mode 100644 index 000000000..4a2da749e --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/util/ProgramNodeSplittingBackend.java @@ -0,0 +1,74 @@ +/* + * Copyright 2015 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; + +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.IntIntOpenHashMap; +import org.teavm.common.GraphSplittingBackend; +import org.teavm.model.BasicBlock; +import org.teavm.model.Program; + +/** + * + * @author Alexey Andreev + */ +public class ProgramNodeSplittingBackend implements GraphSplittingBackend { + private Program program; + + public ProgramNodeSplittingBackend(Program program) { + this.program = program; + } + + @Override + public int[] split(int[] domain, int[] nodes) { + int[] copies = new int[nodes.length]; + IntIntMap map = new IntIntOpenHashMap(); + for (int i = 0; i < nodes.length; ++i) { + int node = nodes[i]; + BasicBlock block = program.basicBlockAt(node); + BasicBlock blockCopy = program.createBasicBlock(); + blockCopy.getInstructions().addAll(ProgramUtils.copyInstructions(block, 0, + block.getInstructions().size(), program)); + copies[i] = blockCopy.getIndex(); + map.put(nodes[i], copies[i] + 1); + } + CopyBlockMapper copyBlockMapper = new CopyBlockMapper(map); + for (int i = 0; i < copies.length; ++i) { + copyBlockMapper.transform(program.basicBlockAt(copies[i])); + } + for (int i = 0; i < domain.length; ++i) { + copyBlockMapper.transform(program.basicBlockAt(domain[i])); + } + return copies; + } + + private static class CopyBlockMapper extends BasicBlockMapper { + private IntIntMap map; + + public CopyBlockMapper(IntIntMap map) { + this.map = map; + } + + @Override + protected BasicBlock map(BasicBlock block) { + int mappedIndex = map.get(block.getIndex()); + if (mappedIndex == 0) { + return block; + } + return block.getProgram().basicBlockAt(mappedIndex - 1); + } + } +}