Alexey Andreev 2015-03-27 17:46:26 +04:00
parent 0e3fb1f3d2
commit 79d76f9a4d
5 changed files with 78 additions and 11 deletions

View File

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

View File

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

View File

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

View File

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

View File

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