[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:
committed by
Space Team
parent
ec73815f80
commit
47ade4530c
+1
@@ -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
|
||||
}
|
||||
|
||||
+10
@@ -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)
|
||||
|
||||
+1
-1
@@ -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) }
|
||||
|
||||
+10
@@ -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)
|
||||
|
||||
+6
-3
@@ -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
@@ -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";
|
||||
}
|
||||
+4
@@ -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(
|
||||
|
||||
+3
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,9 @@ public class JSConfigurationKeys {
|
||||
public static final CompilerConfigurationKey<WasmTarget> WASM_TARGET =
|
||||
CompilerConfigurationKey.create("wasm target");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS =
|
||||
CompilerConfigurationKey.create("use wasm traps instead of throwing exceptions");
|
||||
|
||||
public static final CompilerConfigurationKey<ZipFileSystemAccessor> ZIP_FILE_SYSTEM_ACCESSOR =
|
||||
CompilerConfigurationKey.create("zip file system accessor, used for klib reading");
|
||||
|
||||
|
||||
@@ -123,9 +123,11 @@ class WasmIrToBinary(
|
||||
}
|
||||
|
||||
// tag section
|
||||
appendSection(WasmBinary.Section.TAG) {
|
||||
appendVectorSize(tags.size)
|
||||
tags.forEach { appendTag(it) }
|
||||
if (tags.isNotEmpty()) {
|
||||
appendSection(WasmBinary.Section.TAG) {
|
||||
appendVectorSize(tags.size)
|
||||
tags.forEach { appendTag(it) }
|
||||
}
|
||||
}
|
||||
|
||||
appendSection(WasmBinary.Section.GLOBAL) {
|
||||
@@ -607,7 +609,7 @@ abstract class ByteWriter {
|
||||
fun writeUByte(v: UByte) {
|
||||
writeByte(v.toByte())
|
||||
}
|
||||
|
||||
|
||||
fun writeUInt32(v: UInt) {
|
||||
writeByte(v.toByte())
|
||||
writeByte((v shr 8).toByte())
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.js.JavaScript
|
||||
import org.jetbrains.kotlin.test.DebugMode
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.DISABLE_WASM_EXCEPTION_HANDLING
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.RUN_UNIT_TESTS
|
||||
import org.jetbrains.kotlin.test.model.TestFile
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
@@ -191,6 +192,8 @@ class WasmBoxRunner(
|
||||
val testFileText = originalFile.readText()
|
||||
val failsIn: List<String> = InTextDirectivesUtils.findListWithPrefixes(testFileText, "// WASM_FAILS_IN: ")
|
||||
|
||||
val disableExceptions = DISABLE_WASM_EXCEPTION_HANDLING in testServices.moduleStructure.allDirectives
|
||||
|
||||
val exceptions = listOf(WasmVM.V8, WasmVM.SpiderMonkey).mapNotNull map@{ vm ->
|
||||
try {
|
||||
if (debugMode >= DebugMode.DEBUG) {
|
||||
@@ -199,7 +202,8 @@ class WasmBoxRunner(
|
||||
vm.run(
|
||||
"./${entryMjs}",
|
||||
jsFilePaths,
|
||||
workingDirectory = dir
|
||||
workingDirectory = dir,
|
||||
disableExceptionHandlingIfPossible = disableExceptions
|
||||
)
|
||||
if (vm.shortName in failsIn) {
|
||||
return@map AssertionError("The test expected to fail in ${vm.name}. Please update the testdata.")
|
||||
|
||||
@@ -17,10 +17,10 @@ internal sealed class WasmVM(val shortName: String) {
|
||||
val name: String = javaClass.simpleName
|
||||
protected val tool = ExternalTool(System.getProperty("javascript.engine.path.$name"))
|
||||
|
||||
abstract fun run(entryMjs: String, jsFiles: List<String>, workingDirectory: File?)
|
||||
abstract fun run(entryMjs: String, jsFiles: List<String>, workingDirectory: File?, disableExceptionHandlingIfPossible: Boolean = false)
|
||||
|
||||
object V8 : WasmVM("V8") {
|
||||
override fun run(entryMjs: String, jsFiles: List<String>, workingDirectory: File?) {
|
||||
override fun run(entryMjs: String, jsFiles: List<String>, workingDirectory: File?, disableExceptionHandlingIfPossible: Boolean) {
|
||||
tool.run(
|
||||
"--experimental-wasm-gc",
|
||||
"--wasm-final-types",
|
||||
@@ -34,10 +34,11 @@ internal sealed class WasmVM(val shortName: String) {
|
||||
}
|
||||
|
||||
object SpiderMonkey : WasmVM("SM") {
|
||||
override fun run(entryMjs: String, jsFiles: List<String>, workingDirectory: File?) {
|
||||
override fun run(entryMjs: String, jsFiles: List<String>, workingDirectory: File?, disableExceptionHandlingIfPossible: Boolean) {
|
||||
tool.run(
|
||||
"--wasm-verbose",
|
||||
"--wasm-gc",
|
||||
*if (disableExceptionHandlingIfPossible) arrayOf("--no-wasm-exceptions") else emptyArray(),
|
||||
"--wasm-function-references",
|
||||
*jsFiles.flatMap { listOf("-f", it) }.toTypedArray(),
|
||||
"--module=$entryMjs",
|
||||
|
||||
+6
@@ -139,6 +139,12 @@ public class FirWasmCodegenWasmJsInteropTestGenerated extends AbstractFirWasmCod
|
||||
runTest("compiler/testData/codegen/boxWasmJsInterop/nameClash.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noExceptions.kt")
|
||||
public void testNoExceptions() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxWasmJsInterop/noExceptions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableExternRefs.kt")
|
||||
public void testNullableExternRefs() throws Exception {
|
||||
|
||||
+6
@@ -139,6 +139,12 @@ public class K1WasmCodegenWasmJsInteropTestGenerated extends AbstractK1WasmCodeg
|
||||
runTest("compiler/testData/codegen/boxWasmJsInterop/nameClash.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noExceptions.kt")
|
||||
public void testNoExceptions() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxWasmJsInterop/noExceptions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nullableExternRefs.kt")
|
||||
public void testNullableExternRefs() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user