CF supported for function literals

This commit is contained in:
Andrey Breslav
2011-04-01 14:04:51 +04:00
parent f8a5c25714
commit d2c503bd5f
5 changed files with 89 additions and 78 deletions
@@ -105,6 +105,11 @@ public class JetControlFlowProcessor {
exitElement(element); exitElement(element);
} }
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
value(expression.getExpression(), false);
}
@Override @Override
public void visitConstantExpression(JetConstantExpression expression) { public void visitConstantExpression(JetConstantExpression expression) {
builder.readNode(expression); builder.readNode(expression);
@@ -1,7 +1,6 @@
package org.jetbrains.jet.lang.cfg.pseudocode; package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.JetControlFlowBuilder; import org.jetbrains.jet.lang.cfg.JetControlFlowBuilder;
import org.jetbrains.jet.lang.cfg.JetControlFlowBuilderAdapter; import org.jetbrains.jet.lang.cfg.JetControlFlowBuilderAdapter;
import org.jetbrains.jet.lang.cfg.Label; import org.jetbrains.jet.lang.cfg.Label;
@@ -18,17 +17,20 @@ import java.util.Stack;
*/ */
public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter { public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter {
private final Stack<BlockInfo> loopInfo = new Stack<BlockInfo>();
// private final Stack<BlockInfo> subroutineInfo = new Stack<BlockInfo>();
private final Map<JetElement, BlockInfo> elementToBlockInfo = new HashMap<JetElement, BlockInfo>();
private int labelCount = 0; private int labelCount = 0;
private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>(); private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
public JetControlFlowInstructionsGenerator() { public JetControlFlowInstructionsGenerator(JetElement subroutine) {
super(null); super(null);
pushBuilder(); pushBuilder(subroutine);
} }
private void pushBuilder() { private void pushBuilder(JetElement subroutine) {
Pseudocode parentPseudocode = builder == null ? new Pseudocode() : builders.peek().getPseudocode(); JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(subroutine);
JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(parentPseudocode);
builders.push(worker); builders.push(worker);
builder = worker; builder = worker;
} }
@@ -42,7 +44,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override @Override
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) { public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
if (isFunctionLiteral) { if (isFunctionLiteral) {
pushBuilder(); pushBuilder(builder.getCurrentSubroutine());
builder.enterSubroutine(subroutine, false); builder.enterSubroutine(subroutine, false);
} }
else { else {
@@ -57,8 +59,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
JetControlFlowInstructionsGeneratorWorker worker = popBuilder(); JetControlFlowInstructionsGeneratorWorker worker = popBuilder();
JetControlFlowInstructionsGeneratorWorker builder = builders.peek(); JetControlFlowInstructionsGeneratorWorker builder = builders.peek();
FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction(subroutine); FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction(subroutine);
builder.add(instruction);
instruction.setBody(worker.getPseudocode()); instruction.setBody(worker.getPseudocode());
builder.add(instruction);
} }
} }
@@ -66,40 +68,14 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
return builders.peek().getPseudocode(); return builders.peek().getPseudocode();
} }
private static class BlockInfo {
private final JetElement element;
private final Label entryPoint;
private final Label exitPoint;
private BlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
this.element = element;
this.entryPoint = entryPoint;
this.exitPoint = exitPoint;
}
public JetElement getElement() {
return element;
}
public Label getEntryPoint() {
return entryPoint;
}
public Label getExitPoint() {
return exitPoint;
}
}
private final Stack<BlockInfo> loopInfo = new Stack<BlockInfo>();
private final Stack<BlockInfo> subroutineInfo = new Stack<BlockInfo>();
private final Map<JetElement, BlockInfo> elementToBlockInfo = new HashMap<JetElement, BlockInfo>();
private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder { private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder {
private final Pseudocode pseudocode; private final Pseudocode pseudocode;
private final JetElement currentSubroutine;
private JetControlFlowInstructionsGeneratorWorker(@Nullable Pseudocode parent) { private JetControlFlowInstructionsGeneratorWorker(JetElement currentSubroutine) {
this.pseudocode = new Pseudocode(); this.pseudocode = new Pseudocode();
this.currentSubroutine = currentSubroutine;
} }
public Pseudocode getPseudocode() { public Pseudocode getPseudocode() {
@@ -142,14 +118,14 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) { public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
Label entryPoint = createUnboundLabel(); Label entryPoint = createUnboundLabel();
BlockInfo blockInfo = new BlockInfo(subroutine, entryPoint, createUnboundLabel()); BlockInfo blockInfo = new BlockInfo(subroutine, entryPoint, createUnboundLabel());
subroutineInfo.push(blockInfo); // subroutineInfo.push(blockInfo);
elementToBlockInfo.put(subroutine, blockInfo); elementToBlockInfo.put(subroutine, blockInfo);
bindLabel(entryPoint); bindLabel(entryPoint);
} }
@Override @Override
public JetElement getCurrentSubroutine() { public JetElement getCurrentSubroutine() {
return subroutineInfo.empty() ? null : subroutineInfo.peek().getElement(); return currentSubroutine;// subroutineInfo.empty() ? null : subroutineInfo.peek().getElement();
} }
@Override @Override
@@ -159,7 +135,9 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override @Override
public Label getExitPoint(@NotNull JetElement labelElement) { public Label getExitPoint(@NotNull JetElement labelElement) {
return elementToBlockInfo.get(labelElement).getExitPoint(); BlockInfo blockInfo = elementToBlockInfo.get(labelElement);
assert blockInfo != null : labelElement.getText();
return blockInfo.getExitPoint();
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -169,6 +147,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
bindLabel(getExitPoint(subroutine)); bindLabel(getExitPoint(subroutine));
add(new SubroutineExitInstruction(subroutine)); add(new SubroutineExitInstruction(subroutine));
elementToBlockInfo.remove(subroutine); elementToBlockInfo.remove(subroutine);
// subroutineInfo.pop();
} }
@Override @Override
@@ -203,7 +182,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override @Override
public void bindLabel(@NotNull Label label) { public void bindLabel(@NotNull Label label) {
pseudocode.addLabel(label); pseudocode.bindLabel(label);
} }
@Override @Override
@@ -227,4 +206,27 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
} }
} }
private static class BlockInfo {
private final JetElement element;
private final Label entryPoint;
private final Label exitPoint;
private BlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
this.element = element;
this.entryPoint = entryPoint;
this.exitPoint = exitPoint;
}
public JetElement getElement() {
return element;
}
public Label getEntryPoint() {
return entryPoint;
}
public Label getExitPoint() {
return exitPoint;
}
}
} }
@@ -11,8 +11,11 @@ import java.util.*;
* @author abreslav * @author abreslav
*/ */
public class Pseudocode { public class Pseudocode {
public class PseudocodeLabel implements Label { public class PseudocodeLabel implements Label {
private final String name; private final String name;
private Integer targetInstructionIndex;
private PseudocodeLabel(String name) { private PseudocodeLabel(String name) {
this.name = name; this.name = name;
@@ -28,35 +31,37 @@ public class Pseudocode {
return name; return name;
} }
public int getTargetInstructionIndex() {
return targetInstructionIndex;
}
public void setTargetInstructionIndex(int targetInstructionIndex) {
this.targetInstructionIndex = targetInstructionIndex;
}
@Nullable @Nullable
private List<Instruction> resolve() { private List<Instruction> resolve() {
Integer result = labels.get(this); assert targetInstructionIndex != null;
assert result != null; return instructions.subList(getTargetInstructionIndex(), instructions.size());
return instructions.subList(result, instructions.size());
} }
} }
private final List<Instruction> instructions = new ArrayList<Instruction>(); private final List<Instruction> instructions = new ArrayList<Instruction>();
private final Map<Label, Integer> labels = new LinkedHashMap<Label, Integer>(); private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
// @Nullable
// private final Pseudocode parent;
//
// public Pseudocode(Pseudocode parent) {
// this.parent = parent;
// }
public PseudocodeLabel createLabel(String name) { public PseudocodeLabel createLabel(String name) {
return new PseudocodeLabel(name); PseudocodeLabel label = new PseudocodeLabel(name);
labels.add(label);
return label;
} }
public void addInstruction(Instruction instruction) { public void addInstruction(Instruction instruction) {
instructions.add(instruction); instructions.add(instruction);
} }
public void addLabel(Label label) { public void bindLabel(Label label) {
labels.put(label, instructions.size()); ((PseudocodeLabel) label).setTargetInstructionIndex(instructions.size());
} }
public void postProcess() { public void postProcess() {
@@ -144,9 +149,9 @@ public class Pseudocode {
public void dumpInstructions(@NotNull PrintStream out) { public void dumpInstructions(@NotNull PrintStream out) {
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) { for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
Instruction instruction = instructions.get(i); Instruction instruction = instructions.get(i);
for (Map.Entry<Label, Integer> entry : labels.entrySet()) { for (PseudocodeLabel label: labels) {
if (entry.getValue() == i) { if (label.getTargetInstructionIndex() == i) {
out.println(entry.getKey() + ":"); out.println(label.getName() + ":");
} }
} }
out.println(" " + instruction); out.println(" " + instruction);
@@ -155,14 +160,13 @@ public class Pseudocode {
public void dumpGraph(@NotNull final PrintStream out) { public void dumpGraph(@NotNull final PrintStream out) {
String graphHeader = "digraph g"; String graphHeader = "digraph g";
dumpSubgraph(out, graphHeader, new int[1], ""); dumpSubgraph(out, graphHeader, new int[1], "", new HashMap<Instruction, String>());
} }
private void dumpSubgraph(final PrintStream out, String graphHeader, final int[] count, String style) { private void dumpSubgraph(final PrintStream out, String graphHeader, final int[] count, String style, final Map<Instruction, String> nodeToName) {
out.println(graphHeader + " {"); out.println(graphHeader + " {");
out.println(style); out.println(style);
final Map<Instruction, String> nodeToName = new HashMap<Instruction, String>();
for (Instruction node : instructions) { for (Instruction node : instructions) {
if (node instanceof UnconditionalJumpInstruction) { if (node instanceof UnconditionalJumpInstruction) {
continue; continue;
@@ -195,7 +199,7 @@ public class Pseudocode {
@Override @Override
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) { public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
int index = count[0]; int index = count[0];
instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";"); instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName);
printEdge(out, nodeToName.get(instruction), "n" + index, null); printEdge(out, nodeToName.get(instruction), "n" + index, null);
visitInstructionWithNext(instruction); visitInstructionWithNext(instruction);
} }
@@ -230,21 +230,21 @@ public class TopDownAnalyzer {
declaringScope.addFunctionDescriptor(descriptor); declaringScope.addFunctionDescriptor(descriptor);
functions.put(function, descriptor); functions.put(function, descriptor);
// JetExpression bodyExpression = function.getBodyExpression(); JetExpression bodyExpression = function.getBodyExpression();
// if (bodyExpression != null) { if (bodyExpression != null) {
// System.out.println("-------------"); System.out.println("-------------");
// JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(); JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(function);
// new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression); new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression);
// Pseudocode pseudocode = instructionsGenerator.getPseudocode(); Pseudocode pseudocode = instructionsGenerator.getPseudocode();
// pseudocode.postProcess(); pseudocode.postProcess();
// pseudocode.dumpInstructions(System.out); pseudocode.dumpInstructions(System.out);
// System.out.println("-------------"); System.out.println("-------------");
// try { try {
// pseudocode.dumpGraph(new PrintStream("/Users/abreslav/work/cfg.dot")); pseudocode.dumpGraph(new PrintStream("/Users/abreslav/work/cfg.dot"));
// } catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
// } }
// } }
} }
private void processProperty(WritableScope declaringScope, JetProperty property) { private void processProperty(WritableScope declaringScope, JetProperty property) {
@@ -29,6 +29,6 @@ public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase {
} }
public void testQualifiedThis() throws Exception { public void testQualifiedThis() throws Exception {
// doTest("/checker/QualifiedThis.jet", true, true); doTest("/checker/QualifiedThis.jet", true, true);
} }
} }