diff --git a/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java b/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java index 40a04631f..c9a596a21 100644 --- a/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java +++ b/core/src/main/java/org/teavm/model/util/InterferenceGraphBuilder.java @@ -19,10 +19,6 @@ import java.util.*; import org.teavm.common.MutableGraphNode; import org.teavm.model.*; -/** - * - * @author Alexey Andreev - */ class InterferenceGraphBuilder { public List build(Program program, int paramCount, LivenessAnalyzer liveness) { List nodes = new ArrayList<>(); @@ -32,7 +28,7 @@ class InterferenceGraphBuilder { UsageExtractor useExtractor = new UsageExtractor(); DefinitionExtractor defExtractor = new DefinitionExtractor(); InstructionTransitionExtractor succExtractor = new InstructionTransitionExtractor(); - List> outgoings = getOutgoings(program); + List> outgoings = ProgramUtils.getPhiOutputs(program); Set live = new HashSet<>(128); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); @@ -98,20 +94,4 @@ class InterferenceGraphBuilder { } return nodes; } - - private List> getOutgoings(Program program) { - List> outgoings = new ArrayList<>(program.basicBlockCount()); - for (int i = 0; i < program.basicBlockCount(); ++i) { - outgoings.add(new ArrayList()); - } - for (int i = 0; i < program.basicBlockCount(); ++i) { - BasicBlock block = program.basicBlockAt(i); - for (Phi phi : block.getPhis()) { - for (Incoming incoming : phi.getIncomings()) { - outgoings.get(incoming.getSource().getIndex()).add(incoming); - } - } - } - return outgoings; - } } 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 4f6a6a449..1ea5e0fc3 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -15,12 +15,57 @@ */ package org.teavm.model.util; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.teavm.common.DominatorTree; import org.teavm.common.Graph; import org.teavm.common.GraphUtils; -import org.teavm.model.*; -import org.teavm.model.instructions.*; +import org.teavm.model.BasicBlock; +import org.teavm.model.Incoming; +import org.teavm.model.Instruction; +import org.teavm.model.InvokeDynamicInstruction; +import org.teavm.model.Phi; +import org.teavm.model.Program; +import org.teavm.model.TryCatchBlock; +import org.teavm.model.Variable; +import org.teavm.model.instructions.ArrayLengthInstruction; +import org.teavm.model.instructions.AssignInstruction; +import org.teavm.model.instructions.BinaryBranchingInstruction; +import org.teavm.model.instructions.BinaryInstruction; +import org.teavm.model.instructions.BranchingInstruction; +import org.teavm.model.instructions.CastInstruction; +import org.teavm.model.instructions.CastIntegerInstruction; +import org.teavm.model.instructions.CastNumberInstruction; +import org.teavm.model.instructions.ClassConstantInstruction; +import org.teavm.model.instructions.CloneArrayInstruction; +import org.teavm.model.instructions.ConstructArrayInstruction; +import org.teavm.model.instructions.ConstructInstruction; +import org.teavm.model.instructions.ConstructMultiArrayInstruction; +import org.teavm.model.instructions.DoubleConstantInstruction; +import org.teavm.model.instructions.EmptyInstruction; +import org.teavm.model.instructions.ExitInstruction; +import org.teavm.model.instructions.FloatConstantInstruction; +import org.teavm.model.instructions.GetElementInstruction; +import org.teavm.model.instructions.GetFieldInstruction; +import org.teavm.model.instructions.InitClassInstruction; +import org.teavm.model.instructions.InstructionVisitor; +import org.teavm.model.instructions.IntegerConstantInstruction; +import org.teavm.model.instructions.InvokeInstruction; +import org.teavm.model.instructions.IsInstanceInstruction; +import org.teavm.model.instructions.JumpInstruction; +import org.teavm.model.instructions.LongConstantInstruction; +import org.teavm.model.instructions.MonitorEnterInstruction; +import org.teavm.model.instructions.MonitorExitInstruction; +import org.teavm.model.instructions.NegateInstruction; +import org.teavm.model.instructions.NullCheckInstruction; +import org.teavm.model.instructions.NullConstantInstruction; +import org.teavm.model.instructions.PutElementInstruction; +import org.teavm.model.instructions.PutFieldInstruction; +import org.teavm.model.instructions.RaiseInstruction; +import org.teavm.model.instructions.StringConstantInstruction; +import org.teavm.model.instructions.SwitchInstruction; +import org.teavm.model.instructions.UnwrapArrayInstruction; public class PhiUpdater { private Program program; @@ -30,13 +75,15 @@ public class PhiUpdater { private BasicBlock currentBlock; private Phi[][] phiMap; private int[][] phiIndexMap; + private List> synthesizedPhis = new ArrayList<>(); + private boolean[] usedDefinitions; public void updatePhis(Program program, Variable[] arguments) { if (program.basicBlockCount() == 0) { return; } this.program = program; - cfg = ProgramUtils.buildControlFlowGraphWithTryCatch(program); + cfg = ProgramUtils.buildControlFlowGraph(program); DominatorTree domTree = GraphUtils.buildDominatorTree(cfg); domFrontiers = new int[cfg.size()][]; variableMap = new Variable[program.variableCount()]; @@ -50,6 +97,12 @@ public class PhiUpdater { phiIndexMap[i] = new int[program.variableCount()]; } domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree); + + synthesizedPhis.clear(); + for (int i = 0; i < program.basicBlockCount(); ++i) { + synthesizedPhis.add(new ArrayList<>()); + } + usedDefinitions = new boolean[program.variableCount()]; estimatePhis(); renameVariables(); } @@ -89,61 +142,54 @@ public class PhiUpdater { } } - List> caughtBlocks = new ArrayList<>(); - List> specialPhis = new ArrayList<>(); - for (int i = 0; i < program.basicBlockCount(); ++i) { - caughtBlocks.add(new ArrayList<>()); - specialPhis.add(new ArrayList<>()); - } - for (int i = 0; i < program.basicBlockCount(); ++i) { - for (TryCatchBlock tryCatch : program.basicBlockAt(i).getTryCatchBlocks()) { - caughtBlocks.get(tryCatch.getHandler().getIndex()).add(tryCatch); - } - } + List> phiOutputs = ProgramUtils.getPhiOutputs(program); + boolean[] processed = new boolean[program.basicBlockCount()]; while (head > 0) { Task task = stack[--head]; currentBlock = task.block; - if (processed[currentBlock.getIndex()]) { + int index = currentBlock.getIndex(); + if (processed[index]) { continue; } - processed[currentBlock.getIndex()] = true; + processed[index] = true; variableMap = Arrays.copyOf(task.variables, task.variables.length); - for (Phi phi : currentBlock.getPhis()) { + + for (Phi phi : synthesizedPhis.get(index)) { Variable var = program.createVariable(); var.getDebugNames().addAll(phi.getReceiver().getDebugNames()); variableMap[phi.getReceiver().getIndex()] = var; phi.setReceiver(var); } - if (!caughtBlocks.get(currentBlock.getIndex()).isEmpty()) { - Phi phi = new Phi(); - phi.setReceiver(program.createVariable()); - for (TryCatchBlock tryCatch : caughtBlocks.get(currentBlock.getIndex())) { - variableMap[tryCatch.getExceptionVariable().getIndex()] = phi.getReceiver(); - Set debugNames = tryCatch.getExceptionVariable().getDebugNames(); - tryCatch.setExceptionVariable(program.createVariable()); - tryCatch.getExceptionVariable().getDebugNames().addAll(debugNames); - Incoming incoming = new Incoming(); - incoming.setSource(tryCatch.getProtectedBlock()); - incoming.setValue(tryCatch.getExceptionVariable()); - phi.getIncomings().add(incoming); - } - specialPhis.get(currentBlock.getIndex()).add(phi); + + for (Phi phi : currentBlock.getPhis()) { + phi.setReceiver(define(phi.getReceiver())); } + for (Instruction insn : currentBlock.getInstructions()) { insn.acceptVisitor(consumer); } - int[] successors = domGraph.outgoingEdges(currentBlock.getIndex()); + for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) { + Variable var = tryCatch.getExceptionVariable(); + if (var != null) { + tryCatch.setExceptionVariable(define(var)); + } + } + for (Incoming output : phiOutputs.get(index)) { + output.setValue(use(output.getValue())); + } + + int[] successors = domGraph.outgoingEdges(index); for (int successor : successors) { Task next = new Task(); next.variables = Arrays.copyOf(variableMap, variableMap.length); next.block = program.basicBlockAt(successor); stack[head++] = next; } - successors = cfg.outgoingEdges(currentBlock.getIndex()); + successors = cfg.outgoingEdges(index); for (int successor : successors) { int[] phiIndexes = phiIndexMap[successor]; - List phis = program.basicBlockAt(successor).getPhis(); + List phis = synthesizedPhis.get(successor); for (int j = 0; j < phis.size(); ++j) { Phi phi = phis.get(j); Variable var = variableMap[phiIndexes[j]]; @@ -156,9 +202,8 @@ public class PhiUpdater { } } } - } - for (int i = 0; i < specialPhis.size(); ++i) { - program.basicBlockAt(i).getPhis().addAll(specialPhis.get(i)); + + program.basicBlockAt(index).getPhis().addAll(synthesizedPhis.get(index)); } } @@ -174,13 +219,12 @@ public class PhiUpdater { } for (int frontier : frontiers) { BasicBlock frontierBlock = program.basicBlockAt(frontier); - frontierBlock.getPhis(); Phi phi = phiMap[frontier][var.getIndex()]; if (phi == null) { phi = new Phi(); phi.setReceiver(var); - phiIndexMap[frontier][frontierBlock.getPhis().size()] = var.getIndex(); - frontierBlock.getPhis().add(phi); + phiIndexMap[frontier][synthesizedPhis.get(frontier).size()] = var.getIndex(); + synthesizedPhis.get(frontier).add(phi); phiMap[frontier][var.getIndex()] = phi; worklist[head++] = frontierBlock; } @@ -189,7 +233,14 @@ public class PhiUpdater { } private Variable define(Variable var) { - Variable result = program.createVariable(); + Variable result; + if (!usedDefinitions[var.getIndex()]) { + usedDefinitions[var.getIndex()] = true; + result = var; + } else { + result = program.createVariable(); + } + variableMap[var.getIndex()] = result; return result; } diff --git a/core/src/main/java/org/teavm/model/util/ProgramUtils.java b/core/src/main/java/org/teavm/model/util/ProgramUtils.java index 383fedf80..549b72967 100644 --- a/core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -59,30 +59,6 @@ public final class ProgramUtils { return graphBuilder.build(); } - public static Graph buildControlFlowGraphWithTryCatch(Program program) { - GraphBuilder graphBuilder = new GraphBuilder(program.basicBlockCount()); - InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor(); - for (int i = 0; i < program.basicBlockCount(); ++i) { - BasicBlock block = program.basicBlockAt(i); - Instruction insn = block.getLastInstruction(); - if (insn != null) { - insn.acceptVisitor(transitionExtractor); - if (transitionExtractor.getTargets() != null) { - for (BasicBlock successor : transitionExtractor.getTargets()) { - graphBuilder.addEdge(i, successor.getIndex()); - for (TryCatchBlock succTryCatch : successor.getTryCatchBlocks()) { - graphBuilder.addEdge(i, succTryCatch.getHandler().getIndex()); - } - } - } - } - for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { - graphBuilder.addEdge(i, tryCatch.getHandler().getIndex()); - } - } - return graphBuilder.build(); - } - public static Map getLocationCFG(Program program) { return new LocationGraphBuilder().build(program); } @@ -149,4 +125,22 @@ public final class ProgramUtils { } return result; } + + public static List> getPhiOutputs(Program program) { + List> outputs = new ArrayList<>(program.basicBlockCount()); + for (int i = 0; i < program.basicBlockCount(); ++i) { + outputs.add(new ArrayList<>()); + } + + for (int i = 0; i < program.basicBlockCount(); ++i) { + BasicBlock block = program.basicBlockAt(i); + for (Phi phi : block.getPhis()) { + for (Incoming incoming : phi.getIncomings()) { + outputs.get(incoming.getSource().getIndex()).add(incoming); + } + } + } + + return outputs; + } } diff --git a/core/src/main/java/org/teavm/optimization/LoopInversion.java b/core/src/main/java/org/teavm/optimization/LoopInversion.java index 5db844e4f..b87406729 100644 --- a/core/src/main/java/org/teavm/optimization/LoopInversion.java +++ b/core/src/main/java/org/teavm/optimization/LoopInversion.java @@ -15,12 +15,13 @@ */ package org.teavm.optimization; +import org.teavm.model.ElementModifier; import org.teavm.model.MethodReader; import org.teavm.model.Program; public class LoopInversion implements MethodOptimization { @Override public void optimize(MethodReader method, Program program) { - new LoopInversionImpl(program).apply(); + new LoopInversionImpl(program, method.parameterCount() + 1).apply(); } } diff --git a/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java b/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java index c0f2e2da6..a4381fe7e 100644 --- a/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java +++ b/core/src/main/java/org/teavm/optimization/LoopInversionImpl.java @@ -38,8 +38,10 @@ import org.teavm.model.Instruction; import org.teavm.model.Phi; import org.teavm.model.Program; import org.teavm.model.TryCatchBlock; +import org.teavm.model.Variable; import org.teavm.model.util.BasicBlockMapper; import org.teavm.model.util.InstructionCopyReader; +import org.teavm.model.util.PhiUpdater; import org.teavm.model.util.ProgramUtils; /** @@ -74,12 +76,15 @@ import org.teavm.model.util.ProgramUtils; */ class LoopInversionImpl { private final Program program; + private final int parameterCount; private Graph cfg; private DominatorTree dom; private boolean postponed; + private boolean changed; - LoopInversionImpl(Program program) { + LoopInversionImpl(Program program, int parameterCount) { this.program = program; + this.parameterCount = parameterCount; } void apply() { @@ -90,8 +95,17 @@ class LoopInversionImpl { List loops = getLoopsWithExits(loopGraph); postponed = false; - for (LoopWithExits loop : loops) { - loop.invert(); + if (!loops.isEmpty()) { + for (LoopWithExits loop : loops) { + loop.invert(); + } + if (changed) { + Variable[] inputs = new Variable[parameterCount]; + for (int i = 0; i < inputs.length; ++i) { + inputs[i] = program.variableAt(i); + } + new PhiUpdater().updatePhis(program, inputs); + } } } while (postponed); } @@ -185,6 +199,7 @@ class LoopInversionImpl { removeInternalPhiInputsFromCondition(); removeExternalPhiInputsFromConditionCopy(); + changed = true; return true; } diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index d51c5bbf6..b724671a6 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -15,26 +15,89 @@ */ package org.teavm.vm; -import java.io.*; -import java.util.*; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; import org.teavm.cache.NoCache; -import org.teavm.codegen.*; +import org.teavm.codegen.AliasProvider; +import org.teavm.codegen.DefaultAliasProvider; +import org.teavm.codegen.DefaultNamingStrategy; +import org.teavm.codegen.MinifyingAliasProvider; +import org.teavm.codegen.SourceWriter; +import org.teavm.codegen.SourceWriterBuilder; import org.teavm.common.ServiceRepository; import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.SourceLocation; -import org.teavm.dependency.*; +import org.teavm.dependency.BootstrapMethodSubstitutor; +import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyInfo; +import org.teavm.dependency.DependencyListener; +import org.teavm.dependency.Linker; +import org.teavm.dependency.MethodDependency; import org.teavm.diagnostics.AccumulationDiagnostics; import org.teavm.diagnostics.ProblemProvider; -import org.teavm.javascript.*; +import org.teavm.javascript.Decompiler; +import org.teavm.javascript.EmptyRegularMethodNodeCache; +import org.teavm.javascript.MethodNodeCache; +import org.teavm.javascript.Renderer; +import org.teavm.javascript.RenderingException; import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.spi.GeneratedBy; import org.teavm.javascript.spi.Generator; import org.teavm.javascript.spi.InjectedBy; import org.teavm.javascript.spi.Injector; -import org.teavm.model.*; -import org.teavm.model.instructions.*; -import org.teavm.model.util.*; -import org.teavm.optimization.*; +import org.teavm.model.BasicBlock; +import org.teavm.model.CallLocation; +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderSource; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.ElementHolder; +import org.teavm.model.ElementModifier; +import org.teavm.model.InstructionLocation; +import org.teavm.model.ListableClassHolderSource; +import org.teavm.model.ListableClassReaderSource; +import org.teavm.model.MethodHolder; +import org.teavm.model.MethodReference; +import org.teavm.model.MutableClassHolderSource; +import org.teavm.model.Program; +import org.teavm.model.ProgramCache; +import org.teavm.model.ValueType; +import org.teavm.model.Variable; +import org.teavm.model.instructions.ConstructInstruction; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.InvokeInstruction; +import org.teavm.model.instructions.RaiseInstruction; +import org.teavm.model.instructions.StringConstantInstruction; +import org.teavm.model.util.AsyncMethodFinder; +import org.teavm.model.util.ListingBuilder; +import org.teavm.model.util.MissingItemsProcessor; +import org.teavm.model.util.ModelUtils; +import org.teavm.model.util.ProgramUtils; +import org.teavm.model.util.RegisterAllocator; +import org.teavm.optimization.ArrayUnwrapMotion; +import org.teavm.optimization.Devirtualization; +import org.teavm.optimization.GlobalValueNumbering; +import org.teavm.optimization.LoopInvariantMotion; +import org.teavm.optimization.LoopInversion; +import org.teavm.optimization.MethodOptimization; +import org.teavm.optimization.UnusedVariableElimination; import org.teavm.vm.spi.RendererListener; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; @@ -649,7 +712,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } private List getOptimizations() { - return Arrays.asList(new ArrayUnwrapMotion(), /*new LoopInversion(),*/ new LoopInvariantMotion(), + return Arrays.asList(new ArrayUnwrapMotion(), new LoopInversion(), new LoopInvariantMotion(), new GlobalValueNumbering(), new UnusedVariableElimination()); }