JS: fix exception handling in coroutines when initializing via resumeWithException
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user