WASM: Canonicalize catches without finally blocks

This commit is contained in:
Igor Laevsky
2021-08-20 14:37:36 +03:00
committed by TeamCityServer
parent 02aed80e18
commit d99473fe4d
7 changed files with 115 additions and 6 deletions
@@ -298,6 +298,13 @@ private val returnableBlockLoweringPhase = makeWasmModulePhase(
prerequisite = setOf(functionInliningPhase)
)
private val tryCatchCanonicalization = makeWasmModulePhase(
::TryCatchCanonicalization,
name = "TryCatchCanonicalization",
description = "Transforms try/catch statements into canonical form supported by the wasm codegen",
prerequisite = setOf(functionInliningPhase)
)
private val bridgesConstructionPhase = makeWasmModulePhase(
::WasmBridgesConstruction,
name = "BridgesConstruction",
@@ -461,6 +468,7 @@ val wasmPhases = NamedCompilerPhase(
stringConstructorLowering then
returnableBlockLoweringPhase then
tryCatchCanonicalization then
forLoopsLoweringPhase then
propertyAccessorInlinerLoweringPhase then
@@ -0,0 +1,104 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.wasm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.backend.wasm.utils.isCanonical
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.buildVariable
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTry
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
// This pass transforms try/catch statements into a simple canonical form which is easily mapped into wasm instruction set.
// From this:
// try {
// ...exprs
// } catch (e: Foo) {
// ...exprs
// } catch (e: Bar) {
// ...exprs
// } finally {
// ...exprs
// }
// We get this:
// try {
// ...exprs
// } catch (e: Throwable) {
// when (e) {
// is Foo -> ...exprs
// is Bar -> ...exprs
// }
// }
// TODO: Describe finally transformation
internal class TryCatchCanonicalization(private val ctx: WasmBackendContext) : FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(CatchMerger(ctx))
irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitTry(aTry: IrTry) {
check(aTry.isCanonical(ctx.irBuiltIns)) { "Found non canonical try/catch $aTry" }
}
})
}
}
internal class CatchMerger(private val ctx: WasmBackendContext): IrElementTransformerVoidWithContext() {
override fun visitTry(aTry: IrTry): IrExpression {
// First, handle all nested constructs
aTry.transformChildrenVoid(this)
// Nothing to do
if (aTry.catches.isEmpty() ||
aTry.catches.singleOrNull()?.catchParameter?.symbol?.owner?.type == ctx.irBuiltIns.throwableType)
return aTry
ctx.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
val newCatchParameter = buildVariable(
currentScope!!.scope.getLocalDeclarationParent(),
startOffset,
endOffset,
IrDeclarationOrigin.CATCH_PARAMETER,
Name.identifier("merged_catch_param"),
ctx.irBuiltIns.throwableType
)
val newCatchBody = irBlock(aTry) {
+irWhen(
aTry.type,
aTry.catches.map {
irBranch(
irIs(irGet(newCatchParameter), it.catchParameter.type),
irBlock(it.result) {
it.catchParameter.initializer = irImplicitCast(irGet(newCatchParameter), it.catchParameter.type)
it.catchParameter.origin = IrDeclarationOrigin.DEFINED
+it.catchParameter
+it.result
}
)
} + irElseBranch(irThrow(irGet(newCatchParameter)))
)
}
val newCatch = irCatch(newCatchParameter, newCatchBody)
return irTry(aTry.type, aTry.tryResult, listOf(newCatch), aTry.finallyExpression)
}
}
}
@@ -336,6 +336,9 @@ fun IrBuilderWithScope.irVararg(elementType: IrType, values: List<IrExpression>)
fun IrBuilderWithScope.irRawFunctionReferefence(type: IrType, symbol: IrFunctionSymbol) =
IrRawFunctionReferenceImpl(startOffset, endOffset, type, symbol)
fun IrBuilderWithScope.irTry(type: IrType, tryResult: IrExpression, catches: List<IrCatch>, finallyExpression: IrExpression?) =
IrTryImpl(startOffset, endOffset, type, tryResult, catches, finallyExpression)
inline fun IrBuilderWithScope.irBlock(
startOffset: Int = this.startOffset,
endOffset: Int = this.endOffset,
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: WASM
fun foo() {}
inline fun test1(v: Int) {
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JS
// IGNORE_BACKEND: WASM
var l = ""
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JS
// IGNORE_BACKEND: WASM
var l = ""
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: EXCEPTIONS_NOT_IMPLEMENTED
// WITH_RUNTIME
// KT-44496