cfg traversal enhancement

This commit is contained in:
svtk
2011-10-24 18:52:29 +04:00
parent 38464d4e57
commit 3b8819ad24
@@ -183,17 +183,17 @@ public class JetFlowInformationProvider {
// }
// }
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 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;
@@ -259,16 +259,18 @@ public class JetFlowInformationProvider {
private <D> Map<Instruction, D> traverseInstructionGraphUntilFactsStabilization(
Pseudocode pseudocode,
InstructionsMergeHandler<D> instructionsMergeHandler,
D initialDataValue,
D initialDataValue,
D initialDataValueForEnterInstruction,
boolean straightDirection) {
Map<Instruction, D> dataMap = Maps.newHashMap();
initializeDataMap(dataMap, pseudocode, initialDataValue);
dataMap.put(pseudocode.getEnterInstruction(), initialDataValueForEnterInstruction);
boolean[] changed = new boolean[1];
changed[0] = true;
while (changed[0]) {
changed[0] = false;
traverseSubGraph(pseudocode, instructionsMergeHandler, Collections.<Instruction>emptyList(), straightDirection, dataMap, changed);
traverseSubGraph(pseudocode, instructionsMergeHandler, Collections.<Instruction>emptyList(), straightDirection, dataMap, changed, false);
}
return dataMap;
}
@@ -287,15 +289,18 @@ public class JetFlowInformationProvider {
}
private <D> void traverseSubGraph(
Pseudocode pseudocode,
InstructionsMergeHandler<D> instructionsMergeHandler,
Collection<Instruction> previousSubGraphInstructions,
boolean straightDirection,
Map<Instruction, D> dataMap,
boolean[] changed) {
Pseudocode pseudocode,
InstructionsMergeHandler<D> instructionsMergeHandler,
Collection<Instruction> previousSubGraphInstructions,
boolean straightDirection,
Map<Instruction, D> dataMap,
boolean[] changed,
boolean isLocal) {
List<Instruction> instructions = pseudocode.getInstructions();
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
for (Instruction instruction : instructions) {
if (!isLocal && instruction instanceof SubroutineEnterInstruction) continue;
Collection<Instruction> allPreviousInstructions;
Collection<Instruction> previousInstructions = straightDirection
? instruction.getPreviousInstructions()
@@ -311,7 +316,7 @@ public class JetFlowInformationProvider {
if (instruction instanceof LocalDeclarationInstruction) {
Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody();
traverseSubGraph(subroutinePseudocode, instructionsMergeHandler, previousInstructions, straightDirection, dataMap, changed);
traverseSubGraph(subroutinePseudocode, instructionsMergeHandler, previousInstructions, straightDirection, dataMap, changed, true);
}
D previousDataValue = dataMap.get(instruction);
@@ -320,7 +325,7 @@ public class JetFlowInformationProvider {
for (Instruction previousInstruction : allPreviousInstructions) {
incomingEdgesData.add(dataMap.get(previousInstruction));
}
D mergedData = instructionsMergeHandler.merge(instruction, previousDataValue, incomingEdgesData);
D mergedData = instructionsMergeHandler.merge(instruction, incomingEdgesData);
if (!mergedData.equals(previousDataValue)) {
changed[0] = true;
dataMap.put(instruction, mergedData);
@@ -333,86 +338,203 @@ public class JetFlowInformationProvider {
assert pseudocode != null;
Collection<Instruction> instructions = pseudocode.getInstructions();
InstructionsMergeHandler<Set<LocalVariableDescriptor>> instructionsMergeHandler = new InstructionsMergeHandler<Set<LocalVariableDescriptor>>() {
InstructionsMergeHandler<Map<LocalVariableDescriptor, InitializationPoints>> instructionsMergeHandler = new InstructionsMergeHandler<Map<LocalVariableDescriptor, InitializationPoints>>() {
@Override
public Set<LocalVariableDescriptor> merge(Instruction instruction, Set<LocalVariableDescriptor> previousDataValue, Collection<Set<LocalVariableDescriptor>> incomingEdgesData) {
Set<LocalVariableDescriptor> initializedVariables = Sets.newHashSet();
initializedVariables.addAll(previousDataValue);
Set<LocalVariableDescriptor> edgesDataIntersection = Sets.newHashSet();
boolean isFirst = true;
for (Set<LocalVariableDescriptor> edgeData : incomingEdgesData) {
if (isFirst) {
edgesDataIntersection.addAll(edgeData);
}
else {
edgesDataIntersection = Sets.intersection(edgesDataIntersection, edgeData).immutableCopy();
}
isFirst = false;
}
initializedVariables.addAll(edgesDataIntersection);
public Map<LocalVariableDescriptor, InitializationPoints> merge(
Instruction instruction,
Collection<Map<LocalVariableDescriptor, InitializationPoints>> incomingEdgesData) {
if (instruction instanceof WriteValueInstruction) {
DeclarationDescriptor descriptor = null;
JetElement lValue = ((WriteValueInstruction) instruction).getlValue();
if (lValue instanceof JetProperty || lValue instanceof JetParameter) {
descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue);
}
else if (lValue instanceof JetSimpleNameExpression) {
descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue);
}
if (descriptor instanceof LocalVariableDescriptor) {
initializedVariables.add((LocalVariableDescriptor) descriptor);
}
Set<LocalVariableDescriptor> variablesInScope = Sets.newHashSet();
for (Map<LocalVariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
variablesInScope.addAll(edgePointsMap.keySet());
}
return initializedVariables;
Map<LocalVariableDescriptor, InitializationPoints> pointsMap = Maps.newHashMap();
for (LocalVariableDescriptor variable : variablesInScope) {
Set<InitializationPoints> edgesDataForVariable = Sets.newHashSet();
for (Map<LocalVariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
InitializationPoints points = edgePointsMap.get(variable);
if (points != null) {
edgesDataForVariable.add(points);
}
}
pointsMap.put(variable, new InitializationPoints(edgesDataForVariable));
}
if (instruction instanceof WriteValueInstruction) {
LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
// DeclarationDescriptor descriptor = null;
// JetElement lValue = ((WriteValueInstruction) instruction).getlValue();
// if (lValue instanceof JetProperty || lValue instanceof JetParameter) {
// descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue);
// }
// else if (lValue instanceof JetSimpleNameExpression) {
// descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue);
// }
// if (descriptor instanceof LocalVariableDescriptor) {
// LocalVariableDescriptor variableDescriptor = (LocalVariableDescriptor) descriptor;
InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement());
pointsMap.put(variableDescriptor, initializationAtThisPoint);
// }
}
return pointsMap;
}
};
Map<Instruction, Set<LocalVariableDescriptor>> dataMap = traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeHandler, Collections.<LocalVariableDescriptor>emptySet(), true);
InstructionDataAnalyzer instructionDataAnalyzer = new InstructionDataAnalyzer<Set<LocalVariableDescriptor>>() {
Set<LocalVariableDescriptor> localVariables = collectAllLocalVariables(pseudocode);
Map<LocalVariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
InitializationPoints initialPoints = new InitializationPoints();
for (LocalVariableDescriptor variable : localVariables) {
initialMapForStartInstruction.put(variable, initialPoints);
}
Map<Instruction, Map<LocalVariableDescriptor, InitializationPoints>> dataMap =
traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeHandler, Collections.<LocalVariableDescriptor, InitializationPoints>emptyMap(), initialMapForStartInstruction, true);
InstructionDataAnalyzer<Map<LocalVariableDescriptor, InitializationPoints>> instructionDataAnalyzer = new InstructionDataAnalyzer<Map<LocalVariableDescriptor, InitializationPoints>>() {
@Override
public void analyze(Instruction instruction, Map<Instruction, Set<LocalVariableDescriptor>> dataMap) {
Set<LocalVariableDescriptor> initializedVariables = dataMap.get(instruction);
public void analyze(Instruction instruction, Map<Instruction, Map<LocalVariableDescriptor, InitializationPoints>> dataMap) {
Map<LocalVariableDescriptor, InitializationPoints> variablesData = dataMap.get(instruction);
if (instruction instanceof ReadValueInstruction) {
LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression) {
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
if (descriptor instanceof LocalVariableDescriptor) {
if (!initializedVariables.contains(descriptor)) {
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, descriptor));
}
if (element instanceof JetSimpleNameExpression && variableDescriptor != null) {
// DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
// if (descriptor instanceof LocalVariableDescriptor) {
InitializationPoints initializationPoints = variablesData.get(variableDescriptor);
assert initializationPoints != null;
if (initializationPoints.canBeUninitialized) {
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor));
}
// }
}
}
else if (instruction instanceof WriteValueInstruction) {
JetElement element = ((WriteValueInstruction) instruction).getlValue();
if (element instanceof JetSimpleNameExpression) {
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
if (descriptor instanceof LocalVariableDescriptor) {
if (initializedVariables.contains(descriptor) && !((LocalVariableDescriptor) descriptor).isVar()) {
trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, descriptor));
}
LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
if (element instanceof JetSimpleNameExpression && variableDescriptor != null) {
// DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
// if (descriptor instanceof LocalVariableDescriptor) {
InitializationPoints initializationPoints = variablesData.get(variableDescriptor);
assert initializationPoints != null;
if (initializationPoints.hasPossibleInitializers() && !variableDescriptor.isVar()) {
trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, variableDescriptor));
}
// }
}
}
}
};
traverseInstructionGraphAndReportErrors(instructions, dataMap, instructionDataAnalyzer);
traverseAndAnalyzeInstructionGraph(instructions, dataMap, instructionDataAnalyzer);
}
private void traverseInstructionGraphAndReportErrors(Collection<Instruction> instructions, Map<Instruction, Set<LocalVariableDescriptor>> dataMap, InstructionDataAnalyzer<Set<LocalVariableDescriptor>> instructionDataAnalyzer) {
@Nullable
private LocalVariableDescriptor extractVariableDescriptorIfAny(Instruction instruction) {
LocalVariableDescriptor variableDescriptor = null;
if (instruction instanceof ReadValueInstruction) {
JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression) {
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
if (descriptor instanceof LocalVariableDescriptor) {
variableDescriptor = (LocalVariableDescriptor) descriptor;
}
}
}
else if (instruction instanceof WriteValueInstruction) {
DeclarationDescriptor descriptor = null;
JetElement lValue = ((WriteValueInstruction) instruction).getlValue();
if (lValue instanceof JetProperty || lValue instanceof JetParameter) {
descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue);
}
else if (lValue instanceof JetSimpleNameExpression) {
descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue);
}
if (descriptor instanceof LocalVariableDescriptor) {
variableDescriptor = (LocalVariableDescriptor) descriptor;
}
}
return variableDescriptor;
}
private Set<LocalVariableDescriptor> collectAllLocalVariables(Pseudocode pseudocode) {
final Set<LocalVariableDescriptor> localVariables = Sets.newHashSet();
InstructionDataAnalyzer<Void> analyzer = new InstructionDataAnalyzer<Void>() {
@Override
public void analyze(Instruction instruction, Map<Instruction, Void> dataMap) {
LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
if (variableDescriptor != null) {
localVariables.add(variableDescriptor);
}
}
};
traverseAndAnalyzeInstructionGraph(pseudocode.getInstructions(), Collections.<Instruction, Void>emptyMap(), analyzer);
return localVariables;
}
private <D> void traverseAndAnalyzeInstructionGraph(Collection<Instruction> instructions, Map<Instruction, D> dataMap, InstructionDataAnalyzer<D> instructionDataAnalyzer) {
for (Instruction instruction : instructions) {
if (instruction instanceof LocalDeclarationInstruction) {
traverseInstructionGraphAndReportErrors(((LocalDeclarationInstruction) instruction).getBody().getInstructions(), dataMap, instructionDataAnalyzer);
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody().getInstructions(), dataMap, instructionDataAnalyzer);
}
instructionDataAnalyzer.analyze(instruction, dataMap);
}
}
interface InstructionsMergeHandler<D> {
D merge(Instruction instruction, D previousDataValue, Collection<D> incomingEdgesData);
D merge(Instruction instruction, Collection<D> incomingEdgesData);
}
interface InstructionDataAnalyzer<D> {
void analyze(Instruction instruction, Map<Instruction, D> dataMap);
}
}
private static class InitializationPoints {
private Set<JetElement> possiblePoints = Sets.newHashSet();
private boolean canBeUninitialized;
public InitializationPoints() {
canBeUninitialized = true;
}
public InitializationPoints(JetElement element) {
canBeUninitialized = false;
possiblePoints.add(element);
}
public InitializationPoints(Set<InitializationPoints> edgesData) {
canBeUninitialized = false;
for (InitializationPoints edgeData : edgesData) {
if (edgeData.canBeUninitialized) {
canBeUninitialized = true;
}
possiblePoints.addAll(edgeData.possiblePoints);
}
}
public boolean hasPossibleInitializers() {
return !possiblePoints.isEmpty();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof InitializationPoints)) return false;
InitializationPoints that = (InitializationPoints) o;
if (canBeUninitialized != that.canBeUninitialized) return false;
if (possiblePoints != null ? !possiblePoints.equals(that.possiblePoints) : that.possiblePoints != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = possiblePoints != null ? possiblePoints.hashCode() : 0;
result = 31 * result + (canBeUninitialized ? 1 : 0);
return result;
}
}
}