JS: fix exception handling in coroutines when initializing via resumeWithException

This commit is contained in:
Alexey Andreev
2016-11-11 17:34:46 +03:00
parent bb61fb0a91
commit 14729b0f0e
3 changed files with 10 additions and 6 deletions
@@ -52,12 +52,11 @@ class CoroutineBodyTransformer(
fun preProcess(node: JsNode) {
breakContinueTargetStatements += node.collectBreakContinueTargets()
nodesToSplit = node.collectNodesToSplit()
currentStatements += exceptionState(currentCatchBlock)
}
fun postProcess(): List<CoroutineBlock> {
currentBlock.statements += JsReturn()
val graph = entryBlock.buildGraph()
val graph = entryBlock.buildGraph(globalCatchBlock)
val orderedBlocks = DFS.topologicalOrder(listOf(entryBlock)) { graph[it].orEmpty() }
orderedBlocks.replaceCoroutineFlowStatements(context, program)
return orderedBlocks
@@ -53,13 +53,14 @@ class CoroutineFunctionTransformer(
bodyTransformer.preProcess(body)
body.statements.forEach { it.accept(bodyTransformer) }
val coroutineBlocks = bodyTransformer.postProcess()
val globalCatchBlockIndex = coroutineBlocks.indexOf(context.globalCatchBlock)
coroutineBlocks.forEach { it.jsBlock.collectAdditionalLocalVariables() }
coroutineBlocks.forEach { it.jsBlock.replaceLocalVariables(function.scope, context, localVariables) }
val additionalStatements = mutableListOf<JsStatement>()
val resumeName = generateDoResume(coroutineBlocks, context, additionalStatements, throwName)
generateContinuationConstructor(context, additionalStatements, bodyTransformer.hasFinallyBlocks)
generateContinuationConstructor(context, additionalStatements, bodyTransformer.hasFinallyBlocks, globalCatchBlockIndex)
generateContinuationMethods(resumeName, additionalStatements)
generateCoroutineInstantiation()
@@ -70,7 +71,8 @@ class CoroutineFunctionTransformer(
private fun generateContinuationConstructor(
context: CoroutineTransformationContext,
statements: MutableList<JsStatement>,
hasFinallyBlocks: Boolean
hasFinallyBlocks: Boolean,
globalCatchBlockIndex: Int
) {
val constructor = JsFunction(function.scope.parent, JsBlock(), "Continuation")
constructor.name = className
@@ -86,7 +88,7 @@ class CoroutineFunctionTransformer(
constructor.body.statements.run {
assign(context.stateFieldName, program.getNumberLiteral(0))
assign(context.exceptionStateName, program.getNumberLiteral(0))
assign(context.exceptionStateName, program.getNumberLiteral(globalCatchBlockIndex))
if (hasFinallyBlocks) {
assign(context.finallyPathFieldName, JsLiteral.NULL)
}
@@ -118,7 +118,7 @@ fun List<CoroutineBlock>.replaceCoroutineFlowStatements(context: CoroutineTransf
return forEach { blockReplacementVisitor.accept(it.jsBlock) }
}
fun CoroutineBlock.buildGraph(): Map<CoroutineBlock, Set<CoroutineBlock>> {
fun CoroutineBlock.buildGraph(globalCatchBlock: CoroutineBlock?): Map<CoroutineBlock, Set<CoroutineBlock>> {
// That's a little more than DFS due to need of tracking finally paths
val visitedBlocks = mutableSetOf<CoroutineBlock>()
@@ -139,6 +139,9 @@ fun CoroutineBlock.buildGraph(): Map<CoroutineBlock, Set<CoroutineBlock>> {
val successors = graph.getOrPut(block) { mutableSetOf() }
successors += block.collectTargetBlocks()
if (block == this && globalCatchBlock != null) {
successors += globalCatchBlock
}
successors.forEach(::visitBlock)
}