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
0e3fb1f3d2
commit
79d76f9a4d
|
@ -15,11 +15,15 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.javascript;
|
package org.teavm.javascript;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
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;
|
||||||
import org.teavm.javascript.ast.RegularMethodNode;
|
import org.teavm.javascript.ast.RegularMethodNode;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.util.AsyncProgramSplitter;
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -52,6 +56,9 @@ public class Optimizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter) {
|
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter) {
|
||||||
|
LivenessAnalyzer liveness = new LivenessAnalyzer();
|
||||||
|
liveness.analyze(splitter.getOriginalProgram());
|
||||||
|
|
||||||
boolean[] preservedVars = new boolean[method.getVariables().size()];
|
boolean[] preservedVars = new boolean[method.getVariables().size()];
|
||||||
int[][] readFrequencies = new int[splitter.size()][];
|
int[][] readFrequencies = new int[splitter.size()][];
|
||||||
for (int i = 0; i < splitter.size(); ++i) {
|
for (int i = 0; i < splitter.size(); ++i) {
|
||||||
|
@ -59,16 +66,19 @@ public class Optimizer {
|
||||||
stats.analyze(splitter.getProgram(i));
|
stats.analyze(splitter.getProgram(i));
|
||||||
readFrequencies[i] = stats.reads;
|
readFrequencies[i] = stats.reads;
|
||||||
for (int j = 0; j < stats.writes.length; ++j) {
|
for (int j = 0; j < stats.writes.length; ++j) {
|
||||||
if (stats.readUninitialized[j] || 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) {
|
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());
|
||||||
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, readFrequencies[i]);
|
findEscapingLiveVars(liveness, splitter, i, partPreservedVars);
|
||||||
|
OptimizingVisitor optimizer = new OptimizingVisitor(partPreservedVars, readFrequencies[i]);
|
||||||
part.getStatement().acceptVisitor(optimizer);
|
part.getStatement().acceptVisitor(optimizer);
|
||||||
part.setStatement(optimizer.resultStmt);
|
part.setStatement(optimizer.resultStmt);
|
||||||
}
|
}
|
||||||
|
@ -86,4 +96,45 @@ public class Optimizer {
|
||||||
method.getVariables().set(i, i);
|
method.getVariables().set(i, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void findEscapingLiveVars(LivenessAnalyzer liveness, AsyncProgramSplitter splitter, int partIndex,
|
||||||
|
boolean[] output) {
|
||||||
|
Program originalProgram = splitter.getOriginalProgram();
|
||||||
|
Graph cfg = ProgramUtils.buildControlFlowGraph(originalProgram);
|
||||||
|
int[] successors = splitter.getBlockSuccessors(partIndex);
|
||||||
|
int[] splitPoints = splitter.getSplitPoints(partIndex);
|
||||||
|
|
||||||
|
for (int i = 0; i < originalProgram.basicBlockCount(); ++i) {
|
||||||
|
if (successors[i] < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine live-out vars
|
||||||
|
BitSet liveVars = new BitSet();
|
||||||
|
for (int succ : cfg.outgoingEdges(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();
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
for (Variable var : defExtractor.getDefinedVariables()) {
|
||||||
|
liveVars.clear(var.getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add live variables to output
|
||||||
|
for (int j = liveVars.nextSetBit(0); j >= 0; j = liveVars.nextSetBit(j + 1)) {
|
||||||
|
output[j] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import org.teavm.model.util.UsageExtractor;
|
||||||
class ReadWriteStatsBuilder {
|
class ReadWriteStatsBuilder {
|
||||||
public int[] reads;
|
public int[] reads;
|
||||||
public int[] writes;
|
public int[] writes;
|
||||||
public boolean[] readUninitialized;
|
|
||||||
|
|
||||||
private ReadWriteStatsBuilder() {
|
private ReadWriteStatsBuilder() {
|
||||||
}
|
}
|
||||||
|
@ -39,7 +38,6 @@ class ReadWriteStatsBuilder {
|
||||||
public ReadWriteStatsBuilder(int variableCount) {
|
public ReadWriteStatsBuilder(int variableCount) {
|
||||||
reads = new int[variableCount];
|
reads = new int[variableCount];
|
||||||
writes = new int[variableCount];
|
writes = new int[variableCount];
|
||||||
readUninitialized = new boolean[variableCount];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadWriteStatsBuilder copy() {
|
public ReadWriteStatsBuilder copy() {
|
||||||
|
@ -67,9 +65,6 @@ class ReadWriteStatsBuilder {
|
||||||
}
|
}
|
||||||
for (Variable var : useExtractor.getUsedVariables()) {
|
for (Variable var : useExtractor.getUsedVariables()) {
|
||||||
reads[var.getIndex()]++;
|
reads[var.getIndex()]++;
|
||||||
if (writes[var.getIndex()] == 0) {
|
|
||||||
readUninitialized[var.getIndex()] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Phi phi : block.getPhis()) {
|
for (Phi phi : block.getPhis()) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class AsyncProgramSplitter {
|
||||||
private Map<Long, Integer> partMap = new HashMap<>();
|
private Map<Long, Integer> partMap = new HashMap<>();
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private Set<MethodReference> asyncMethods = new HashSet<>();
|
private Set<MethodReference> asyncMethods = new HashSet<>();
|
||||||
|
private Program program;
|
||||||
|
|
||||||
public AsyncProgramSplitter(ClassReaderSource classSource, Set<MethodReference> asyncMethods) {
|
public AsyncProgramSplitter(ClassReaderSource classSource, Set<MethodReference> asyncMethods) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
|
@ -38,12 +39,15 @@ public class AsyncProgramSplitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void split(Program program) {
|
public void split(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();
|
||||||
initialPart.program = initialProgram;
|
initialPart.program = initialProgram;
|
||||||
initialPart.blockSuccessors = new int[program.basicBlockCount()];
|
initialPart.blockSuccessors = new int[program.basicBlockCount()];
|
||||||
Arrays.fill(initialPart.blockSuccessors, -1);
|
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();
|
||||||
|
@ -87,6 +91,8 @@ public class AsyncProgramSplitter {
|
||||||
}
|
}
|
||||||
last = i;
|
last = i;
|
||||||
|
|
||||||
|
step.targetPart.splitPoints[step.source] = 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
|
||||||
long key = ((long)step.source << 32) | i;
|
long key = ((long)step.source << 32) | i;
|
||||||
|
@ -103,6 +109,8 @@ public class AsyncProgramSplitter {
|
||||||
parts.add(part);
|
parts.add(part);
|
||||||
part.blockSuccessors = new int[program.basicBlockCount() + 1];
|
part.blockSuccessors = new int[program.basicBlockCount() + 1];
|
||||||
Arrays.fill(part.blockSuccessors, -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);
|
||||||
|
@ -192,6 +200,10 @@ public class AsyncProgramSplitter {
|
||||||
return parts.size();
|
return parts.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Program getOriginalProgram() {
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
public Program getProgram(int index) {
|
public Program getProgram(int index) {
|
||||||
return parts.get(index).program;
|
return parts.get(index).program;
|
||||||
}
|
}
|
||||||
|
@ -201,9 +213,18 @@ public class AsyncProgramSplitter {
|
||||||
return Arrays.copyOf(result, result.length);
|
return Arrays.copyOf(result, result.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getBlockSuccessor(int index, int blockIndex) {
|
||||||
|
return parts.get(index).blockSuccessors[blockIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getSplitPoints(int index) {
|
||||||
|
return parts.get(index).splitPoints.clone();
|
||||||
|
}
|
||||||
|
|
||||||
private static class Part {
|
private static class Part {
|
||||||
Program program;
|
Program program;
|
||||||
int[] blockSuccessors;
|
int[] blockSuccessors;
|
||||||
|
int[] splitPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Step {
|
private static class Step {
|
||||||
|
|
|
@ -205,11 +205,11 @@ public class DefinitionExtractor implements InstructionVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterInstruction insn) {
|
public void visit(MonitorEnterInstruction insn) {
|
||||||
|
definedVariables = new Variable[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitInstruction insn) {
|
public void visit(MonitorExitInstruction insn) {
|
||||||
|
definedVariables = new Variable[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
|
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
|
||||||
<mainClass>org.teavm.samples.async.AsyncProgram</mainClass>
|
<mainClass>org.teavm.samples.async.AsyncProgram</mainClass>
|
||||||
<runtime>SEPARATE</runtime>
|
<runtime>SEPARATE</runtime>
|
||||||
<minifying>true</minifying>
|
<minifying>false</minifying>
|
||||||
<debugInformationGenerated>true</debugInformationGenerated>
|
<debugInformationGenerated>true</debugInformationGenerated>
|
||||||
<sourceMapsGenerated>true</sourceMapsGenerated>
|
<sourceMapsGenerated>true</sourceMapsGenerated>
|
||||||
<sourceFilesCopied>true</sourceFilesCopied>
|
<sourceFilesCopied>true</sourceFilesCopied>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user