mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
This commit is contained in:
parent
41f8e10e24
commit
a4cb94df2f
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user