diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt index 262a040d716..2eae331fc1d 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt @@ -64,7 +64,7 @@ fun compileWasm( wasmPhases.invokeToplevel(phaseConfig, context, moduleFragment) - val compiledWasmModule = WasmCompiledModuleFragment() + val compiledWasmModule = WasmCompiledModuleFragment(context.irBuiltIns) val codeGenerator = WasmModuleFragmentGenerator(context, compiledWasmModule) codeGenerator.generateModule(moduleFragment) 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 b61cade09a7..cfbc08805b4 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 @@ -23,7 +23,6 @@ import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid -import org.jetbrains.kotlin.psi2ir.intermediate.generateExpressionValue import org.jetbrains.kotlin.wasm.ir.* class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorVoid { @@ -67,6 +66,26 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV body.buildThrow(context.tagIdx) } + 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) + generateExpression(aTry.tryResult) + + body.buildCatch(context.tagIdx) + + // Exception object is on top of the stack, store it into the local + aTry.catches.single().catchParameter.symbol.let { + context.defineLocal(it) + body.buildSetLocal(context.referenceLocal(it)) + } + generateExpression(aTry.catches.single().result) + + body.buildEnd() + } + override fun visitTypeOperator(expression: IrTypeOperatorCall) { when (expression.operator) { IrTypeOperator.REINTERPRET_CAST -> generateExpression(expression.argument) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt index 19023fbb92f..6f858e56d6a 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment import org.jetbrains.kotlin.ir.symbols.* @@ -14,7 +15,7 @@ import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.getPackageFragment import org.jetbrains.kotlin.wasm.ir.* -class WasmCompiledModuleFragment { +class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) { val functions = ReferencableAndDefinable() val globals = @@ -33,12 +34,20 @@ class WasmCompiledModuleFragment { ReferencableElements() val stringLiteralId = ReferencableElements() - val tagFuncType = WasmFunctionType("ex_handling_tag", listOf(WasmAnyRef), emptyList()) - val tag = WasmTag(tagFuncType) val runtimeTypes = ReferencableAndDefinable() + val tagFuncType = WasmFunctionType( + "ex_handling_tag", + listOf( + WasmRefNullType(WasmHeapType.Type(gcTypes.reference(irBuiltIns.throwableClass))) + ), + emptyList() + ) + val tag = WasmTag(tagFuncType) + + val classes = mutableListOf() val interfaces = mutableListOf() val virtualFunctions = mutableListOf() diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Utils.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Utils.kt new file mode 100644 index 00000000000..501e9bc3363 --- /dev/null +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Utils.kt @@ -0,0 +1,21 @@ +/* + * 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.utils + +import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrTry + +// Backed codegen can only handle try/catch in canonical form. +// Canonical form for the try/catch: +// try { +// ...exprs +// } catch (e: Throwable) { +// ...exprs +// } +// no-finally +fun IrTry.isCanonical(builtIns: IrBuiltIns) = + catches.singleOrNull()?.catchParameter?.symbol?.owner?.type == builtIns.throwableType && + finallyExpression == null \ No newline at end of file diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt index e9d15ac11d1..4138b387c4b 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt @@ -76,6 +76,12 @@ abstract class WasmExpressionBuilder { buildInstr(WasmOp.THROW, WasmImmediate.TagIdx(tagIdx)) } + @Suppress("UNUSED_PARAMETER") + fun buildTry(label: String?, resultType: WasmType? = null) { + numberOfNestedBlocks++ + buildInstr(WasmOp.TRY, WasmImmediate.BlockType.Value(resultType)) + } + fun buildCatch(tagIdx: Int) { buildInstr(WasmOp.CATCH, WasmImmediate.TagIdx(tagIdx)) }