Try..finally supported by CF-builder

This commit is contained in:
Andrey Breslav
2011-04-14 15:45:39 +04:00
parent bd73ef4bd9
commit 6e9e22df16
9 changed files with 666 additions and 34 deletions
@@ -0,0 +1,8 @@
package org.jetbrains.jet.lang.cfg;
/**
* @author abreslav
*/
public interface GenerationTrigger {
void generate();
}
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.cfg;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetBlockExpression;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
@@ -37,7 +36,7 @@ public interface JetControlFlowBuilder {
@Nullable
JetElement getCurrentLoop();
// Finally
void enterTryFinally(@NotNull JetBlockExpression expression);
void enterTryFinally(@NotNull GenerationTrigger trigger);
void exitTryFinally();
// Subroutines
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.cfg;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetBlockExpression;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
@@ -84,8 +83,8 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
}
@Override
public void enterTryFinally(@NotNull JetBlockExpression expression) {
builder.enterTryFinally(expression);
public void enterTryFinally(@NotNull GenerationTrigger trigger) {
builder.enterTryFinally(trigger);
}
@Override
@@ -272,25 +272,26 @@ public class JetControlFlowProcessor {
@Override
public void visitTryExpression(JetTryExpression expression) {
JetFinallySection finallyBlock = expression.getFinallyBlock();
final JetFinallySection finallyBlock = expression.getFinallyBlock();
if (finallyBlock != null) {
builder.enterTryFinally(finallyBlock.getFinalExpression());
builder.enterTryFinally(new GenerationTrigger() {
@Override
public void generate() {
value(finallyBlock.getFinalExpression(), true, inCondition);
}
});
}
Label onException = builder.createUnboundLabel();
builder.nondeterministicJump(onException);
value(expression.getTryBlock(), true, inCondition);
List<JetCatchClause> catchClauses = expression.getCatchClauses();
if (catchClauses.isEmpty()) {
value(expression.getTryBlock(), true, false);
}
else {
Label catchBlock = builder.createUnboundLabel();
builder.nondeterministicJump(catchBlock);
value(expression.getTryBlock(), true, false);
if (!catchClauses.isEmpty()) {
Label afterCatches = builder.createUnboundLabel();
builder.jump(afterCatches);
builder.bindLabel(catchBlock);
builder.bindLabel(onException);
for (Iterator<JetCatchClause> iterator = catchClauses.iterator(); iterator.hasNext(); ) {
JetCatchClause catchClause = iterator.next();
JetExpression catchBody = catchClause.getCatchBody();
@@ -303,10 +304,13 @@ public class JetControlFlowProcessor {
}
builder.bindLabel(afterCatches);
} else {
builder.bindLabel(onException);
}
if (finallyBlock != null) {
builder.exitTryFinally();
value(finallyBlock.getFinalExpression(), true, inCondition);
}
}
@@ -1,10 +1,10 @@
package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.GenerationTrigger;
import org.jetbrains.jet.lang.cfg.JetControlFlowBuilder;
import org.jetbrains.jet.lang.cfg.JetControlFlowBuilderAdapter;
import org.jetbrains.jet.lang.cfg.Label;
import org.jetbrains.jet.lang.psi.JetBlockExpression;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
@@ -16,11 +16,14 @@ import java.util.*;
*/
public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter {
private final Stack<BlockInfo> loopInfo = new Stack<BlockInfo>();
private final Map<JetElement, BlockInfo> elementToBlockInfo = new HashMap<JetElement, BlockInfo>();
private final Stack<BreakableBlockInfo> loopInfo = new Stack<BreakableBlockInfo>();
private final Map<JetElement, BreakableBlockInfo> elementToBlockInfo = new HashMap<JetElement, BreakableBlockInfo>();
private int labelCount = 0;
private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
private final Stack<BlockInfo> allBlocks = new Stack<BlockInfo>();
private final JetPseudocodeTrace trace;
public JetControlFlowInstructionsGenerator(JetPseudocodeTrace trace) {
@@ -94,16 +97,18 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
public final Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) {
Label label = createUnboundLabel();
bindLabel(label);
BlockInfo blockInfo = new BlockInfo(expression, label, loopExitPoint);
BreakableBlockInfo blockInfo = new BreakableBlockInfo(expression, label, loopExitPoint);
loopInfo.push(blockInfo);
elementToBlockInfo.put(expression, blockInfo);
allBlocks.push(blockInfo);
return label;
}
@Override
public final void exitLoop(@NotNull JetExpression expression) {
BlockInfo info = loopInfo.pop();
BreakableBlockInfo info = loopInfo.pop();
elementToBlockInfo.remove(expression);
allBlocks.pop();
bindLabel(info.getExitPoint());
}
@@ -115,9 +120,10 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
Label entryPoint = createUnboundLabel();
BlockInfo blockInfo = new BlockInfo(subroutine, entryPoint, createUnboundLabel());
BreakableBlockInfo blockInfo = new BreakableBlockInfo(subroutine, entryPoint, createUnboundLabel());
// subroutineInfo.push(blockInfo);
elementToBlockInfo.put(subroutine, blockInfo);
allBlocks.push(blockInfo);
bindLabel(entryPoint);
add(new SubroutineEnterInstruction(subroutine));
}
@@ -134,29 +140,54 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override
public Label getExitPoint(@NotNull JetElement labelElement) {
BlockInfo blockInfo = elementToBlockInfo.get(labelElement);
BreakableBlockInfo blockInfo = elementToBlockInfo.get(labelElement);
assert blockInfo != null : labelElement.getText();
return blockInfo.getExitPoint();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void handleJumpInsideTryFinally(Label jumpTarget) {
List<TryFinallyBlockInfo> finallyBlocks = new ArrayList<TryFinallyBlockInfo>();
for (int i = allBlocks.size() - 1; i >= 0; i--) {
BlockInfo blockInfo = allBlocks.get(i);
if (blockInfo instanceof BreakableBlockInfo) {
BreakableBlockInfo breakableBlockInfo = (BreakableBlockInfo) blockInfo;
if (jumpTarget == breakableBlockInfo.getExitPoint() || jumpTarget == breakableBlockInfo.getEntryPoint()) {
for (int j = finallyBlocks.size() - 1; j >= 0; j--) {
finallyBlocks.get(j).generateFinallyBlock();
}
break;
}
}
else if (blockInfo instanceof TryFinallyBlockInfo) {
TryFinallyBlockInfo tryFinallyBlockInfo = (TryFinallyBlockInfo) blockInfo;
finallyBlocks.add(tryFinallyBlockInfo);
}
}
}
@Override
public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) {
bindLabel(getExitPoint(subroutine));
add(new SubroutineExitInstruction(subroutine));
elementToBlockInfo.remove(subroutine);
// subroutineInfo.pop();
allBlocks.pop();
}
@Override
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
add(new ReturnValueInstruction(returnExpression, getExitPoint(subroutine)));
Label exitPoint = getExitPoint(subroutine);
handleJumpInsideTryFinally(exitPoint);
add(new ReturnValueInstruction(returnExpression, exitPoint));
}
@Override
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
add(new ReturnNoValueInstruction(returnExpression, getExitPoint(subroutine)));
Label exitPoint = getExitPoint(subroutine);
handleJumpInsideTryFinally(exitPoint);
add(new ReturnNoValueInstruction(returnExpression, exitPoint));
}
@Override
@@ -176,16 +207,19 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override
public void jump(@NotNull Label label) {
handleJumpInsideTryFinally(label);
add(new UnconditionalJumpInstruction(label));
}
@Override
public void jumpOnFalse(@NotNull Label label) {
handleJumpInsideTryFinally(label);
add(new ConditionalJumpInstruction(false, label));
}
@Override
public void jumpOnTrue(@NotNull Label label) {
handleJumpInsideTryFinally(label);
add(new ConditionalJumpInstruction(true, label));
}
@@ -196,17 +230,19 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override
public void nondeterministicJump(Label label) {
handleJumpInsideTryFinally(label);
add(new NondeterministicJumpInstruction(label));
}
@Override
public void enterTryFinally(@NotNull JetBlockExpression expression) {
throw new UnsupportedOperationException(); // TODO
public void enterTryFinally(@NotNull GenerationTrigger generationTrigger) {
allBlocks.push(new TryFinallyBlockInfo(generationTrigger));
}
@Override
public void exitTryFinally() {
throw new UnsupportedOperationException(); // TODO
BlockInfo pop = allBlocks.pop();
assert pop instanceof TryFinallyBlockInfo;
}
@Override
@@ -215,12 +251,26 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
}
}
private static class BlockInfo {
private static abstract class BlockInfo {}
private static class TryFinallyBlockInfo extends BlockInfo {
private final GenerationTrigger finallyBlock;
private TryFinallyBlockInfo(GenerationTrigger finallyBlock) {
this.finallyBlock = finallyBlock;
}
public void generateFinallyBlock() {
finallyBlock.generate();
}
}
private static class BreakableBlockInfo extends BlockInfo {
private final JetElement element;
private final Label entryPoint;
private final Label exitPoint;
private BlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
private BreakableBlockInfo(JetElement element, Label entryPoint, Label exitPoint) {
this.element = element;
this.entryPoint = entryPoint;
this.exitPoint = exitPoint;
@@ -1238,7 +1238,9 @@ public class JetExpressionParsing extends AbstractJetParsing {
myJetParsing.parseBlock();
boolean catchOrFinally = false;
while (at(CATCH_KEYWORD)) {
catchOrFinally = true;
PsiBuilder.Marker catchBlock = mark();
advance(); // CATCH_KEYWORD
@@ -1249,6 +1251,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
}
if (at(FINALLY_KEYWORD)) {
catchOrFinally = true;
PsiBuilder.Marker finallyBlock = mark();
advance(); // FINALLY_KEYWORD
@@ -1258,6 +1261,10 @@ public class JetExpressionParsing extends AbstractJetParsing {
finallyBlock.done(FINALLY);
}
if (!catchOrFinally) {
error("Expecting 'catch' or 'finally'");
}
tryExpression.done(TRY);
}
+437
View File
@@ -0,0 +1,437 @@
== t3 ==
fun t3() {
try {
1
} finally {
2
}
}
---------------------
l0:
<START>
jmp?(l2)
r(1)
l2:
r(2)
l1:
<END>
=====================
== t3 ==
fun t3() {
try {
1
if (2 > 3) {
return
}
} finally {
2
}
}
---------------------
l0:
<START>
jmp?(l2)
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l3)
r(2)
ret l1
jmp(l4)
l3:
read (Unit)
l2:
l4:
r(2)
l1:
<END>
=====================
== anonymous_0 ==
{ () =>
if (2 > 3) {
return@
}
}
---------------------
l3:
<START>
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
ret l4
jmp(l6)
l5:
read (Unit)
l4:
l6:
<END>
=====================
== t3 ==
fun t3() {
try {
1
@{ () =>
if (2 > 3) {
return@
}
}
} finally {
2
}
}
---------------------
l0:
<START>
jmp?(l2)
r(1)
rf({ () =>
if (2 > 3) {
return@
}
})
l2:
r(2)
l1:
<END>
l3:
<START>
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
ret l4
jmp(l6)
l5:
read (Unit)
l4:
l6:
<END>
=====================
== anonymous_1 ==
{ () =>
try {
1
if (2 > 3) {
return@
}
} finally {
2
}
}
---------------------
l2:
<START>
jmp?(l4)
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
r(2)
ret l3
jmp(l6)
l5:
read (Unit)
l4:
l6:
r(2)
l3:
<END>
=====================
== t3 ==
fun t3() {
@{ () =>
try {
1
if (2 > 3) {
return@
}
} finally {
2
}
}
}
---------------------
l0:
<START>
rf({ () =>
try {
1
if (2 > 3) {
return@
}
} finally {
2
}
})
l1:
<END>
l2:
<START>
jmp?(l4)
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
r(2)
ret l3
jmp(l6)
l5:
read (Unit)
l4:
l6:
r(2)
l3:
<END>
=====================
== t3 ==
fun t3() {
@ while(true) {
try {
1
if (2 > 3) {
break @
}
} finally {
2
}
}
}
---------------------
l0:
<START>
l3:
r(true)
jf(l2)
jmp?(l4)
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
r(2)
jmp(l2)
jmp(l6)
l5:
read (Unit)
l4:
l6:
r(2)
jmp(l3)
l1:
l2:
<END>
=====================
== t3 ==
fun t3() {
try {
@ while(true) {
1
if (2 > 3) {
break @
}
}
5
} finally {
2
}
}
---------------------
l0:
<START>
jmp?(l2)
l4:
r(true)
jf(l3)
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
jmp(l3)
jmp(l6)
l5:
read (Unit)
l6:
jmp(l4)
l3:
r(5)
l2:
r(2)
l1:
<END>
=====================
== t3 ==
fun t3() {
try {
@ while(true) {
1
if (2 > 3) {
break @
}
}
} finally {
2
}
}
---------------------
l0:
<START>
jmp?(l2)
l4:
r(true)
jf(l3)
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
jmp(l3)
jmp(l6)
l5:
read (Unit)
l6:
jmp(l4)
l2:
l3:
r(2)
l1:
<END>
=====================
== t3 ==
fun t3(a : Int) {
@ for (i in 1..a) {
try {
1
if (2 > 3) {
continue @
}
} finally {
2
}
}
}
---------------------
l0:
<START>
r(1)
r(a)
r(..)
r(1..a)
jmp?(l2)
l3:
jmp?(l4)
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
r(2)
jmp(l3)
jmp(l6)
l5:
read (Unit)
l4:
l6:
r(2)
jmp?(l3)
l1:
l2:
<END>
=====================
== t3 ==
fun t3(a : Int) {
try {
@ for (i in 1..a) {
1
if (2 > 3) {
continue @
}
}
5
} finally {
2
}
}
---------------------
l0:
<START>
jmp?(l2)
r(1)
r(a)
r(..)
r(1..a)
jmp?(l3)
l4:
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
jmp(l4)
jmp(l6)
l5:
read (Unit)
l6:
jmp?(l4)
l3:
r(5)
l2:
r(2)
l1:
<END>
=====================
== t3 ==
fun t3(a : Int) {
try {
@ for (i in 1..a) {
1
if (2 > 3) {
continue @
}
}
} finally {
2
}
}
---------------------
l0:
<START>
jmp?(l2)
r(1)
r(a)
r(..)
r(1..a)
jmp?(l3)
l4:
r(1)
r(2)
r(3)
r(>)
r(2 > 3)
jf(l5)
jmp(l4)
jmp(l6)
l5:
read (Unit)
l6:
jmp?(l4)
l2:
l3:
r(2)
l1:
<END>
=====================
+125
View File
@@ -0,0 +1,125 @@
fun t3() {
try {
1
} finally {
2
}
}
fun t3() {
try {
1
if (2 > 3) {
return
}
} finally {
2
}
}
fun t3() {
try {
1
@{ () =>
if (2 > 3) {
return@
}
}
} finally {
2
}
}
fun t3() {
@{ () =>
try {
1
if (2 > 3) {
return@
}
} finally {
2
}
}
}
fun t3() {
@ while(true) {
try {
1
if (2 > 3) {
break @
}
} finally {
2
}
}
}
fun t3() {
try {
@ while(true) {
1
if (2 > 3) {
break @
}
}
5
} finally {
2
}
}
fun t3() {
try {
@ while(true) {
1
if (2 > 3) {
break @
}
}
} finally {
2
}
}
fun t3(a : Int) {
@ for (i in 1..a) {
try {
1
if (2 > 3) {
continue @
}
} finally {
2
}
}
}
fun t3(a : Int) {
try {
@ for (i in 1..a) {
1
if (2 > 3) {
continue @
}
}
5
} finally {
2
}
}
fun t3(a : Int) {
try {
@ for (i in 1..a) {
1
if (2 > 3) {
continue @
}
}
} finally {
2
}
}
@@ -68,11 +68,14 @@ public class JetControlFlowTest extends JetTestCaseBase {
try {
processCFData(name, data);
}
catch (IOException e) {
throw new RuntimeException(e);
}
finally {
if ("true".equals(System.getProperty("jet.control.flow.test.dump.graphs"))) {
dumpDot(name, data.values());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}