WASM: Implement simple try/catch codegen

This commit is contained in:
Igor Laevsky
2021-08-18 15:57:07 +03:00
committed by TeamCityServer
parent 6ca965af6f
commit 02aed80e18
5 changed files with 60 additions and 5 deletions
@@ -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)
@@ -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)
@@ -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<IrFunctionSymbol, WasmFunction>()
val globals =
@@ -33,12 +34,20 @@ class WasmCompiledModuleFragment {
ReferencableElements<WasmSignature, Int>()
val stringLiteralId =
ReferencableElements<String, Int>()
val tagFuncType = WasmFunctionType("ex_handling_tag", listOf(WasmAnyRef), emptyList())
val tag = WasmTag(tagFuncType)
val runtimeTypes =
ReferencableAndDefinable<IrClassSymbol, WasmGlobal>()
val tagFuncType = WasmFunctionType(
"ex_handling_tag",
listOf(
WasmRefNullType(WasmHeapType.Type(gcTypes.reference(irBuiltIns.throwableClass)))
),
emptyList()
)
val tag = WasmTag(tagFuncType)
val classes = mutableListOf<IrClassSymbol>()
val interfaces = mutableListOf<IrClassSymbol>()
val virtualFunctions = mutableListOf<IrSimpleFunctionSymbol>()
@@ -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
@@ -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))
}