From 429991532659891f173a21113f688afb6049b450 Mon Sep 17 00:00:00 2001 From: Igor Laevsky Date: Thu, 2 Sep 2021 18:55:11 +0300 Subject: [PATCH] WASM: Implement finally blocks for try/catch'es --- .../common/lower/FinallyBlocksLowering.kt | 4 +-- .../kotlin/backend/wasm/WasmLoweringPhases.kt | 16 +++++----- .../backend/wasm/ir2wasm/BodyGenerator.kt | 1 - .../wasm/lower/TryCatchCanonicalization.kt | 30 +++++++++++++++++-- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt index b2f7bb156b6..8a1943bcc7e 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt @@ -217,7 +217,7 @@ class FinallyBlocksLowering(val context: CommonBackendContext, private val throw val syntheticTry = IrTryImpl( startOffset = startOffset, endOffset = endOffset, - type = context.irBuiltIns.unitType + type = context.irBuiltIns.nothingType ).apply { this.catches += irCatch( catchParameter, @@ -241,7 +241,7 @@ class FinallyBlocksLowering(val context: CommonBackendContext, private val throw val transformedTry = IrTryImpl( startOffset = startOffset, endOffset = endOffset, - type = context.irBuiltIns.unitType + type = context.irBuiltIns.nothingType ) transformedTry.tryResult = returnedResult for (aCatch in aTry.catches) { diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 1576bde81bd..12e8d5d73bd 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -291,13 +291,6 @@ private val excludeDeclarationsFromCodegenPhase = makeCustomWasmModulePhase( description = "Move excluded declarations to separate place" ) -private val returnableBlockLoweringPhase = makeWasmModulePhase( - ::ReturnableBlockLowering, - name = "ReturnableBlockLowering", - description = "Replace returnable block with do-while loop", - prerequisite = setOf(functionInliningPhase) -) - private val tryCatchCanonicalization = makeWasmModulePhase( ::TryCatchCanonicalization, name = "TryCatchCanonicalization", @@ -305,6 +298,13 @@ private val tryCatchCanonicalization = makeWasmModulePhase( prerequisite = setOf(functionInliningPhase) ) +private val returnableBlockLoweringPhase = makeWasmModulePhase( + ::ReturnableBlockLowering, + name = "ReturnableBlockLowering", + description = "Replace returnable block with do-while loop", + prerequisite = setOf(functionInliningPhase) +) + private val bridgesConstructionPhase = makeWasmModulePhase( ::WasmBridgesConstruction, name = "BridgesConstruction", @@ -467,8 +467,8 @@ val wasmPhases = NamedCompilerPhase( // suspendFunctionsLoweringPhase then stringConstructorLowering then - returnableBlockLoweringPhase then tryCatchCanonicalization then + returnableBlockLoweringPhase then forLoopsLoweringPhase then propertyAccessorInlinerLoweringPhase then diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt index cfbc08805b4..3324195ecbe 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt @@ -68,7 +68,6 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV override fun visitTry(aTry: IrTry) { assert(aTry.isCanonical(irBuiltIns)) { "expected canonical try/catch" } - assert(aTry.type != irBuiltIns.nothingType) { "shouldn't happen" } val resultType = context.transformBlockResultType(aTry.type) body.buildTry(null, resultType) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/TryCatchCanonicalization.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/TryCatchCanonicalization.kt index 9ce7d7ebcd9..45cfcccada6 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/TryCatchCanonicalization.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/TryCatchCanonicalization.kt @@ -40,12 +40,38 @@ import org.jetbrains.kotlin.name.Name // is Bar -> ...exprs // } // } -// TODO: Describe finally transformation +// With finally we transform this: +// try { +// ...exprs +// } catch (e: Throwable) { +// ...exprs +// } finally { +// ... +// } +// Into something like this (tmp variable is used only if we return some result): +// val tmp = block { // this is where we return if we return from original try/catch with the result +// try { +// try { +// return@block ...exprs +// } catch (e: Throwable) { +// return@block ...exprs +// } +// } +// catch (e: Throwable) { +// ... +// throw e // rethrow exception if it happened inside of the catch statement +// } +// } +// ... +// tmp // result + internal class TryCatchCanonicalization(private val ctx: WasmBackendContext) : FileLoweringPass { override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(CatchMerger(ctx)) + irFile.transformChildrenVoid(FinallyBlocksLowering(ctx, ctx.irBuiltIns.throwableType)) + irFile.acceptVoid(object : IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) @@ -58,7 +84,7 @@ internal class TryCatchCanonicalization(private val ctx: WasmBackendContext) : F } } -internal class CatchMerger(private val ctx: WasmBackendContext): IrElementTransformerVoidWithContext() { +internal class CatchMerger(private val ctx: WasmBackendContext) : IrElementTransformerVoidWithContext() { override fun visitTry(aTry: IrTry): IrExpression { // First, handle all nested constructs aTry.transformChildrenVoid(this)