From a4cb94df2f2aa64c53b6b2d46cbe61ae0eb20543 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 29 Mar 2015 17:50:57 +0300 Subject: [PATCH] Fix https://github.com/konsoletyper/teavm/issues/89 --- .../teavm/codegen/MinifyingAliasProvider.java | 7 ++- .../java/org/teavm/javascript/Decompiler.java | 2 +- .../java/org/teavm/javascript/Optimizer.java | 45 +++++++++-------- .../model/util/AsyncProgramSplitter.java | 49 +++++++++++++------ .../teavm/model/util/RegisterAllocator.java | 4 ++ 5 files changed, 69 insertions(+), 38 deletions(-) diff --git a/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java b/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java index b7eaae831..c79a23ad9 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java +++ b/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java @@ -15,6 +15,7 @@ */ package org.teavm.codegen; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.teavm.model.FieldReference; @@ -26,6 +27,8 @@ import org.teavm.model.MethodReference; * @author Alexey Andreev */ public class MinifyingAliasProvider implements AliasProvider { + private static Set keywords = new HashSet<>(Arrays.asList("do", "if", "else", "for", "case", + "goto", "in", "let", "new", "this", "try", "var", "void", "with")); private static String startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; private static String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -38,7 +41,7 @@ public class MinifyingAliasProvider implements AliasProvider { String result; do { result = getNewAlias(lastVirtual++, startVirtualLetters); - } while (!usedAliases.add(result)); + } while (!usedAliases.add(result) || keywords.contains(result)); return result; } @@ -52,7 +55,7 @@ public class MinifyingAliasProvider implements AliasProvider { String result; do { result = getNewAlias(lastVirtual++, startVirtualLetters); - } while (!usedAliases.add(result)); + } while (!usedAliases.add(result) || keywords.contains(result)); return result; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index c3948c85e..71349ba54 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -249,7 +249,7 @@ public class Decompiler { return true; } - public AsyncMethodNode decompileAsyncCacheMiss(MethodHolder method) { + private AsyncMethodNode decompileAsyncCacheMiss(MethodHolder method) { AsyncMethodNode node = new AsyncMethodNode(method.getReference()); AsyncProgramSplitter splitter = new AsyncProgramSplitter(classSource, splitMethods); splitter.split(method.getProgram()); diff --git a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java index 9ffdd31de..fe0fbf6e7 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java @@ -15,7 +15,8 @@ */ package org.teavm.javascript; -import java.util.*; +import java.util.BitSet; +import java.util.List; import org.teavm.common.Graph; import org.teavm.javascript.ast.AsyncMethodNode; import org.teavm.javascript.ast.AsyncMethodPart; @@ -23,7 +24,11 @@ import org.teavm.javascript.ast.RegularMethodNode; import org.teavm.model.Instruction; import org.teavm.model.Program; import org.teavm.model.Variable; -import org.teavm.model.util.*; +import org.teavm.model.util.AsyncProgramSplitter; +import org.teavm.model.util.DefinitionExtractor; +import org.teavm.model.util.LivenessAnalyzer; +import org.teavm.model.util.ProgramUtils; +import org.teavm.model.util.UsageExtractor; /** * @@ -59,26 +64,23 @@ public class Optimizer { LivenessAnalyzer liveness = new LivenessAnalyzer(); liveness.analyze(splitter.getOriginalProgram()); - boolean[] preservedVars = new boolean[method.getVariables().size()]; - int[][] readFrequencies = new int[splitter.size()][]; + Graph cfg = ProgramUtils.buildControlFlowGraph(splitter.getOriginalProgram()); + for (int i = 0; i < splitter.size(); ++i) { + boolean[] preservedVars = new boolean[method.getVariables().size()]; ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size()); stats.analyze(splitter.getProgram(i)); - readFrequencies[i] = stats.reads; for (int j = 0; j < stats.writes.length; ++j) { if (stats.writes[j] != 1 && stats.reads[j] > 0) { preservedVars[j] = true; } } - } - for (int i = 0; i < splitter.size(); ++i) { - boolean[] partPreservedVars = preservedVars.clone(); AsyncMethodPart part = method.getBody().get(i); BreakEliminator breakEliminator = new BreakEliminator(); breakEliminator.eliminate(part.getStatement()); - findEscapingLiveVars(liveness, splitter, i, partPreservedVars); - OptimizingVisitor optimizer = new OptimizingVisitor(partPreservedVars, readFrequencies[i]); + findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars); + OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.reads); part.getStatement().acceptVisitor(optimizer); part.setStatement(optimizer.resultStmt); } @@ -97,38 +99,39 @@ public class Optimizer { } } - private void findEscapingLiveVars(LivenessAnalyzer liveness, AsyncProgramSplitter splitter, int partIndex, - boolean[] output) { + private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter, + int partIndex, boolean[] output) { Program originalProgram = splitter.getOriginalProgram(); - Graph cfg = ProgramUtils.buildControlFlowGraph(originalProgram); + Program program = splitter.getProgram(partIndex); int[] successors = splitter.getBlockSuccessors(partIndex); int[] splitPoints = splitter.getSplitPoints(partIndex); + int[] originalBlocks = splitter.getOriginalBlocks(partIndex); - for (int i = 0; i < originalProgram.basicBlockCount(); ++i) { - if (successors[i] < 0) { + for (int i = 0; i < program.basicBlockCount(); ++i) { + if (successors[i] < 0 || originalBlocks[i] < 0) { continue; } // Determine live-out vars BitSet liveVars = new BitSet(); - for (int succ : cfg.outgoingEdges(i)) { + for (int succ : cfg.outgoingEdges(originalBlocks[i])) { liveVars.or(liveness.liveIn(succ)); } // Remove from live set all variables that are defined in these blocks DefinitionExtractor defExtractor = new DefinitionExtractor(); UsageExtractor useExtractor = new UsageExtractor(); - List instructions = originalProgram.basicBlockAt(i).getInstructions(); + List instructions = originalProgram.basicBlockAt(originalBlocks[i]).getInstructions(); int splitPoint = splitPoints[i]; for (int j = instructions.size() - 1; j >= splitPoint; --j) { - instructions.get(j).acceptVisitor(useExtractor); instructions.get(j).acceptVisitor(defExtractor); - for (Variable var : useExtractor.getUsedVariables()) { - liveVars.set(var.getIndex()); - } + instructions.get(j).acceptVisitor(useExtractor); for (Variable var : defExtractor.getDefinedVariables()) { liveVars.clear(var.getIndex()); } + for (Variable var : useExtractor.getUsedVariables()) { + liveVars.set(var.getIndex()); + } } // Add live variables to output 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 2c49e180e..dbfa1ac58 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 @@ -42,12 +42,8 @@ public class AsyncProgramSplitter { this.program = program; parts.clear(); Program initialProgram = createStubCopy(program); - Part initialPart = new Part(); + Part initialPart = new Part(program.basicBlockCount()); initialPart.program = initialProgram; - initialPart.blockSuccessors = new int[program.basicBlockCount()]; - Arrays.fill(initialPart.blockSuccessors, -1); - initialPart.splitPoints = new int[program.basicBlockCount()]; - Arrays.fill(initialPart.splitPoints, -1); parts.add(initialPart); partMap.put(0L, 0); Step initialStep = new Step(); @@ -63,6 +59,7 @@ public class AsyncProgramSplitter { continue; } BasicBlock sourceBlock = program.basicBlockAt(step.source); + step.targetPart.originalBlocks[step.source] = step.source; int last = 0; for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) { Instruction insn = sourceBlock.getInstructions().get(i); @@ -91,7 +88,7 @@ public class AsyncProgramSplitter { } last = i; - step.targetPart.splitPoints[step.source] = i; + step.targetPart.splitPoints[targetBlock.getIndex()] = i; // If this instruction already separates program, end with current block and refer to the // existing part @@ -103,14 +100,10 @@ public class AsyncProgramSplitter { // Create a new part Program nextProgram = createStubCopy(program); - Part part = new Part(); + Part part = new Part(program.basicBlockCount() + 1); part.program = nextProgram; int partId = parts.size(); parts.add(part); - part.blockSuccessors = new int[program.basicBlockCount() + 1]; - Arrays.fill(part.blockSuccessors, -1); - part.splitPoints = new int[program.basicBlockCount() + 1]; - Arrays.fill(part.splitPoints, -1); // Mark current instruction as a separator and remember which part is in charge. partMap.put(key, partId); @@ -126,6 +119,7 @@ public class AsyncProgramSplitter { nextProgram)); } step.targetPart = part; + part.originalBlocks[targetBlock.getIndex()] = step.source; } targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, last, sourceBlock.getInstructions().size(), targetBlock.getProgram())); @@ -153,8 +147,10 @@ public class AsyncProgramSplitter { for (Part part : parts) { IntegerArray blockSuccessors = IntegerArray.of(part.blockSuccessors); + IntegerArray originalBlocks = IntegerArray.of(part.originalBlocks); + IntegerArray splitPoints = IntegerArray.of(part.splitPoints); AsyncProgramSplittingBackend splittingBackend = new AsyncProgramSplittingBackend( - new ProgramNodeSplittingBackend(part.program), blockSuccessors); + new ProgramNodeSplittingBackend(part.program), blockSuccessors, originalBlocks, splitPoints); Graph graph = ProgramUtils.buildControlFlowGraphWithTryCatch(part.program); int[] weights = new int[graph.size()]; for (int i = 0; i < part.program.basicBlockCount(); ++i) { @@ -162,6 +158,8 @@ public class AsyncProgramSplitter { } GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend); part.blockSuccessors = splittingBackend.blockSuccessors.getAll(); + part.originalBlocks = splittingBackend.originalBlocks.getAll(); + part.splitPoints = splittingBackend.splitPoints.getAll(); } partMap.clear(); } @@ -221,10 +219,24 @@ public class AsyncProgramSplitter { return parts.get(index).splitPoints.clone(); } - private static class Part { + public int[] getOriginalBlocks(int index) { + return parts.get(index).originalBlocks.clone(); + } + + static class Part { Program program; int[] blockSuccessors; int[] splitPoints; + int[] originalBlocks; + + public Part(int blockCount) { + blockSuccessors = new int[blockCount]; + Arrays.fill(blockSuccessors, -1); + splitPoints = new int[blockCount]; + Arrays.fill(splitPoints, -1); + originalBlocks = new int[blockCount]; + Arrays.fill(originalBlocks, -1); + } } private static class Step { @@ -235,10 +247,15 @@ public class AsyncProgramSplitter { private static class AsyncProgramSplittingBackend implements GraphSplittingBackend { private GraphSplittingBackend inner; private IntegerArray blockSuccessors; + private IntegerArray originalBlocks; + private IntegerArray splitPoints; - public AsyncProgramSplittingBackend(GraphSplittingBackend inner, IntegerArray blockSuccessors) { + public AsyncProgramSplittingBackend(GraphSplittingBackend inner, IntegerArray blockSuccessors, + IntegerArray originalBlocks, IntegerArray splitPoints) { this.inner = inner; this.blockSuccessors = blockSuccessors; + this.originalBlocks = originalBlocks; + this.splitPoints = splitPoints; } @Override @@ -249,8 +266,12 @@ public class AsyncProgramSplitter { int node = nodes[i]; if (blockSuccessors.size() <= copy) { blockSuccessors.add(-1); + splitPoints.add(-1); + originalBlocks.add(-1); } blockSuccessors.set(copy, blockSuccessors.get(node)); + originalBlocks.set(copy, originalBlocks.get(node)); + splitPoints.set(copy, splitPoints.get(node)); } return copies; } diff --git a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java index 8908915fa..9cf08eb82 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -60,6 +60,10 @@ public class RegisterAllocator { for (int i = 0; i < colors.length; ++i) { program.variableAt(i).setRegister(colors[i]); } + + for (int i = 0; i < program.basicBlockCount(); ++i) { + program.basicBlockAt(i).getPhis().clear(); + } } private int[] getVariableCategories(ProgramReader program, MethodReference method) {