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