[Wasm] Move non-recursive function types out of rec group

This fixes linking with other wasm modules with non-rec types
This commit is contained in:
Svyatoslav Kuzmich
2022-12-21 17:16:32 +01:00
committed by teamcity
parent 88f1f74aec
commit d788adcbb5
9 changed files with 83 additions and 29 deletions
@@ -192,21 +192,29 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
}
}
val typeDeclarations = mutableListOf<WasmTypeDeclaration>()
typeDeclarations.addAll(vTableGcTypes.elements)
typeDeclarations.addAll(gcTypes.elements)
typeDeclarations.addAll(classITableGcType.elements.distinct())
typeDeclarations.sortBy(::wasmTypeDeclarationOrderKey)
val recGroupTypes = mutableListOf<WasmTypeDeclaration>()
recGroupTypes.addAll(vTableGcTypes.elements)
recGroupTypes.addAll(this.gcTypes.elements)
recGroupTypes.addAll(classITableGcType.elements.distinct())
recGroupTypes.sortBy(::wasmTypeDeclarationOrderKey)
val globals = mutableListOf<WasmGlobal>()
globals.addAll(globalFields.elements)
globals.addAll(globalVTables.elements)
globals.addAll(globalClassITables.elements.distinct())
val allFunctionTypes = canonicalFunctionTypes.values.toList() + tagFuncType + masterInitFunctionType
// Partition out function types that can't be recursive,
// we don't need to put them into a rec group
// so that they can be matched with function types from other Wasm modules.
val (potentiallyRecursiveFunctionTypes, nonRecursiveFunctionTypes) =
allFunctionTypes.partition { it.referencesTypeDeclarations() }
recGroupTypes.addAll(potentiallyRecursiveFunctionTypes)
val module = WasmModule(
functionTypes = canonicalFunctionTypes.values.toList() + tagFuncType + masterInitFunctionType,
gcTypes = typeDeclarations,
gcTypesInRecursiveGroup = true,
functionTypes = nonRecursiveFunctionTypes,
recGroupTypes = recGroupTypes,
importsInOrder = importedFunctions,
importedFunctions = importedFunctions,
definedFunctions = functions.elements.filterIsInstance<WasmFunction.Defined>() + masterInitFunction,
@@ -0,0 +1,30 @@
// TARGET_BACKEND: WASM
/*
Here we pass export of another Wasm module to our import directly without JS layer.
This enables strict type check without JS conversons.
For instance, recursion groups of function types must fully match.
(module
(func (export "addTwo") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))
*/
@JsFun("""
(() => {
let bytes = [0, 97, 115, 109, 1, 0, 0, 0, 1, 7, 1, 96, 2, 127, 127, 1, 127, 3,
2, 1, 0, 7, 10, 1, 6, 97, 100, 100, 84, 119, 111, 0, 0, 10, 9, 1,
7, 0, 32, 0, 32, 1, 106, 11, 0, 10, 4, 110, 97, 109, 101, 2, 3, 1, 0, 0];
let buffer = (new Int8Array(bytes)).buffer;
let module = new WebAssembly.Module(buffer);
let instance = new WebAssembly.Instance(module);
return instance.exports.addTwo;
})()
""")
external fun addTwo(a: Int, b: Int): Int
fun box(): String {
if (addTwo(100, 200) != 300) return "Fail1"
return "OK"
}
@@ -30,6 +30,11 @@ public class IrCodegenWasmJsInteropWasmTestGenerated extends AbstractIrCodegenWa
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxWasmJsInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.WASM, true);
}
@TestMetadata("callingWasmDirectly.kt")
public void testCallingWasmDirectly() throws Exception {
runTest("compiler/testData/codegen/boxWasmJsInterop/callingWasmDirectly.kt");
}
@TestMetadata("defaultValues.kt")
public void testDefaultValues() throws Exception {
runTest("compiler/testData/codegen/boxWasmJsInterop/defaultValues.kt");
@@ -10,9 +10,7 @@ import org.jetbrains.kotlin.wasm.ir.source.location.SourceLocation
class WasmModule(
val functionTypes: List<WasmFunctionType> = emptyList(),
val gcTypes: List<WasmTypeDeclaration> = emptyList(),
val gcTypesInRecursiveGroup: Boolean,
val recGroupTypes: List<WasmTypeDeclaration> = emptyList(),
val importsInOrder: List<WasmNamedModuleField> = emptyList(),
val importedFunctions: List<WasmFunction.Imported> = emptyList(),
val importedMemories: List<WasmMemory> = emptyList(),
@@ -77,3 +77,15 @@ fun WasmType.getHeapType(): WasmHeapType =
is WasmExternRef -> WasmHeapType.Simple.Extern
else -> error("Unknown heap type for type $this")
}
fun WasmFunctionType.referencesTypeDeclarations(): Boolean =
parameterTypes.any { it.referencesTypeDeclaration() } or resultTypes.any { it.referencesTypeDeclaration() }
fun WasmType.referencesTypeDeclaration(): Boolean {
val heapType = when (this) {
is WasmRefNullType -> getHeapType()
is WasmRefType -> getHeapType()
else -> return false
}
return heapType is WasmHeapType.Type
}
@@ -16,7 +16,7 @@ fun WasmModule.calculateIds() {
}
functionTypes.calculateIds()
gcTypes.calculateIds(startIndex = functionTypes.size)
recGroupTypes.calculateIds(startIndex = functionTypes.size)
importedFunctions.calculateIds()
importedMemories.calculateIds()
importedTables.calculateIds()
@@ -329,8 +329,7 @@ class WasmBinaryToIR(val b: MyByteReader) {
return WasmModule(
functionTypes = functionTypes,
gcTypes = gcTypes,
gcTypesInRecursiveGroup = false,
recGroupTypes = gcTypes,
importsInOrder = importsInOrder,
importedFunctions = importedFunctions,
importedMemories = importedMemories,
@@ -35,17 +35,18 @@ class WasmIrToBinary(
with(module) {
// type section
appendSection(1u) {
if (module.gcTypesInRecursiveGroup) {
appendVectorSize(1)
b.writeByte(0x4f)
}
appendVectorSize(functionTypes.size + gcTypes.size)
val numRecGroups = if (recGroupTypes.isEmpty()) 0 else 1
appendVectorSize(functionTypes.size + numRecGroups)
functionTypes.forEach { appendFunctionTypeDeclaration(it) }
gcTypes.forEach {
when (it) {
is WasmStructDeclaration -> appendStructTypeDeclaration(it)
is WasmArrayDeclaration -> appendArrayTypeDeclaration(it)
is WasmFunctionType -> error("Function type in GC types")
if (!recGroupTypes.isEmpty()) {
b.writeByte(0x4f)
appendVectorSize(recGroupTypes.size)
recGroupTypes.forEach {
when (it) {
is WasmStructDeclaration -> appendStructTypeDeclaration(it)
is WasmArrayDeclaration -> appendArrayTypeDeclaration(it)
is WasmFunctionType -> appendFunctionTypeDeclaration(it)
}
}
}
}
@@ -172,8 +173,8 @@ class WasmIrToBinary(
// https://github.com/WebAssembly/extended-name-section/blob/main/document/core/appendix/custom.rst
appendSection(4u) {
appendVectorSize(module.gcTypes.size)
module.gcTypes.forEach {
appendVectorSize(module.recGroupTypes.size)
module.recGroupTypes.forEach {
appendModuleFieldReference(it)
b.writeString(it.name)
}
@@ -190,7 +191,7 @@ class WasmIrToBinary(
// Experimental fields name section
// https://github.com/WebAssembly/gc/issues/193
appendSection(10u) {
val structDeclarations = module.gcTypes.filterIsInstance<WasmStructDeclaration>()
val structDeclarations = module.recGroupTypes.filterIsInstance<WasmStructDeclaration>()
appendVectorSize(structDeclarations.size)
structDeclarations.forEach {
appendModuleFieldReference(it)
@@ -228,13 +228,14 @@ class WasmIrToText : SExpressionBuilder() {
with(module) {
newLineList("module") {
functionTypes.forEach { appendFunctionTypeDeclaration(it) }
gcTypes.forEach {
recGroupTypes.forEach {
when (it) {
is WasmStructDeclaration ->
appendStructTypeDeclaration(it)
is WasmArrayDeclaration ->
appendArrayTypeDeclaration(it)
else -> error("Unexpected GC type: $it")
is WasmFunctionType ->
appendFunctionTypeDeclaration(it)
}
}
importsInOrder.forEach {