From 60efd7f56eb4db460c09a2e2982b268b1b0d4f78 Mon Sep 17 00:00:00 2001 From: svtk Date: Tue, 1 Nov 2011 20:51:33 +0400 Subject: [PATCH] Control flow graph traversing refactoring --- .../cfg/JetControlFlowGraphTraverser.java | 58 +++-- .../lang/cfg/JetFlowInformationProvider.java | 221 ++++-------------- 2 files changed, 82 insertions(+), 197 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java index ec0fa13338f..5dbd9032499 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java @@ -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 Map> traverseInstructionGraphUntilFactsStabilization( - Pseudocode pseudocode, +public class JetControlFlowGraphTraverser { + private final Pseudocode pseudocode; + private final Map> dataMap = Maps.newLinkedHashMap(); + + public static JetControlFlowGraphTraverser create(Pseudocode pseudocode) { + return new JetControlFlowGraphTraverser(pseudocode); + } + + private JetControlFlowGraphTraverser(Pseudocode pseudocode) { + this.pseudocode = pseudocode; + } + + public void collectInformationFromInstructionGraph( InstructionsMergeStrategy instructionsMergeStrategy, D initialDataValue, D initialDataValueForEnterInstruction, boolean straightDirection) { - Map> 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.emptyList(), straightDirection, dataMap, changed, false); + traverseSubGraph(pseudocode, instructionsMergeStrategy, Collections.emptyList(), straightDirection, changed, false); } - return dataMap; } - private static void initializeDataMap( - Map> dataMap, + private void initializeDataMap( Pseudocode pseudocode, D initialDataValue) { List 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 void traverseSubGraph( + private void traverseSubGraph( Pseudocode pseudocode, InstructionsMergeStrategy instructionsMergeStrategy, Collection previousSubGraphInstructions, boolean straightDirection, - Map> dataMap, boolean[] changed, boolean isLocal) { List 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 previousDataValue = dataMap.get(instruction); @@ -93,24 +101,36 @@ public class JetControlFlowGraphTraverser { } } - public static void traverseAndAnalyzeInstructionGraph( + public void traverseAndAnalyzeInstructionGraph( + InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { + traverseAndAnalyzeInstructionGraph(pseudocode, instructionDataAnalyzeStrategy); + } + + private void traverseAndAnalyzeInstructionGraph( Pseudocode pseudocode, - InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { + InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { List 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 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 { - Pair execute(Instruction instruction, Collection incomingEdgesData); + Pair execute(Instruction instruction, @NotNull Collection incomingEdgesData); } - interface InstructionDataAnalyzeStrategy { - void execute(Instruction instruction); + interface InstructionDataAnalyzeStrategy { + void execute(Instruction instruction, @Nullable D enterData, @Nullable D exitData); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 00971026b7a..880270690c3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -65,14 +65,6 @@ public class JetFlowInformationProvider { wrappedTrace.close(); } -// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { -// Pseudocode pseudocode = pseudocodeMap.get(subroutine); -// assert pseudocode != null; -// -// SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); -// processPreviousInstructions(exitInstruction, new HashSet(), returnedExpressions, elementsReturningUnit); -// } - public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection 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 visited = new HashSet(); -// 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 dominated) { -// Instruction dominatorInstruction = representativeInstructions.get(dominator); -// if (dominatorInstruction == null) { -// return; -// } -// SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction(); -// -// Set reachable = new HashSet(); -// collectReachable(enterInstruction, reachable, null); -// -// Set reachableWithDominatorProhibited = new HashSet(); -// 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 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.newHashSet(), toInstr); -// } -// } -// private boolean collectReachable(Instruction current, Set 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 visited, final Collection returnedExpressions, final Collection elementsReturningUnit) { -// if (!visited.add(previousFor)) return; -// -// Collection 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> traverser = JetControlFlowGraphTraverser.create(pseudocode); + JetControlFlowGraphTraverser.InstructionsMergeStrategy> instructionsMergeStrategy = new JetControlFlowGraphTraverser.InstructionsMergeStrategy>() { @Override public Pair, Map> execute( Instruction instruction, - Collection> incomingEdgesData) { + @NotNull Collection> incomingEdgesData) { Set variablesInScope = Sets.newHashSet(); for (Map edgePointsMap : incomingEdgesData) { @@ -300,34 +163,17 @@ public class JetFlowInformationProvider { } }; - Collection usedVariables = collectUsedVariables(pseudocode); - Collection declaredVariables = collectDeclaredVariables(subroutine); + Map initialMapForStartInstruction = prepareInitialMapForStartInstruction(subroutine, pseudocode); + + traverser.collectInformationFromInstructionGraph(instructionsMergeStrategy, + Collections.emptyMap(), + initialMapForStartInstruction, + true); - Map 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, Map>> dataMap = - JetControlFlowGraphTraverser.traverseInstructionGraphUntilFactsStabilization(pseudocode, - instructionsMergeStrategy, - Collections.emptyMap(), - initialMapForStartInstruction, - true); - - JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { + traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy>() { @Override - public void execute(Instruction instruction) { - Pair, Map> variablesData = dataMap.get(instruction); - Map enterData = variablesData.getFirst(); - Map exitData = variablesData.getSecond(); + public void execute(Instruction instruction, @Nullable Map enterData, @Nullable Map 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 lastInfo = dataMap.get(pseudocode.getExitInstruction()).getFirst(); + Map lastInfo = traverser.getResultInfo(); for (Map.Entry entry : lastInfo.entrySet()) { VariableDescriptor variable = entry.getKey(); if (variable instanceof PropertyDescriptor) { @@ -390,7 +236,26 @@ public class JetFlowInformationProvider { } } } - + + private Map prepareInitialMapForStartInstruction(JetElement subroutine, Pseudocode pseudocode) { + Collection usedVariables = collectUsedVariables(pseudocode); + Collection declaredVariables = collectDeclaredVariables(subroutine); + + Map 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 variables) { final List 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.create(pseudocode).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { @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 collectUsedVariables(Pseudocode pseudocode) { final Set usedVariables = Sets.newHashSet(); - JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { + JetControlFlowGraphTraverser.create(pseudocode).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { @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 collectDeclaredVariables(JetElement element) { - final Set concernedVariables = Sets.newHashSet(); + final Set declaredVariables = Sets.newHashSet(); element.accept(new JetTreeVisitor() { @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 {