CF for local functions supported

This commit is contained in:
Andrey Breslav
2011-04-01 17:51:53 +04:00
parent 12757146d1
commit 783654707a
5 changed files with 114 additions and 59 deletions
@@ -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();
}
}
@@ -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.
}
}
}
}