[Wasm] Add compiler flag to disable exception handling proposal

Fail with unreachable instead of throwing an exception

Merge-request: KT-MR-11481
Merged-by: Svyatoslav Kuzmich <svyatoslav.kuzmich@jetbrains.com>
This commit is contained in:
Svyatoslav Kuzmich
2023-08-07 16:19:29 +00:00
committed by Space Team
parent ec73815f80
commit 47ade4530c
17 changed files with 118 additions and 13 deletions
@@ -73,6 +73,7 @@ fun copyK2JSCompilerArguments(from: K2JSCompilerArguments, to: K2JSCompilerArgum
to.wasmGenerateWat = from.wasmGenerateWat
to.wasmKClassFqn = from.wasmKClassFqn
to.wasmTarget = from.wasmTarget
to.wasmUseTrapsInsteadOfExceptions = from.wasmUseTrapsInsteadOfExceptions
return to
}
@@ -630,6 +630,16 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
field = if (value.isNullOrEmpty()) null else value
}
@Argument(
value = "-Xwasm-use-traps-instead-of-exceptions",
description = "Trap instead of throwing exceptions"
)
var wasmUseTrapsInsteadOfExceptions = false
set(value) {
checkFrozen()
field = value
}
@Argument(
value = "-Xforce-deprecated-legacy-compiler-usage",
description = "The flag is used only for our inner infrastructure. It will be removed soon, so it's unsafe to use it nowadays."
@@ -170,6 +170,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
configuration.put(JSConfigurationKeys.WASM_ENABLE_ARRAY_RANGE_CHECKS, arguments.wasmEnableArrayRangeChecks)
configuration.put(JSConfigurationKeys.WASM_ENABLE_ASSERTS, arguments.wasmEnableAsserts)
configuration.put(JSConfigurationKeys.WASM_GENERATE_WAT, arguments.wasmGenerateWat)
configuration.put(JSConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS, arguments.wasmUseTrapsInsteadOfExceptions)
configuration.putIfNotNull(JSConfigurationKeys.WASM_TARGET, arguments.wasmTarget?.let(WasmTarget::fromName))
configuration.put(JSConfigurationKeys.OPTIMIZE_GENERATED_JS, arguments.optimizeGeneratedJs)
@@ -24,11 +24,11 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -97,7 +97,10 @@ fun compileWasm(
generateWat: Boolean = false,
generateSourceMaps: Boolean = false,
): WasmCompilerResult {
val compiledWasmModule = WasmCompiledModuleFragment(backendContext.irBuiltIns)
val compiledWasmModule = WasmCompiledModuleFragment(
backendContext.irBuiltIns,
backendContext.configuration.getBoolean(JSConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS)
)
val codeGenerator = WasmModuleFragmentGenerator(backendContext, compiledWasmModule, allowIncompleteImplementations = allowIncompleteImplementations)
allModules.forEach { codeGenerator.collectInterfaceTables(it) }
allModules.forEach { codeGenerator.generateModule(it) }
@@ -137,12 +137,22 @@ class BodyGenerator(
override fun visitThrow(expression: IrThrow) {
generateExpression(expression.value)
if (context.backendContext.configuration.getBoolean(JSConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS)) {
body.buildUnreachable(SourceLocation.NoLocation("Unreachable is inserted instead of a `throw` instruction"))
return
}
body.buildThrow(functionContext.tagIdx, expression.getSourceLocation())
}
override fun visitTry(aTry: IrTry) {
assert(aTry.isCanonical(irBuiltIns)) { "expected canonical try/catch" }
if (context.backendContext.configuration.getBoolean(JSConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS)) {
generateExpression(aTry.tryResult)
return
}
val resultType = context.transformBlockResultType(aTry.type)
body.buildTry(null, resultType)
generateExpression(aTry.tryResult)
@@ -15,7 +15,10 @@ import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.wasm.ir.*
import org.jetbrains.kotlin.wasm.ir.source.location.SourceLocation
class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
class WasmCompiledModuleFragment(
val irBuiltIns: IrBuiltIns,
generateTrapsInsteadOfExceptions: Boolean,
) {
val functions =
ReferencableAndDefinable<IrFunctionSymbol, WasmFunction>()
val globalFields =
@@ -49,7 +52,7 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
),
emptyList()
)
val tag = WasmTag(tagFuncType)
val tags = if (generateTrapsInsteadOfExceptions) emptyList() else listOf(WasmTag(tagFuncType))
val typeInfo = ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>()
@@ -238,7 +241,7 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
elements = emptyList(),
data = data,
dataCount = true,
tags = listOf(tag)
tags = tags
)
module.calculateIds()
return module
+2
View File
@@ -60,6 +60,8 @@ where advanced options include:
-Xwasm-generate-wat Generate wat file
-Xwasm-kclass-fqn Enable support for FQ names in KClass
-Xwasm-target Set up Wasm target (wasm-js or wasm-wasi)
-Xwasm-use-traps-instead-of-exceptions
Trap instead of throwing exceptions
-Xallow-any-scripts-in-source-roots
Allow to compile any scripts along with regular Kotlin sources
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
@@ -0,0 +1,46 @@
// TARGET_BACKEND: WASM
// DISABLE_WASM_EXCEPTION_HANDLING
// MODULE: main
// FILE: foo.kt
@JsExport
fun sumNumbers(x: Int): Int =
(0..x).toList().sum()
@JsExport
fun add(x: Int, y: Int): Int =
x + y
@JsExport
fun throws() {
try {
error("Test Error")
} catch (e: Throwable) {
// This code normally catches the error,
// but with exception handling disabled it should fail with trap
}
}
// FILE: entry.mjs
import wasmExports from "./index.mjs";
if (wasmExports.add(10, 20) !== 30) {
throw "Fail add";
}
if (wasmExports.sumNumbers(10) !== 55) {
throw "Fail sumNumbers";
}
var thrown = false;
try {
wasmExports.throws();
} catch(e) {
thrown = true;
}
if (!thrown) {
throw "Fail exception was not thrown";
}
@@ -13,6 +13,10 @@ object WasmEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
description = "Run kotlin.test unit tests (function marked with @Test)",
)
val DISABLE_WASM_EXCEPTION_HANDLING by directive(
description = "Generate wasm without EH proposal and test in runtime with EH turned off",
)
// Next directives are used only inside test system and must not be present in test file
val PATH_TO_TEST_DIR by stringDirective(
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.PROPERTY_LAZY_INITIALIZATION
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.SOURCE_MAP_EMBED_SOURCES
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.DISABLE_WASM_EXCEPTION_HANDLING
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
@@ -155,5 +156,7 @@ class WasmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfi
configuration.put(JSConfigurationKeys.SOURCE_MAP_EMBED_SOURCES, sourceMapSourceEmbedding)
configuration.put(CommonConfigurationKeys.EXPECT_ACTUAL_LINKER, EXPECT_ACTUAL_LINKER in registeredDirectives)
configuration.put(JSConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS, DISABLE_WASM_EXCEPTION_HANDLING in registeredDirectives)
}
}