CF for local functions supported
This commit is contained in:
@@ -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()) {
|
||||
|
||||
@@ -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<JetElement, Pseudocode> data = new LinkedHashMap<JetElement, Pseudocode>();
|
||||
|
||||
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<Pseudocode> getAllData() {
|
||||
return data.values();
|
||||
}
|
||||
}
|
||||
+12
-14
@@ -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<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
|
||||
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;
|
||||
|
||||
@@ -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<Instruction, String> 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<Instruction, String> 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) {
|
||||
|
||||
@@ -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<Pseudocode> pseudocodes = controlFlowDataTrace.getAllData();
|
||||
int[] count = new int[1];
|
||||
Map<Instruction,String> nodeToName = new HashMap<Instruction, String>();
|
||||
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.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user