updated allow dead instructions handling

Added labels collecting:
Allow dead instruction block can have several starters and
one stopper that knows all corresponding starters by labels
This commit is contained in:
Svetlana Isakova
2012-12-07 20:09:27 +04:00
parent 28f1d288cf
commit bb2e1c04ec
6 changed files with 104 additions and 48 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@@ -37,8 +38,12 @@ public interface JetControlFlowBuilder {
Label createUnboundLabel(@NotNull String name); Label createUnboundLabel(@NotNull String name);
void bindLabel(@NotNull Label label); void bindLabel(@NotNull Label label);
void allowDead();
void stopAllowDead(); @NotNull
Label createAllowDeadLabel(@NotNull Collection<Label> allowDeadLabels);
@NotNull
Label createAllowDeadLabel(@NotNull String name, @NotNull Collection<Label> allowDeadLabels);
void stopAllowDead(@NotNull Collection<Label> allowDeadLabels);
// Jumps // Jumps
void jump(@NotNull Label label); void jump(@NotNull Label label);
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@@ -61,16 +62,24 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
builder.bindLabel(label); builder.bindLabel(label);
} }
@NotNull
@Override @Override
public void allowDead() { public Label createAllowDeadLabel(@NotNull Collection<Label> allowDeadLabels) {
assert builder != null; assert builder != null;
builder.allowDead(); return builder.createAllowDeadLabel(allowDeadLabels);
}
@NotNull
@Override
public Label createAllowDeadLabel(@NotNull String name, @NotNull Collection<Label> allowDeadLabels) {
assert builder != null;
return builder.createAllowDeadLabel(name, allowDeadLabels);
} }
@Override @Override
public void stopAllowDead() { public void stopAllowDead(@NotNull Collection<Label> allowDeadLabels) {
assert builder != null; assert builder != null;
builder.stopAllowDead(); builder.stopAllowDead(allowDeadLabels);
} }
@Override @Override
@@ -37,6 +37,7 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -378,8 +379,9 @@ public class JetControlFlowProcessor {
} }
value(expression.getTryBlock(), inCondition); value(expression.getTryBlock(), inCondition);
Collection<Label> allowDeadLabels = Lists.newArrayList();
if (hasCatches) { if (hasCatches) {
builder.allowDead(); builder.createAllowDeadLabel(allowDeadLabels);
Label afterCatches = builder.createUnboundLabel("afterCatches"); Label afterCatches = builder.createUnboundLabel("afterCatches");
builder.jump(afterCatches); builder.jump(afterCatches);
@@ -407,14 +409,14 @@ public class JetControlFlowProcessor {
if (catchBody != null) { if (catchBody != null) {
value(catchBody, false); value(catchBody, false);
} }
builder.allowDead(); builder.createAllowDeadLabel(allowDeadLabels);
builder.jump(afterCatches); builder.jump(afterCatches);
} }
builder.bindLabel(afterCatches); builder.bindLabel(afterCatches);
} }
else { else {
builder.allowDead(); builder.createAllowDeadLabel(allowDeadLabels);
} }
if (finallyBlock != null) { if (finallyBlock != null) {
@@ -429,7 +431,7 @@ public class JetControlFlowProcessor {
value(finallyBlock.getFinalExpression(), inCondition); value(finallyBlock.getFinalExpression(), inCondition);
} }
builder.stopAllowDead(); builder.stopAllowDead(allowDeadLabels);
} }
@Override @Override
@@ -784,6 +786,7 @@ public class JetControlFlowProcessor {
Label doneLabel = builder.createUnboundLabel(); Label doneLabel = builder.createUnboundLabel();
Label nextLabel = null; Label nextLabel = null;
Collection<Label> allowDeadLabels = Lists.newArrayList();
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) { for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
JetWhenEntry whenEntry = iterator.next(); JetWhenEntry whenEntry = iterator.next();
@@ -818,7 +821,7 @@ public class JetControlFlowProcessor {
builder.bindLabel(bodyLabel); builder.bindLabel(bodyLabel);
value(whenEntry.getExpression(), inCondition); value(whenEntry.getExpression(), inCondition);
builder.allowDead(); builder.createAllowDeadLabel(allowDeadLabels);
builder.jump(doneLabel); builder.jump(doneLabel);
if (!isIrrefutable) { if (!isIrrefutable) {
@@ -830,7 +833,7 @@ public class JetControlFlowProcessor {
if (!hasElseOrIrrefutableBranch && !isWhenExhaust) { if (!hasElseOrIrrefutableBranch && !isWhenExhaust) {
trace.report(NO_ELSE_IN_WHEN.on(expression)); trace.report(NO_ELSE_IN_WHEN.on(expression));
} }
builder.stopAllowDead(); builder.stopAllowDead(allowDeadLabels);
} }
@Override @Override
@@ -21,4 +21,5 @@ package org.jetbrains.jet.lang.cfg;
*/ */
public interface Label { public interface Label {
String getName(); String getName();
boolean allowDead();
} }
@@ -30,6 +30,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
private final Stack<BreakableBlockInfo> loopInfo = new Stack<BreakableBlockInfo>(); private final Stack<BreakableBlockInfo> loopInfo = new Stack<BreakableBlockInfo>();
private final Map<JetElement, BreakableBlockInfo> elementToBlockInfo = new HashMap<JetElement, BreakableBlockInfo>(); private final Map<JetElement, BreakableBlockInfo> elementToBlockInfo = new HashMap<JetElement, BreakableBlockInfo>();
private int labelCount = 0; private int labelCount = 0;
private int allowDeadLabelCount = 0;
private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>(); private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
@@ -272,18 +273,26 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
pseudocode.bindLabel(label); pseudocode.bindLabel(label);
} }
@NotNull
@Override @Override
public void allowDead() { public Label createAllowDeadLabel(@NotNull Collection<Label> allowDeadLabels) {
Label allowedDeadLabel = createUnboundLabel(); return createAllowDeadLabel("d" + allowDeadLabelCount++, allowDeadLabels);
bindLabel(allowedDeadLabel); }
pseudocode.allowDead(allowedDeadLabel);
@NotNull
@Override
public Label createAllowDeadLabel(@NotNull String name, @NotNull Collection<Label> allowDeadLabels) {
Label label = pseudocode.createAllowDeadLabel(name);
bindLabel(label);
allowDeadLabels.add(label);
return label;
} }
@Override @Override
public void stopAllowDead() { public void stopAllowDead(@NotNull Collection<Label> allowDeadLabels) {
Label allowedDeadLabel = createUnboundLabel(); Label allowedDeadLabel = createUnboundLabel("stop " + allowDeadLabels);
bindLabel(allowedDeadLabel); bindLabel(allowedDeadLabel);
pseudocode.stopAllowDead(allowedDeadLabel); pseudocode.stopAllowDead(allowedDeadLabel, allowDeadLabels);
} }
@Override @Override
@@ -36,11 +36,13 @@ public class PseudocodeImpl implements Pseudocode {
public class PseudocodeLabel implements Label { public class PseudocodeLabel implements Label {
private final String name; private final String name;
private final boolean allowDead;
private Integer targetInstructionIndex; private Integer targetInstructionIndex;
private PseudocodeLabel(String name) { private PseudocodeLabel(String name, boolean allowDead) {
this.name = name; this.name = name;
this.allowDead = allowDead;
} }
@Override @Override
@@ -48,6 +50,11 @@ public class PseudocodeImpl implements Pseudocode {
return name; return name;
} }
@Override
public boolean allowDead() {
return allowDead;
}
@Override @Override
public String toString() { public String toString() {
return name; return name;
@@ -85,8 +92,7 @@ public class PseudocodeImpl implements Pseudocode {
private final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap(); private final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>(); private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
private final List<PseudocodeLabel> allowedDeadLabels = new ArrayList<PseudocodeLabel>(); private final Map<PseudocodeLabel, Collection<Label>> stopAllowDeadLabels = Maps.newHashMap();
private final List<PseudocodeLabel> stopAllowDeadLabels = new ArrayList<PseudocodeLabel>();
private final JetElement correspondingElement; private final JetElement correspondingElement;
private SubroutineExitInstruction exitInstruction; private SubroutineExitInstruction exitInstruction;
@@ -126,17 +132,21 @@ public class PseudocodeImpl implements Pseudocode {
} }
/*package*/ PseudocodeLabel createLabel(String name) { /*package*/ PseudocodeLabel createLabel(String name) {
PseudocodeLabel label = new PseudocodeLabel(name); return createLabel(name, false);
}
private PseudocodeLabel createLabel(String name, boolean allowDead) {
PseudocodeLabel label = new PseudocodeLabel(name, allowDead);
labels.add(label); labels.add(label);
return label; return label;
} }
/*package*/ void allowDead(Label label) { /*package*/ Label createAllowDeadLabel(String name) {
allowedDeadLabels.add((PseudocodeLabel) label); return createLabel(name, true);
} }
/*package*/ void stopAllowDead(Label label) { /*package*/ void stopAllowDead(Label label, Collection<Label> allowDeadLabels) {
stopAllowDeadLabels.add((PseudocodeLabel) label); stopAllowDeadLabels.put((PseudocodeLabel) label, allowDeadLabels);
} }
@Override @Override
@@ -373,24 +383,26 @@ public class PseudocodeImpl implements Pseudocode {
} }
@NotNull @NotNull
private Set<Instruction> prepareAllowedDeadInstructions() { private Map<Instruction, Label> prepareAllowDeadStarters() {
Set<Instruction> allowedDeadStartInstructions = Sets.newHashSet(); Map<Instruction, Label> allowedDeadBeginners = Maps.newHashMap();
for (PseudocodeLabel allowedDeadLabel : allowedDeadLabels) { for (PseudocodeLabel label : labels) {
Instruction allowedDeadInstruction = getJumpTarget(allowedDeadLabel); if (!label.allowDead()) continue;
if (((InstructionImpl)allowedDeadInstruction).isDead()) { Instruction allowDeadPossibleBeginner = getJumpTarget(label);
allowedDeadStartInstructions.add(allowedDeadInstruction); if (((InstructionImpl)allowDeadPossibleBeginner).isDead()) {
allowedDeadBeginners.put(allowDeadPossibleBeginner, label);
} }
} }
return allowedDeadStartInstructions; return allowedDeadBeginners;
} }
@NotNull @NotNull
private Set<Instruction> prepareStopAllowedDeadInstructions() { private Map<Instruction, Collection<Label>> prepareAllowDeadStoppers() {
Set<Instruction> stopAllowedDeadInstructions = Sets.newHashSet(); Map<Instruction, Collection<Label>> stopAllowedDeadInstructions = Maps.newHashMap();
for (PseudocodeLabel stopAllowedDeadLabel : stopAllowDeadLabels) { for (Map.Entry<PseudocodeLabel, Collection<Label>> entry : stopAllowDeadLabels.entrySet()) {
PseudocodeLabel stopAllowedDeadLabel = entry.getKey();
Instruction stopAllowDeadInsruction = getJumpTarget(stopAllowedDeadLabel); Instruction stopAllowDeadInsruction = getJumpTarget(stopAllowedDeadLabel);
if (((InstructionImpl)stopAllowDeadInsruction).isDead()) { if (((InstructionImpl)stopAllowDeadInsruction).isDead()) {
stopAllowedDeadInstructions.add(stopAllowDeadInsruction); stopAllowedDeadInstructions.put(stopAllowDeadInsruction, entry.getValue());
} }
} }
return stopAllowedDeadInstructions; return stopAllowedDeadInstructions;
@@ -398,22 +410,39 @@ public class PseudocodeImpl implements Pseudocode {
@NotNull @NotNull
private Collection<Instruction> collectAllowedDeadInstructions() { private Collection<Instruction> collectAllowedDeadInstructions() {
Set<Instruction> allowedDeadStartInstructions = prepareAllowedDeadInstructions(); // Allow dead instruction block can have several starters and
Set<Instruction> stopAllowDeadInstructions = prepareStopAllowedDeadInstructions(); // one stopper that knows all corresponding starters by labels
Map<Instruction, Label> allowDeadStarters = prepareAllowDeadStarters();
Map<Instruction, Collection<Label>> allowDeadStoppers = prepareAllowDeadStoppers();
Set<Instruction> allowedDeadInstructions = Sets.newHashSet(); Set<Instruction> allowedDeadInstructions = Sets.newHashSet();
for (Instruction allowedDeadStartInstruction : allowedDeadStartInstructions) { for (Map.Entry<Instruction, Label> entry : allowDeadStarters.entrySet()) {
collectAllowedDeadInstructions(allowedDeadStartInstruction, allowedDeadInstructions, stopAllowDeadInstructions); Instruction starter = entry.getKey();
Set<Instruction> allowedDeadFromThisInstruction = Sets.newHashSet();
Label starterLabel = entry.getValue();
collectAllowedDeadInstructions(starter, starterLabel, allowedDeadFromThisInstruction, allowDeadStoppers);
allowedDeadInstructions.addAll(allowedDeadFromThisInstruction);
} }
return allowedDeadInstructions; return allowedDeadInstructions;
} }
private void collectAllowedDeadInstructions(Instruction allowedDeadInstruction, Set<Instruction> instructionSet, Set<Instruction> stopAllowDeadInstructions) { private static void collectAllowedDeadInstructions(
if (instructionSet.contains(allowedDeadInstruction) || stopAllowDeadInstructions.contains(allowedDeadInstruction)) return; @NotNull Instruction current,
if (((InstructionImpl)allowedDeadInstruction).isDead()) { @NotNull Label starterLabel,
instructionSet.add(allowedDeadInstruction); @NotNull Set<Instruction> collectedDeadInstructions,
for (Instruction instruction : allowedDeadInstruction.getNextInstructions()) { @NotNull Map<Instruction, Collection<Label>> allowDeadStoppers
collectAllowedDeadInstructions(instruction, instructionSet, stopAllowDeadInstructions); ) {
if (collectedDeadInstructions.contains(current)) return;
Collection<Label> allowDeadLabels = allowDeadStoppers.get(current);
boolean isStopper = allowDeadLabels != null && allowDeadLabels.contains(starterLabel);
if (isStopper) return;
if (((InstructionImpl)current).isDead()) {
collectedDeadInstructions.add(current);
for (Instruction instruction : current.getNextInstructions()) {
collectAllowedDeadInstructions(instruction, starterLabel, collectedDeadInstructions, allowDeadStoppers);
} }
} }
} }