Control flow graph traversing refactoring

This commit is contained in:
svtk
2011-11-01 20:51:33 +04:00
parent 503f1cf94d
commit 60efd7f56e
2 changed files with 82 additions and 197 deletions
@@ -4,6 +4,8 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.*;
import java.util.Collection;
@@ -14,28 +16,35 @@ import java.util.Map;
/**
* @author svtk
*/
public class JetControlFlowGraphTraverser {
public static <D> Map<Instruction, Pair<D, D>> traverseInstructionGraphUntilFactsStabilization(
Pseudocode pseudocode,
public class JetControlFlowGraphTraverser<D> {
private final Pseudocode pseudocode;
private final Map<Instruction, Pair<D, D>> dataMap = Maps.newLinkedHashMap();
public static <D> JetControlFlowGraphTraverser<D> create(Pseudocode pseudocode) {
return new JetControlFlowGraphTraverser<D>(pseudocode);
}
private JetControlFlowGraphTraverser(Pseudocode pseudocode) {
this.pseudocode = pseudocode;
}
public void collectInformationFromInstructionGraph(
InstructionsMergeStrategy<D> instructionsMergeStrategy,
D initialDataValue,
D initialDataValueForEnterInstruction,
boolean straightDirection) {
Map<Instruction, Pair<D, D>> dataMap = Maps.newLinkedHashMap();
initializeDataMap(dataMap, pseudocode, initialDataValue);
initializeDataMap(pseudocode, initialDataValue);
dataMap.put(pseudocode.getEnterInstruction(), Pair.create(initialDataValueForEnterInstruction, initialDataValueForEnterInstruction));
boolean[] changed = new boolean[1];
changed[0] = true;
while (changed[0]) {
changed[0] = false;
traverseSubGraph(pseudocode, instructionsMergeStrategy, Collections.<Instruction>emptyList(), straightDirection, dataMap, changed, false);
traverseSubGraph(pseudocode, instructionsMergeStrategy, Collections.<Instruction>emptyList(), straightDirection, changed, false);
}
return dataMap;
}
private static <D> void initializeDataMap(
Map<Instruction, Pair<D, D>> dataMap,
private void initializeDataMap(
Pseudocode pseudocode,
D initialDataValue) {
List<Instruction> instructions = pseudocode.getInstructions();
@@ -43,17 +52,16 @@ public class JetControlFlowGraphTraverser {
for (Instruction instruction : instructions) {
dataMap.put(instruction, initialPair);
if (instruction instanceof LocalDeclarationInstruction) {
initializeDataMap(dataMap, ((LocalDeclarationInstruction) instruction).getBody(), initialDataValue);
initializeDataMap(((LocalDeclarationInstruction) instruction).getBody(), initialDataValue);
}
}
}
private static <D> void traverseSubGraph(
private void traverseSubGraph(
Pseudocode pseudocode,
InstructionsMergeStrategy<D> instructionsMergeStrategy,
Collection<Instruction> previousSubGraphInstructions,
boolean straightDirection,
Map<Instruction, Pair<D, D>> dataMap,
boolean[] changed,
boolean isLocal) {
List<Instruction> instructions = pseudocode.getInstructions();
@@ -76,7 +84,7 @@ public class JetControlFlowGraphTraverser {
if (instruction instanceof LocalDeclarationInstruction) {
Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody();
traverseSubGraph(subroutinePseudocode, instructionsMergeStrategy, previousInstructions, straightDirection, dataMap, changed, true);
traverseSubGraph(subroutinePseudocode, instructionsMergeStrategy, previousInstructions, straightDirection, changed, true);
}
Pair<D, D> previousDataValue = dataMap.get(instruction);
@@ -93,24 +101,36 @@ public class JetControlFlowGraphTraverser {
}
}
public static void traverseAndAnalyzeInstructionGraph(
public void traverseAndAnalyzeInstructionGraph(
InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) {
traverseAndAnalyzeInstructionGraph(pseudocode, instructionDataAnalyzeStrategy);
}
private void traverseAndAnalyzeInstructionGraph(
Pseudocode pseudocode,
InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) {
InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) {
List<Instruction> instructions = pseudocode.getInstructions();
for (Instruction instruction : instructions) {
if (((InstructionImpl)instruction).isDead()) continue;
if (instruction instanceof LocalDeclarationInstruction) {
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), instructionDataAnalyzeStrategy);
}
instructionDataAnalyzeStrategy.execute(instruction);
Pair<D, D> pair = dataMap.get(instruction);
instructionDataAnalyzeStrategy.execute(instruction,
pair != null ? pair.getFirst() : null,
pair != null ? pair.getSecond() : null);
}
}
public D getResultInfo() {
return dataMap.get(pseudocode.getExitInstruction()).getFirst();
}
interface InstructionsMergeStrategy<D> {
Pair<D, D> execute(Instruction instruction, Collection<D> incomingEdgesData);
Pair<D, D> execute(Instruction instruction, @NotNull Collection<D> incomingEdgesData);
}
interface InstructionDataAnalyzeStrategy {
void execute(Instruction instruction);
interface InstructionDataAnalyzeStrategy<D> {
void execute(Instruction instruction, @Nullable D enterData, @Nullable D exitData);
}
}
@@ -65,14 +65,6 @@ public class JetFlowInformationProvider {
wrappedTrace.close();
}
// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
// Pseudocode pseudocode = pseudocodeMap.get(subroutine);
// assert pseudocode != null;
//
// SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
// processPreviousInstructions(exitInstruction, new HashSet<Instruction>(), returnedExpressions, elementsReturningUnit);
// }
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetExpression> returnedExpressions) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
@@ -128,149 +120,20 @@ public class JetFlowInformationProvider {
unreachableElements.add(((JetElementInstruction) deadInstruction).getElement());
}
}
// SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
// Set<Instruction> visited = new HashSet<Instruction>();
// collectReachable(enterInstruction, visited, null);
//
// for (Instruction instruction : pseudocode.getInstructions()) {
// if (!visited.contains(instruction) &&
// instruction instanceof JetElementInstruction &&
// // TODO : do {return} while (1 > a)
// !(instruction instanceof ReadUnitValueInstruction)) {
// unreachableElements.add(((JetElementInstruction) instruction).getElement());
// }
// }
}
// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
// Instruction dominatorInstruction = representativeInstructions.get(dominator);
// if (dominatorInstruction == null) {
// return;
// }
// SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
//
// Set<Instruction> reachable = new HashSet<Instruction>();
// collectReachable(enterInstruction, reachable, null);
//
// Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
// reachableWithDominatorProhibited.add(dominatorInstruction);
// collectReachable(enterInstruction, reachableWithDominatorProhibited, null);
//
// for (Instruction instruction : reachable) {
// if (instruction instanceof JetElementInstruction
// && reachable.contains(instruction)
// && !reachableWithDominatorProhibited.contains(instruction)) {
// JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
// dominated.add(elementInstruction.getElement());
// }
// }
// }
//
// public boolean isBreakable(JetLoopExpression loop) {
// LoopInfo info = loopInfo.get(loop);
// Pseudocode.PseudocodeLabel bodyEntryPoint = (Pseudocode.PseudocodeLabel) info.getBodyEntryPoint();
// Pseudocode.PseudocodeLabel exitPoint = (Pseudocode.PseudocodeLabel) info.getExitPoint();
// HashSet<Instruction> visited = Sets.newHashSet();
// Pseudocode.PseudocodeLabel conditionEntryPoint = (Pseudocode.PseudocodeLabel) info.getConditionEntryPoint();
// visited.add(conditionEntryPoint.resolveToInstruction());
// return collectReachable(bodyEntryPoint.resolveToInstruction(), visited, exitPoint.resolveToInstruction());
// }
//
// public boolean isReachable(JetExpression from, JetExpression to) {
// Instruction fromInstr = representativeInstructions.get(from);
// assert fromInstr != null : "No representative instruction for " + from.getText();
// Instruction toInstr = representativeInstructions.get(to);
// assert toInstr != null : "No representative instruction for " + to.getText();
//
// return collectReachable(fromInstr, Sets.<Instruction>newHashSet(), toInstr);
// }
// }
// private boolean collectReachable(Instruction current, Set<Instruction> visited, @Nullable Instruction lookFor) {
// if (!visited.add(current)) return false;
// if (current == lookFor) return true;
//
// for (Instruction nextInstruction : current.getNextInstructions()) {
// if (collectReachable(nextInstruction, visited, lookFor)) {
// return true;
// }
// }
// return false;
// }
// private void processPreviousInstructions(Instruction previousFor, final Set<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
// if (!visited.add(previousFor)) return;
//
// Collection<Instruction> previousInstructions = previousFor.getPreviousInstructions();
// InstructionVisitor visitor = new InstructionVisitor() {
// @Override
// public void visitReadValue(ReadValueInstruction instruction) {
// returnedExpressions.add((JetExpression) instruction.getElement());
// }
//
// @Override
// public void visitReturnValue(ReturnValueInstruction instruction) {
// processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit);
// }
//
// @Override
// public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
// elementsReturningUnit.add(instruction.getElement());
// }
//
// @Override
// public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
// elementsReturningUnit.add(instruction.getSubroutine());
// }
//
// @Override
// public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) {
// context.getTrace().report(UNSUPPORTED.on(instruction.getElement(), "Control-flow builder"));
// }
//
// @Override
// public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
// elementsReturningUnit.add(writeValueInstruction.getElement());
// }
//
// @Override
// public void visitJump(AbstractJumpInstruction instruction) {
// processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit);
// }
//
// @Override
// public void visitReadUnitValue(ReadUnitValueInstruction instruction) {
// returnedExpressions.add((JetExpression) instruction.getElement());
// }
//
// @Override
// public void visitInstruction(Instruction instruction) {
// if (instruction instanceof JetElementInstructionImpl) {
// JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction;
// context.getTrace().report(UNSUPPORTED.on(elementInstruction.getElement(), "Control-flow builder"));
// }
// else {
// throw new UnsupportedOperationException(instruction.toString());
// }
// }
// };
// for (Instruction previousInstruction : previousInstructions) {
// previousInstruction.accept(visitor);
// }
// }
public void markUninitializedVariables(
@NotNull JetElement subroutine,
final boolean inAnonymousInitializers) {
public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean inAnonymousInitializers) {
final Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
JetControlFlowGraphTraverser<Map<VariableDescriptor, InitializationPoints>> traverser = JetControlFlowGraphTraverser.create(pseudocode);
JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>> instructionsMergeStrategy =
new JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>>() {
@Override
public Pair<Map<VariableDescriptor, InitializationPoints>, Map<VariableDescriptor, InitializationPoints>> execute(
Instruction instruction,
Collection<Map<VariableDescriptor, InitializationPoints>> incomingEdgesData) {
@NotNull Collection<Map<VariableDescriptor, InitializationPoints>> incomingEdgesData) {
Set<VariableDescriptor> variablesInScope = Sets.newHashSet();
for (Map<VariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
@@ -300,34 +163,17 @@ public class JetFlowInformationProvider {
}
};
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = prepareInitialMapForStartInstruction(subroutine, pseudocode);
traverser.collectInformationFromInstructionGraph(instructionsMergeStrategy,
Collections.<VariableDescriptor, InitializationPoints>emptyMap(),
initialMapForStartInstruction,
true);
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
InitializationPoints initialPointsForDeclaredVariable = new InitializationPoints(false);
InitializationPoints initialPointsForExternalVariable = new InitializationPoints(true);
for (VariableDescriptor variable : usedVariables) {
if (declaredVariables.contains(variable)) {
initialMapForStartInstruction.put(variable, initialPointsForDeclaredVariable);
}
else {
initialMapForStartInstruction.put(variable, initialPointsForExternalVariable);
}
}
final Map<Instruction, Pair<Map<VariableDescriptor, InitializationPoints>, Map<VariableDescriptor, InitializationPoints>>> dataMap =
JetControlFlowGraphTraverser.traverseInstructionGraphUntilFactsStabilization(pseudocode,
instructionsMergeStrategy,
Collections.<VariableDescriptor, InitializationPoints>emptyMap(),
initialMapForStartInstruction,
true);
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Map<VariableDescriptor, InitializationPoints>>() {
@Override
public void execute(Instruction instruction) {
Pair<Map<VariableDescriptor, InitializationPoints>, Map<VariableDescriptor, InitializationPoints>> variablesData = dataMap.get(instruction);
Map<VariableDescriptor, InitializationPoints> enterData = variablesData.getFirst();
Map<VariableDescriptor, InitializationPoints> exitData = variablesData.getSecond();
public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, InitializationPoints> enterData, @Nullable Map<VariableDescriptor, InitializationPoints> exitData) {
assert enterData != null && exitData != null;
if (instruction instanceof ReadValueInstruction) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
JetElement element = ((ReadValueInstruction) instruction).getElement();
@@ -380,7 +226,7 @@ public class JetFlowInformationProvider {
});
if (inAnonymousInitializers) {
Map<VariableDescriptor, InitializationPoints> lastInfo = dataMap.get(pseudocode.getExitInstruction()).getFirst();
Map<VariableDescriptor, InitializationPoints> lastInfo = traverser.getResultInfo();
for (Map.Entry<VariableDescriptor, InitializationPoints> entry : lastInfo.entrySet()) {
VariableDescriptor variable = entry.getKey();
if (variable instanceof PropertyDescriptor) {
@@ -390,7 +236,26 @@ public class JetFlowInformationProvider {
}
}
}
private Map<VariableDescriptor, InitializationPoints> prepareInitialMapForStartInstruction(JetElement subroutine, Pseudocode pseudocode) {
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
InitializationPoints initialPointsForDeclaredVariable = new InitializationPoints(false);
InitializationPoints initialPointsForExternalVariable = new InitializationPoints(true);
for (VariableDescriptor variable : usedVariables) {
if (declaredVariables.contains(variable)) {
initialMapForStartInstruction.put(variable, initialPointsForDeclaredVariable);
}
else {
initialMapForStartInstruction.put(variable, initialPointsForExternalVariable);
}
}
return initialMapForStartInstruction;
}
public void markNotOnlyInvokedFunctionVariables(@NotNull JetElement subroutine, List<? extends VariableDescriptor> variables) {
final List<VariableDescriptor> functionVariables = Lists.newArrayList();
for (VariableDescriptor variable : variables) {
@@ -402,16 +267,16 @@ public class JetFlowInformationProvider {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
JetControlFlowGraphTraverser.<Void>create(pseudocode).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
@Override
public void execute(Instruction instruction) {
public void execute(Instruction instruction, Void enterData, Void exitData) {
if (instruction instanceof ReadValueInstruction) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
if (variableDescriptor != null && functionVariables.contains(variableDescriptor)) {
//check that we only invoke this variable
JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression && !(element.getParent() instanceof JetCallExpression)) {
trace.report(Errors.FUNCTION_PARAMETERS_OF_INLINE_FUNCTION.on((JetSimpleNameExpression)element, variableDescriptor));
trace.report(Errors.FUNCTION_PARAMETERS_OF_INLINE_FUNCTION.on((JetSimpleNameExpression) element, variableDescriptor));
}
}
}
@@ -449,9 +314,9 @@ public class JetFlowInformationProvider {
private Collection<VariableDescriptor> collectUsedVariables(Pseudocode pseudocode) {
final Set<VariableDescriptor> usedVariables = Sets.newHashSet();
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
JetControlFlowGraphTraverser.<Void>create(pseudocode).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
@Override
public void execute(Instruction instruction) {
public void execute(Instruction instruction, Void enterData, Void exitData) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
if (variableDescriptor != null) {
usedVariables.add(variableDescriptor);
@@ -462,13 +327,13 @@ public class JetFlowInformationProvider {
}
private Collection<VariableDescriptor> collectDeclaredVariables(JetElement element) {
final Set<VariableDescriptor> concernedVariables = Sets.newHashSet();
final Set<VariableDescriptor> declaredVariables = Sets.newHashSet();
element.accept(new JetTreeVisitor<Void>() {
@Override
public Void visitProperty(JetProperty property, Void data) {
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
assert descriptor instanceof VariableDescriptor;
concernedVariables.add((VariableDescriptor) descriptor);
declaredVariables.add((VariableDescriptor) descriptor);
return null;
}
@@ -478,12 +343,12 @@ public class JetFlowInformationProvider {
if (loopParameter != null) {
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, loopParameter);
assert descriptor instanceof VariableDescriptor;
concernedVariables.add((VariableDescriptor) descriptor);
declaredVariables.add((VariableDescriptor) descriptor);
}
return null;
}
}, null);
return concernedVariables;
return declaredVariables;
}
private static class InitializationPoints {