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) wasmPhases.invokeToplevel(phaseConfig, context, moduleFragment)
val compiledWasmModule = WasmCompiledModuleFragment() val compiledWasmModule = WasmCompiledModuleFragment(context.irBuiltIns)
val codeGenerator = WasmModuleFragmentGenerator(context, compiledWasmModule) val codeGenerator = WasmModuleFragmentGenerator(context, compiledWasmModule)
codeGenerator.generateModule(moduleFragment) codeGenerator.generateModule(moduleFragment)
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.psi2ir.intermediate.generateExpressionValue
import org.jetbrains.kotlin.wasm.ir.* import org.jetbrains.kotlin.wasm.ir.*
class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorVoid { class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorVoid {
@@ -67,6 +66,26 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
body.buildThrow(context.tagIdx) 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) { override fun visitTypeOperator(expression: IrTypeOperatorCall) {
when (expression.operator) { when (expression.operator) {
IrTypeOperator.REINTERPRET_CAST -> generateExpression(expression.argument) 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.common.push
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature 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.IrDeclarationWithName
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.symbols.* 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.ir.util.getPackageFragment
import org.jetbrains.kotlin.wasm.ir.* import org.jetbrains.kotlin.wasm.ir.*
class WasmCompiledModuleFragment { class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
val functions = val functions =
ReferencableAndDefinable<IrFunctionSymbol, WasmFunction>() ReferencableAndDefinable<IrFunctionSymbol, WasmFunction>()
val globals = val globals =
@@ -33,12 +34,20 @@ class WasmCompiledModuleFragment {
ReferencableElements<WasmSignature, Int>() ReferencableElements<WasmSignature, Int>()
val stringLiteralId = val stringLiteralId =
ReferencableElements<String, Int>() ReferencableElements<String, Int>()
val tagFuncType = WasmFunctionType("ex_handling_tag", listOf(WasmAnyRef), emptyList())
val tag = WasmTag(tagFuncType)
val runtimeTypes = val runtimeTypes =
ReferencableAndDefinable<IrClassSymbol, WasmGlobal>() 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 classes = mutableListOf<IrClassSymbol>()
val interfaces = mutableListOf<IrClassSymbol>() val interfaces = mutableListOf<IrClassSymbol>()
val virtualFunctions = mutableListOf<IrSimpleFunctionSymbol>() 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)) 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) { fun buildCatch(tagIdx: Int) {
buildInstr(WasmOp.CATCH, WasmImmediate.TagIdx(tagIdx)) buildInstr(WasmOp.CATCH, WasmImmediate.TagIdx(tagIdx))
} }