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