From 783654707ad32d0ccc15584e3b84fe24722f0511 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 1 Apr 2011 17:51:53 +0400 Subject: [PATCH] CF for local functions supported --- .../jet/lang/cfg/JetControlFlowProcessor.java | 10 +-- .../pseudocode/JetControlFlowDataTrace.java | 30 ++++++++ .../JetControlFlowInstructionsGenerator.java | 26 ++++--- .../jet/lang/cfg/pseudocode/Pseudocode.java | 72 ++++++++++--------- .../jet/lang/resolve/TopDownAnalyzer.java | 35 ++++++--- 5 files changed, 114 insertions(+), 59 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index d2e54136d6c..c1d06c0081c 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -140,11 +140,6 @@ public class JetControlFlowProcessor { } } - @Override - public void visitFunction(JetFunction function) { - generate(function, function.getBodyExpression()); - } - @Override public void visitBinaryExpression(JetBinaryExpression expression) { IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); @@ -333,6 +328,11 @@ public class JetControlFlowProcessor { } } + @Override + public void visitFunction(JetFunction function) { + generate(function, function.getBodyExpression()); + } + @Override public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) { if (preferBlock && !expression.hasParameterSpecification()) { diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java new file mode 100644 index 00000000000..90e422bdab8 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java @@ -0,0 +1,30 @@ +package org.jetbrains.jet.lang.cfg.pseudocode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.psi.JetElement; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author abreslav + */ +public class JetControlFlowDataTrace { + + private Map data = new LinkedHashMap(); + + public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { + data.put(element, pseudocode); + } + + @Nullable + public Pseudocode getControlFlowData(@NotNull JetElement element) { + return data.get(element); + } + + public Collection getAllData() { + return data.values(); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index 32465492f99..dda6a393931 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -8,9 +8,7 @@ import org.jetbrains.jet.lang.psi.JetBlockExpression; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetExpression; -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; +import java.util.*; /** * @author abreslav @@ -23,10 +21,11 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd private int labelCount = 0; private final Stack builders = new Stack(); + private final JetControlFlowDataTrace trace; - public JetControlFlowInstructionsGenerator(JetElement subroutine) { + public JetControlFlowInstructionsGenerator(JetControlFlowDataTrace trace) { super(null); - pushBuilder(subroutine); + this.trace = trace; } private void pushBuilder(JetElement subroutine) { @@ -35,9 +34,12 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd builder = worker; } - private JetControlFlowInstructionsGeneratorWorker popBuilder() { + private JetControlFlowInstructionsGeneratorWorker popBuilder(@NotNull JetElement element) { JetControlFlowInstructionsGeneratorWorker worker = builders.pop(); - builder = builders.peek(); + trace.recordControlFlowData(element, worker.getPseudocode()); + if (!builders.isEmpty()) { + builder = builders.peek(); + } return worker; } @@ -45,18 +47,18 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) { if (isFunctionLiteral) { pushBuilder(builder.getCurrentSubroutine()); - builder.enterSubroutine(subroutine, false); } else { - super.enterSubroutine(subroutine, isFunctionLiteral); + pushBuilder(subroutine); } + builder.enterSubroutine(subroutine, false); } @Override public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) { super.exitSubroutine(subroutine, functionLiteral); + JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine); if (functionLiteral) { - JetControlFlowInstructionsGeneratorWorker worker = popBuilder(); JetControlFlowInstructionsGeneratorWorker builder = builders.peek(); FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction(subroutine); instruction.setBody(worker.getPseudocode()); @@ -64,10 +66,6 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd } } - public Pseudocode getPseudocode() { - return builders.peek().getPseudocode(); - } - private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder { private final Pseudocode pseudocode; diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java index 0d504ea4e4f..67e9899ebc5 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java @@ -175,43 +175,20 @@ public class Pseudocode { out.println(graphHeader + " {"); out.println(style); - for (Instruction node : instructions) { - if (node instanceof UnconditionalJumpInstruction) { - continue; - } - String name = "n" + count[0]++; - nodeToName.put(node, name); - String text = node.toString(); - int newline = text.indexOf("\n"); - if (newline >= 0) { - text = text.substring(0, newline); - } - String shape = "box"; - if (node instanceof ConditionalJumpInstruction) { - shape = "diamond"; - } - else if (node instanceof NondeterministicJumpInstruction) { - shape = "Mdiamond"; - } - else if (node instanceof UnsupportedElementInstruction) { - shape = "box, fillcolor=red, style=filled"; - } - else if (node instanceof FunctionLiteralValueInstruction) { - shape = "Mcircle"; - } - else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) { - shape = "roundrect, style=rounded"; - } - out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); - } + dumpNodes(out, count, nodeToName); + dumpEdges(out, count, nodeToName); + out.println("}"); + } + + public void dumpEdges(final PrintStream out, final int[] count, final Map nodeToName) { for (final Instruction fromInst : instructions) { fromInst.accept(new InstructionVisitor() { @Override public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) { int index = count[0]; - instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName); - printEdge(out, nodeToName.get(instruction), "n" + index, null); +// instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName); + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getBody().instructions.get(0)), null); visitInstructionWithNext(instruction); } @@ -264,7 +241,38 @@ public class Pseudocode { } }); } - out.println("}"); + } + + public void dumpNodes(PrintStream out, int[] count, Map nodeToName) { + for (Instruction node : instructions) { + if (node instanceof UnconditionalJumpInstruction) { + continue; + } + String name = "n" + count[0]++; + nodeToName.put(node, name); + String text = node.toString(); + int newline = text.indexOf("\n"); + if (newline >= 0) { + text = text.substring(0, newline); + } + String shape = "box"; + if (node instanceof ConditionalJumpInstruction) { + shape = "diamond"; + } + else if (node instanceof NondeterministicJumpInstruction) { + shape = "Mdiamond"; + } + else if (node instanceof UnsupportedElementInstruction) { + shape = "box, fillcolor=red, style=filled"; + } + else if (node instanceof FunctionLiteralValueInstruction) { + shape = "Mcircle"; + } + else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) { + shape = "roundrect, style=rounded"; + } + out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); + } } private void printEdge(PrintStream out, String from, String to, String label) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index cba6e74c73d..8caf427aad9 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -4,6 +4,8 @@ import com.intellij.openapi.application.ApplicationManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor; +import org.jetbrains.jet.lang.cfg.pseudocode.Instruction; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTrace; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.psi.*; @@ -233,20 +235,37 @@ public class TopDownAnalyzer { JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression != null) { - JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(function); + JetControlFlowDataTrace controlFlowDataTrace = new JetControlFlowDataTrace(); + JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(controlFlowDataTrace); new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression); - Pseudocode pseudocode = instructionsGenerator.getPseudocode(); - pseudocode.postProcess(); - if (!ApplicationManager.getApplication().isUnitTestMode()) { - System.out.println("-------------"); - pseudocode.dumpInstructions(System.out); - System.out.println("-------------"); try { - pseudocode.dumpGraph(new PrintStream("/Users/abreslav/work/cfg.dot")); + PrintStream out = new PrintStream("/Users/abreslav/work/cfg.dot"); + out.println("digraph " + function.getName() + " {"); + Collection pseudocodes = controlFlowDataTrace.getAllData(); + int[] count = new int[1]; + Map nodeToName = new HashMap(); + for (Pseudocode pseudocode : pseudocodes) { + pseudocode.postProcess(); + System.out.println("-------------"); + pseudocode.dumpInstructions(System.out); + System.out.println("-------------"); + pseudocode.dumpNodes(out, count, nodeToName); + } + int i = 0; + for (Pseudocode pseudocode : pseudocodes) { + out.println("subgraph cluster_" + i + " {\n" + + "label=\"f" + i + "\";\n" + + "color=blue;\n"); + pseudocode.dumpEdges(out, count, nodeToName); + out.println("}"); + i++; + } + out.println("}"); } catch (FileNotFoundException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } + } } }