diff --git a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java index e68904e57..6e05819fd 100644 --- a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java +++ b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java @@ -68,12 +68,15 @@ public class Optimizer { public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter, boolean friendlyToDebugger) { LivenessAnalyzer liveness = new LivenessAnalyzer(); - liveness.analyze(splitter.getOriginalProgram()); + liveness.analyze(splitter.getOriginalProgram(), method.getReference().getDescriptor()); Graph cfg = ProgramUtils.buildControlFlowGraph(splitter.getOriginalProgram()); + boolean[] preservedVars = new boolean[method.getVariables().size()]; + for (int i = 0; i < splitter.size(); ++i) { + findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars); + } 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)); applyParametersToWriteStats(stats, method.getReference()); @@ -81,7 +84,6 @@ public class Optimizer { AsyncMethodPart part = method.getBody().get(i); BreakEliminator breakEliminator = new BreakEliminator(); breakEliminator.eliminate(part.getStatement()); - findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars); OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads, stats.constants, friendlyToDebugger); part.getStatement().acceptVisitor(optimizer); diff --git a/core/src/main/java/org/teavm/backend/lowlevel/transform/CoroutineTransformation.java b/core/src/main/java/org/teavm/backend/lowlevel/transform/CoroutineTransformation.java index 6688a373e..754746c84 100644 --- a/core/src/main/java/org/teavm/backend/lowlevel/transform/CoroutineTransformation.java +++ b/core/src/main/java/org/teavm/backend/lowlevel/transform/CoroutineTransformation.java @@ -112,7 +112,7 @@ public class CoroutineTransformation { parameterCount = methodReference.parameterCount(); returnType = methodReference.getReturnType(); variableTypes.inferTypes(program, methodReference); - livenessAnalysis.analyze(program); + livenessAnalysis.analyze(program, methodReference.getDescriptor()); splitter = new BasicBlockSplitter(program); int basicBlockCount = program.basicBlockCount(); createSplitPrologue(); diff --git a/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java b/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java index b5471993c..feb88ed67 100644 --- a/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java +++ b/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java @@ -36,6 +36,7 @@ import org.teavm.model.BasicBlock; import org.teavm.model.FieldReference; import org.teavm.model.Incoming; import org.teavm.model.Instruction; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; import org.teavm.model.Phi; import org.teavm.model.Program; @@ -95,7 +96,7 @@ public class EscapeAnalysis { escapingVars[definitionClasses[i]] = true; } } - analyzePhis(program); + analyzePhis(program, methodReference.getDescriptor()); propagateFields(program, visitor.fields); fields = packFields(visitor.fields); @@ -114,9 +115,9 @@ public class EscapeAnalysis { return varFields != null ? varFields.clone() : null; } - private void analyzePhis(Program program) { + private void analyzePhis(Program program, MethodDescriptor methodDescriptor) { LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); - livenessAnalyzer.analyze(program); + livenessAnalyzer.analyze(program, methodDescriptor); GraphBuilder graphBuilder = new GraphBuilder(program.variableCount()); IntDeque queue = new IntArrayDeque(); diff --git a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java index 020fea5e3..39bd05a91 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java @@ -134,7 +134,7 @@ public class GCShadowStackContributor { List> liveInInformation = new ArrayList<>(); LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); - livenessAnalyzer.analyze(program); + livenessAnalyzer.analyze(program, method.getDescriptor()); DefinitionExtractor defExtractor = new DefinitionExtractor(); UsageExtractor useExtractor = new UsageExtractor(); diff --git a/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java b/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java index 7089161e9..1ea186277 100644 --- a/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java +++ b/core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java @@ -18,6 +18,7 @@ package org.teavm.model.util; import com.carrotsearch.hppc.IntHashSet; import com.carrotsearch.hppc.IntSet; import com.carrotsearch.hppc.IntStack; +import java.util.Arrays; import java.util.BitSet; import org.teavm.common.DominatorTree; import org.teavm.common.Graph; @@ -25,6 +26,7 @@ import org.teavm.common.GraphUtils; import org.teavm.model.BasicBlock; import org.teavm.model.Incoming; import org.teavm.model.Instruction; +import org.teavm.model.MethodDescriptor; import org.teavm.model.Phi; import org.teavm.model.Program; import org.teavm.model.Variable; @@ -45,7 +47,11 @@ public class LivenessAnalyzer { return (BitSet) liveOutVars[block].clone(); } - public void analyze(Program program) { + public void analyze(Program program, MethodDescriptor descriptor) { + analyze(program, descriptor.parameterCount() + 1); + } + + public void analyze(Program program, int parameterCount) { Graph cfg = ProgramUtils.buildControlFlowGraph(program); DominatorTree dominatorTree = GraphUtils.buildDominatorTree(cfg); liveVars = new BitSet[program.basicBlockCount()]; @@ -58,32 +64,28 @@ public class LivenessAnalyzer { UsageExtractor usageExtractor = new UsageExtractor(); DefinitionExtractor defExtractor = new DefinitionExtractor(); IntStack stack = new IntStack(); - int[] definitions = new int[program.variableCount()]; + IntSet[] definitionsBuilder = new IntSet[program.variableCount()]; for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); if (block.getExceptionVariable() != null) { - definitions[block.getExceptionVariable().getIndex()] = i; + addDefinition(definitionsBuilder, block.getExceptionVariable().getIndex(), i); } for (Instruction insn : block) { insn.acceptVisitor(usageExtractor); - IntSet usedVars = new IntHashSet(); for (Variable var : usageExtractor.getUsedVariables()) { stack.push(i); stack.push(var.getIndex()); - usedVars.add(var.getIndex()); } insn.acceptVisitor(defExtractor); for (Variable var : defExtractor.getDefinedVariables()) { - if (!usedVars.contains(var.getIndex())) { - definitions[var.getIndex()] = i; - } + addDefinition(definitionsBuilder, var.getIndex(), i); } } for (Phi phi : block.getPhis()) { - definitions[phi.getReceiver().getIndex()] = i; + addDefinition(definitionsBuilder, phi.getReceiver().getIndex(), i); for (Incoming incoming : phi.getIncomings()) { stack.push(incoming.getSource().getIndex()); stack.push(incoming.getValue().getIndex()); @@ -91,15 +93,39 @@ public class LivenessAnalyzer { } } - while (!stack.isEmpty()) { + int[][] definitions = new int[program.variableCount()][]; + for (int i = 0; i < definitions.length; ++i) { + IntSet definitionsByVar = definitionsBuilder[i]; + if (definitionsByVar == null) { + definitions[i] = new int[0]; + } else { + definitions[i] = definitionsByVar.toArray(); + Arrays.sort(definitions[i]); + } + } + + worklist: while (!stack.isEmpty()) { int variable = stack.pop(); int block = stack.pop(); BitSet blockLiveVars = liveVars[block]; - if (blockLiveVars.get(variable) || definitions[variable] == block - || !dominatorTree.dominates(definitions[variable], block)) { + if (blockLiveVars.get(variable)) { continue; } - liveVars[block].set(variable, true); + + boolean hasDominatingDefinition = variable < parameterCount; + for (int definedAt : definitions[variable]) { + if (definedAt == block) { + continue worklist; + } + if (!hasDominatingDefinition && dominatorTree.dominates(definedAt, block)) { + hasDominatingDefinition = true; + } + } + if (!hasDominatingDefinition) { + continue; + } + + blockLiveVars.set(variable, true); for (int pred : cfg.incomingEdges(block)) { stack.push(pred); stack.push(variable); @@ -118,4 +144,13 @@ public class LivenessAnalyzer { } } } + + private static void addDefinition(IntSet[] definitions, int v, int block) { + IntSet definitionsByVar = definitions[v]; + if (definitionsByVar == null) { + definitionsByVar = new IntHashSet(); + definitions[v] = definitionsByVar; + } + definitionsByVar.add(block); + } } diff --git a/core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/core/src/main/java/org/teavm/model/util/RegisterAllocator.java index b5a335eb4..37df01266 100644 --- a/core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -42,7 +42,7 @@ public class RegisterAllocator { insertPhiArgumentsCopies(program); InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder(); LivenessAnalyzer liveness = new LivenessAnalyzer(); - liveness.analyze(program); + liveness.analyze(program, method.getDescriptor()); List interferenceGraph = interferenceBuilder.build( program, method.parameterCount(), liveness); DisjointSet congruenceClasses = buildPhiCongruenceClasses(program);