Alexey Andreev 2015-03-29 17:50:57 +03:00
parent 41f8e10e24
commit a4cb94df2f
5 changed files with 69 additions and 38 deletions

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.codegen; package org.teavm.codegen;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
@ -26,6 +27,8 @@ import org.teavm.model.MethodReference;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class MinifyingAliasProvider implements AliasProvider { public class MinifyingAliasProvider implements AliasProvider {
private static Set<String> 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 startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; private static String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
@ -38,7 +41,7 @@ public class MinifyingAliasProvider implements AliasProvider {
String result; String result;
do { do {
result = getNewAlias(lastVirtual++, startVirtualLetters); result = getNewAlias(lastVirtual++, startVirtualLetters);
} while (!usedAliases.add(result)); } while (!usedAliases.add(result) || keywords.contains(result));
return result; return result;
} }
@ -52,7 +55,7 @@ public class MinifyingAliasProvider implements AliasProvider {
String result; String result;
do { do {
result = getNewAlias(lastVirtual++, startVirtualLetters); result = getNewAlias(lastVirtual++, startVirtualLetters);
} while (!usedAliases.add(result)); } while (!usedAliases.add(result) || keywords.contains(result));
return result; return result;
} }

View File

@ -249,7 +249,7 @@ public class Decompiler {
return true; return true;
} }
public AsyncMethodNode decompileAsyncCacheMiss(MethodHolder method) { private AsyncMethodNode decompileAsyncCacheMiss(MethodHolder method) {
AsyncMethodNode node = new AsyncMethodNode(method.getReference()); AsyncMethodNode node = new AsyncMethodNode(method.getReference());
AsyncProgramSplitter splitter = new AsyncProgramSplitter(classSource, splitMethods); AsyncProgramSplitter splitter = new AsyncProgramSplitter(classSource, splitMethods);
splitter.split(method.getProgram()); splitter.split(method.getProgram());

View File

@ -15,7 +15,8 @@
*/ */
package org.teavm.javascript; package org.teavm.javascript;
import java.util.*; import java.util.BitSet;
import java.util.List;
import org.teavm.common.Graph; import org.teavm.common.Graph;
import org.teavm.javascript.ast.AsyncMethodNode; import org.teavm.javascript.ast.AsyncMethodNode;
import org.teavm.javascript.ast.AsyncMethodPart; 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.Instruction;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.Variable; 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(); LivenessAnalyzer liveness = new LivenessAnalyzer();
liveness.analyze(splitter.getOriginalProgram()); liveness.analyze(splitter.getOriginalProgram());
boolean[] preservedVars = new boolean[method.getVariables().size()]; Graph cfg = ProgramUtils.buildControlFlowGraph(splitter.getOriginalProgram());
int[][] readFrequencies = new int[splitter.size()][];
for (int i = 0; i < splitter.size(); ++i) { for (int i = 0; i < splitter.size(); ++i) {
boolean[] preservedVars = new boolean[method.getVariables().size()];
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size()); ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(splitter.getProgram(i)); stats.analyze(splitter.getProgram(i));
readFrequencies[i] = stats.reads;
for (int j = 0; j < stats.writes.length; ++j) { for (int j = 0; j < stats.writes.length; ++j) {
if (stats.writes[j] != 1 && stats.reads[j] > 0) { if (stats.writes[j] != 1 && stats.reads[j] > 0) {
preservedVars[j] = true; preservedVars[j] = true;
} }
} }
}
for (int i = 0; i < splitter.size(); ++i) {
boolean[] partPreservedVars = preservedVars.clone();
AsyncMethodPart part = method.getBody().get(i); AsyncMethodPart part = method.getBody().get(i);
BreakEliminator breakEliminator = new BreakEliminator(); BreakEliminator breakEliminator = new BreakEliminator();
breakEliminator.eliminate(part.getStatement()); breakEliminator.eliminate(part.getStatement());
findEscapingLiveVars(liveness, splitter, i, partPreservedVars); findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
OptimizingVisitor optimizer = new OptimizingVisitor(partPreservedVars, readFrequencies[i]); OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.reads);
part.getStatement().acceptVisitor(optimizer); part.getStatement().acceptVisitor(optimizer);
part.setStatement(optimizer.resultStmt); part.setStatement(optimizer.resultStmt);
} }
@ -97,38 +99,39 @@ public class Optimizer {
} }
} }
private void findEscapingLiveVars(LivenessAnalyzer liveness, AsyncProgramSplitter splitter, int partIndex, private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
boolean[] output) { int partIndex, boolean[] output) {
Program originalProgram = splitter.getOriginalProgram(); Program originalProgram = splitter.getOriginalProgram();
Graph cfg = ProgramUtils.buildControlFlowGraph(originalProgram); Program program = splitter.getProgram(partIndex);
int[] successors = splitter.getBlockSuccessors(partIndex); int[] successors = splitter.getBlockSuccessors(partIndex);
int[] splitPoints = splitter.getSplitPoints(partIndex); int[] splitPoints = splitter.getSplitPoints(partIndex);
int[] originalBlocks = splitter.getOriginalBlocks(partIndex);
for (int i = 0; i < originalProgram.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
if (successors[i] < 0) { if (successors[i] < 0 || originalBlocks[i] < 0) {
continue; continue;
} }
// Determine live-out vars // Determine live-out vars
BitSet liveVars = new BitSet(); BitSet liveVars = new BitSet();
for (int succ : cfg.outgoingEdges(i)) { for (int succ : cfg.outgoingEdges(originalBlocks[i])) {
liveVars.or(liveness.liveIn(succ)); liveVars.or(liveness.liveIn(succ));
} }
// Remove from live set all variables that are defined in these blocks // Remove from live set all variables that are defined in these blocks
DefinitionExtractor defExtractor = new DefinitionExtractor(); DefinitionExtractor defExtractor = new DefinitionExtractor();
UsageExtractor useExtractor = new UsageExtractor(); UsageExtractor useExtractor = new UsageExtractor();
List<Instruction> instructions = originalProgram.basicBlockAt(i).getInstructions(); List<Instruction> instructions = originalProgram.basicBlockAt(originalBlocks[i]).getInstructions();
int splitPoint = splitPoints[i]; int splitPoint = splitPoints[i];
for (int j = instructions.size() - 1; j >= splitPoint; --j) { for (int j = instructions.size() - 1; j >= splitPoint; --j) {
instructions.get(j).acceptVisitor(useExtractor);
instructions.get(j).acceptVisitor(defExtractor); instructions.get(j).acceptVisitor(defExtractor);
for (Variable var : useExtractor.getUsedVariables()) { instructions.get(j).acceptVisitor(useExtractor);
liveVars.set(var.getIndex());
}
for (Variable var : defExtractor.getDefinedVariables()) { for (Variable var : defExtractor.getDefinedVariables()) {
liveVars.clear(var.getIndex()); liveVars.clear(var.getIndex());
} }
for (Variable var : useExtractor.getUsedVariables()) {
liveVars.set(var.getIndex());
}
} }
// Add live variables to output // Add live variables to output

View File

@ -42,12 +42,8 @@ public class AsyncProgramSplitter {
this.program = program; this.program = program;
parts.clear(); parts.clear();
Program initialProgram = createStubCopy(program); Program initialProgram = createStubCopy(program);
Part initialPart = new Part(); Part initialPart = new Part(program.basicBlockCount());
initialPart.program = initialProgram; 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); parts.add(initialPart);
partMap.put(0L, 0); partMap.put(0L, 0);
Step initialStep = new Step(); Step initialStep = new Step();
@ -63,6 +59,7 @@ public class AsyncProgramSplitter {
continue; continue;
} }
BasicBlock sourceBlock = program.basicBlockAt(step.source); BasicBlock sourceBlock = program.basicBlockAt(step.source);
step.targetPart.originalBlocks[step.source] = step.source;
int last = 0; int last = 0;
for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) { for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) {
Instruction insn = sourceBlock.getInstructions().get(i); Instruction insn = sourceBlock.getInstructions().get(i);
@ -91,7 +88,7 @@ public class AsyncProgramSplitter {
} }
last = i; 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 // If this instruction already separates program, end with current block and refer to the
// existing part // existing part
@ -103,14 +100,10 @@ public class AsyncProgramSplitter {
// Create a new part // Create a new part
Program nextProgram = createStubCopy(program); Program nextProgram = createStubCopy(program);
Part part = new Part(); Part part = new Part(program.basicBlockCount() + 1);
part.program = nextProgram; part.program = nextProgram;
int partId = parts.size(); int partId = parts.size();
parts.add(part); 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. // Mark current instruction as a separator and remember which part is in charge.
partMap.put(key, partId); partMap.put(key, partId);
@ -126,6 +119,7 @@ public class AsyncProgramSplitter {
nextProgram)); nextProgram));
} }
step.targetPart = part; step.targetPart = part;
part.originalBlocks[targetBlock.getIndex()] = step.source;
} }
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock,
last, sourceBlock.getInstructions().size(), targetBlock.getProgram())); last, sourceBlock.getInstructions().size(), targetBlock.getProgram()));
@ -153,8 +147,10 @@ public class AsyncProgramSplitter {
for (Part part : parts) { for (Part part : parts) {
IntegerArray blockSuccessors = IntegerArray.of(part.blockSuccessors); IntegerArray blockSuccessors = IntegerArray.of(part.blockSuccessors);
IntegerArray originalBlocks = IntegerArray.of(part.originalBlocks);
IntegerArray splitPoints = IntegerArray.of(part.splitPoints);
AsyncProgramSplittingBackend splittingBackend = new AsyncProgramSplittingBackend( AsyncProgramSplittingBackend splittingBackend = new AsyncProgramSplittingBackend(
new ProgramNodeSplittingBackend(part.program), blockSuccessors); new ProgramNodeSplittingBackend(part.program), blockSuccessors, originalBlocks, splitPoints);
Graph graph = ProgramUtils.buildControlFlowGraphWithTryCatch(part.program); Graph graph = ProgramUtils.buildControlFlowGraphWithTryCatch(part.program);
int[] weights = new int[graph.size()]; int[] weights = new int[graph.size()];
for (int i = 0; i < part.program.basicBlockCount(); ++i) { for (int i = 0; i < part.program.basicBlockCount(); ++i) {
@ -162,6 +158,8 @@ public class AsyncProgramSplitter {
} }
GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend); GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend);
part.blockSuccessors = splittingBackend.blockSuccessors.getAll(); part.blockSuccessors = splittingBackend.blockSuccessors.getAll();
part.originalBlocks = splittingBackend.originalBlocks.getAll();
part.splitPoints = splittingBackend.splitPoints.getAll();
} }
partMap.clear(); partMap.clear();
} }
@ -221,10 +219,24 @@ public class AsyncProgramSplitter {
return parts.get(index).splitPoints.clone(); 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; Program program;
int[] blockSuccessors; int[] blockSuccessors;
int[] splitPoints; 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 { private static class Step {
@ -235,10 +247,15 @@ public class AsyncProgramSplitter {
private static class AsyncProgramSplittingBackend implements GraphSplittingBackend { private static class AsyncProgramSplittingBackend implements GraphSplittingBackend {
private GraphSplittingBackend inner; private GraphSplittingBackend inner;
private IntegerArray blockSuccessors; 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.inner = inner;
this.blockSuccessors = blockSuccessors; this.blockSuccessors = blockSuccessors;
this.originalBlocks = originalBlocks;
this.splitPoints = splitPoints;
} }
@Override @Override
@ -249,8 +266,12 @@ public class AsyncProgramSplitter {
int node = nodes[i]; int node = nodes[i];
if (blockSuccessors.size() <= copy) { if (blockSuccessors.size() <= copy) {
blockSuccessors.add(-1); blockSuccessors.add(-1);
splitPoints.add(-1);
originalBlocks.add(-1);
} }
blockSuccessors.set(copy, blockSuccessors.get(node)); blockSuccessors.set(copy, blockSuccessors.get(node));
originalBlocks.set(copy, originalBlocks.get(node));
splitPoints.set(copy, splitPoints.get(node));
} }
return copies; return copies;
} }

View File

@ -60,6 +60,10 @@ public class RegisterAllocator {
for (int i = 0; i < colors.length; ++i) { for (int i = 0; i < colors.length; ++i) {
program.variableAt(i).setRegister(colors[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) { private int[] getVariableCategories(ProgramReader program, MethodReference method) {