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;
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<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 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;
}

View File

@ -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());

View File

@ -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<Instruction> instructions = originalProgram.basicBlockAt(i).getInstructions();
List<Instruction> 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

View File

@ -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;
}

View File

@ -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) {