FIR CFG: add more uncaught exception paths

This commit is contained in:
Jinseong Jeon
2020-11-06 07:11:31 -08:00
committed by teamcityserver
parent 7b06885348
commit 440cf78884
8 changed files with 34 additions and 16 deletions
@@ -159,7 +159,8 @@ digraph complex_kt {
28 -> {29}; 28 -> {29};
29 -> {30}; 29 -> {30};
30 -> {38 31}; 30 -> {38 31};
31 -> {54 32}; 31 -> {32};
31 -> {54} [label=onUncaughtException];
32 -> {33}; 32 -> {33};
33 -> {34}; 33 -> {34};
34 -> {35}; 34 -> {35};
@@ -177,7 +177,8 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
44 -> {45}; 44 -> {45};
45 -> {46}; 45 -> {46};
46 -> {52 47}; 46 -> {52 47};
47 -> {56 48}; 47 -> {48};
47 -> {56} [label=onUncaughtException];
48 -> {49}; 48 -> {49};
49 -> {50}; 49 -> {50};
50 -> {51}; 50 -> {51};
@@ -315,7 +315,8 @@ digraph propertiesAndInitBlocks_kt {
88 -> {89}; 88 -> {89};
89 -> {90}; 89 -> {90};
90 -> {96 91}; 90 -> {96 91};
91 -> {102 92}; 91 -> {92};
91 -> {96} [label=onUncaughtException];
92 -> {93}; 92 -> {93};
93 -> {94}; 93 -> {94};
94 -> {95}; 94 -> {95};
@@ -63,13 +63,15 @@ digraph tryCatch_kt {
6 -> {7}; 6 -> {7};
7 -> {8}; 7 -> {8};
8 -> {21 15 9}; 8 -> {21 15 9};
9 -> {23 10}; 9 -> {10};
9 -> {23} [label=onUncaughtException];
10 -> {11}; 10 -> {11};
11 -> {12}; 11 -> {12};
12 -> {13}; 12 -> {13};
13 -> {14}; 13 -> {14};
14 -> {21}; 14 -> {21};
15 -> {23 16}; 15 -> {16};
15 -> {23} [label=onUncaughtException];
16 -> {17}; 16 -> {17};
17 -> {18}; 17 -> {18};
18 -> {19}; 18 -> {19};
@@ -124,7 +126,8 @@ digraph tryCatch_kt {
29 -> {30}; 29 -> {30};
30 -> {31}; 30 -> {31};
31 -> {37 32}; 31 -> {37 32};
32 -> {40 33}; 32 -> {33};
32 -> {40} [label=onUncaughtException];
33 -> {34}; 33 -> {34};
34 -> {35}; 34 -> {35};
35 -> {36}; 35 -> {36};
@@ -295,7 +298,8 @@ digraph tryCatch_kt {
78 -> {79}; 78 -> {79};
79 -> {80}; 79 -> {80};
80 -> {97 91 81}; 80 -> {97 91 81};
81 -> {102 82}; 81 -> {82};
81 -> {102} [label=onUncaughtException];
82 -> {83}; 82 -> {83};
83 -> {87}; 83 -> {87};
83 -> {84} [style=dotted]; 83 -> {84} [style=dotted];
@@ -306,7 +310,8 @@ digraph tryCatch_kt {
88 -> {89}; 88 -> {89};
89 -> {90}; 89 -> {90};
90 -> {102}; 90 -> {102};
91 -> {102 92}; 91 -> {92};
91 -> {102} [label=onUncaughtException];
92 -> {93}; 92 -> {93};
93 -> {94} [style=dotted]; 93 -> {94} [style=dotted];
93 -> {43} [color=green style=dashed]; 93 -> {43} [color=green style=dashed];
@@ -541,6 +541,7 @@ class ControlFlowGraphBuilder {
fun exitJump(jump: FirJump<*>): JumpNode { fun exitJump(jump: FirJump<*>): JumpNode {
val node = createJumpNode(jump) val node = createJumpNode(jump)
// TODO: if within `try` with `finally`, don't go to the target directly.
val nextNode = when (jump) { val nextNode = when (jump) {
is FirReturnExpression -> exitTargetsForReturn[jump.target.labeledElement.symbol] is FirReturnExpression -> exitTargetsForReturn[jump.target.labeledElement.symbol]
is FirContinueExpression -> loopEnterNodes[jump.target.labeledElement] is FirContinueExpression -> loopEnterNodes[jump.target.labeledElement]
@@ -793,8 +794,6 @@ class ControlFlowGraphBuilder {
catchNodeStorage.push(catchNode) catchNodeStorage.push(catchNode)
// a flow where an exception of interest is thrown and caught before executing any of try-main block. // a flow where an exception of interest is thrown and caught before executing any of try-main block.
addEdge(enterTryExpressionNode, catchNode) addEdge(enterTryExpressionNode, catchNode)
// TODO: Should go to the finally block w/ a label, and exit to the exit target w/ the same label.
addEdge(catchNode, exitTargetsForTry.top())
} }
levelCounter++ levelCounter++
@@ -816,6 +815,7 @@ class ControlFlowGraphBuilder {
val finallyEnterNode = finallyEnterNodes.topOrNull() val finallyEnterNode = finallyEnterNodes.topOrNull()
// NB: Check the level to avoid adding an edge to the finally block at an upper level. // NB: Check the level to avoid adding an edge to the finally block at an upper level.
if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) { if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) {
// TODO: in case of return/throw in try main block, we need a unique label.
addEdge(node, finallyEnterNode) addEdge(node, finallyEnterNode)
} else { } else {
addEdge(node, tryExitNodes.top()) addEdge(node, tryExitNodes.top())
@@ -828,6 +828,14 @@ class ControlFlowGraphBuilder {
val tryMainExitNode = tryMainExitNodes.top() val tryMainExitNode = tryMainExitNodes.top()
// a flow where an exception of interest is thrown and caught after executing all of try-main block. // a flow where an exception of interest is thrown and caught after executing all of try-main block.
addEdge(tryMainExitNode, it) addEdge(tryMainExitNode, it)
val finallyEnterNode = finallyEnterNodes.topOrNull()
// a flow where an uncaught exception is thrown before executing any of catch clause.
// NB: Check the level to avoid adding an edge to the finally block at an upper level.
if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) {
addEdge(it, finallyEnterNode, label = UncaughtExceptionPath)
} else {
addEdge(it, exitTargetsForTry.top(), label = UncaughtExceptionPath)
}
lastNodes.push(it) lastNodes.push(it)
levelCounter++ levelCounter++
} }
@@ -840,6 +848,7 @@ class ControlFlowGraphBuilder {
val finallyEnterNode = finallyEnterNodes.topOrNull() val finallyEnterNode = finallyEnterNodes.topOrNull()
// NB: Check the level to avoid adding an edge to the finally block at an upper level. // NB: Check the level to avoid adding an edge to the finally block at an upper level.
if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) { if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) {
// TODO: in case of return/rethrow in catch clause, we need a unique label.
addEdge(it, finallyEnterNode, propagateDeadness = false) addEdge(it, finallyEnterNode, propagateDeadness = false)
} else { } else {
addEdge(it, tryExitNodes.top(), propagateDeadness = false) addEdge(it, tryExitNodes.top(), propagateDeadness = false)
@@ -861,6 +870,7 @@ class ControlFlowGraphBuilder {
addEdge(it, tryExitNode) addEdge(it, tryExitNode)
// a flow that exits to the exit target while there was an uncaught exception. // a flow that exits to the exit target while there was an uncaught exception.
addEdge(it, exitTargetsForTry.top(), label = UncaughtExceptionPath) addEdge(it, exitTargetsForTry.top(), label = UncaughtExceptionPath)
// TODO: differentiate flows that return/(re)throw in try main block or catch clauses.
} }
} }
@@ -1255,4 +1265,4 @@ class ControlFlowGraphBuilder {
} }
fun FirDeclaration?.isLocalClassOrAnonymousObject() = ((this as? FirRegularClass)?.isLocal == true) || this is FirAnonymousObject fun FirDeclaration?.isLocalClassOrAnonymousObject() = ((this as? FirRegularClass)?.isLocal == true) || this is FirAnonymousObject
@@ -62,7 +62,7 @@ fun innerFinallyInitializes() {
} }
// Properly initialized // Properly initialized
<!UNINITIALIZED_VARIABLE!>x<!>.inc() x.inc()
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
log() log()
} }
@@ -87,12 +87,12 @@ fun innerFinallyInitializesOuterRethrows() {
} }
// Properly initialized // Properly initialized
<!UNINITIALIZED_VARIABLE!>x<!>.inc() x.inc()
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
log() log()
throw e throw e
} }
// Guaranteed to be initialized because all catch-clauses are rethrowing // Guaranteed to be initialized because all catch-clauses are rethrowing
<!UNINITIALIZED_VARIABLE!>x<!>.inc() x.inc()
} }
@@ -43,5 +43,5 @@ fun innerTryCatchInitializes() {
x = 42 x = 42
} }
// Here x=I because outer try-catch either exited normally (x=I) or catched exception (x=I, with reassingment, though) // Here x=I because outer try-catch either exited normally (x=I) or catched exception (x=I, with reassingment, though)
<!UNINITIALIZED_VARIABLE!>x<!>.inc() x.inc()
} }
@@ -30,5 +30,5 @@ fun innerTryCatchFinally() {
} }
} }
<!UNINITIALIZED_VARIABLE!>x<!>.inc() x.inc()
} }