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.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();
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-7
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user