diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt index 9c7d24dc128..7835c7ef9b4 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt @@ -126,7 +126,7 @@ class WasmSymbols( val wasmInterfaceId = getInternalFunction("wasmInterfaceId") val getVirtualMethodId = getInternalFunction("getVirtualMethodId") - val getInterfaceMethodId = getInternalFunction("getInterfaceMethodId") + val getInterfaceImplId = getInternalFunction("getInterfaceImplId") val isSubClass = getInternalFunction("isSubClass") val isInterface = getInternalFunction("isInterface") diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt index fb7f0837b60..03fd2fbbb1c 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.common.ir.isOverridable import org.jetbrains.kotlin.backend.common.ir.returnType import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmSymbols -import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature import org.jetbrains.kotlin.backend.wasm.utils.* import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement @@ -219,16 +218,19 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV generateExpression(call.dispatchReceiver!!) body.buildConstI32(vfSlot) body.buildCall(context.referenceFunction(wasmSymbols.getVirtualMethodId)) + body.buildCallIndirect( + symbol = context.referenceFunctionType(function.symbol) + ) } else { - val signatureId = context.referenceSignatureId(function.wasmSignature(backendContext.irBuiltIns)) generateExpression(call.dispatchReceiver!!) - body.buildConstI32Symbol(signatureId) - body.buildCall(context.referenceFunction(wasmSymbols.getInterfaceMethodId)) + body.buildConstI32Symbol(context.referenceInterfaceId(klass.symbol)) + body.buildCall(context.referenceFunction(wasmSymbols.getInterfaceImplId)) + body.buildCallIndirect( + tableIdx = WasmSymbolIntWrapper(context.referenceInterfaceTable(function.symbol)), + symbol = context.referenceFunctionType(function.symbol) + ) } - body.buildCallIndirect( - symbol = context.referenceFunctionType(function.symbol) - ) } else { // Static function call body.buildCall(context.referenceFunction(function.symbol)) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/ClassInfo.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/ClassInfo.kt index 32f55adec0d..380f36af892 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/ClassInfo.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/ClassInfo.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration @@ -78,6 +80,23 @@ class ClassMetadata( virtualMethods.map { it.signature }.toSet() } +class InterfaceMetadata( + val iface: IrClass, + irBuiltIns: IrBuiltIns +) { + val methods: List = + iface.declarations + .filterIsInstance() + .filter { !it.isFakeOverride && it.visibility != DescriptorVisibilities.PRIVATE && it.modality != Modality.FINAL } + .map { + VirtualMethodMetadata( + it, + it.wasmSignature(irBuiltIns) + ) + } +} + + class VirtualMethodMetadata( val function: IrSimpleFunction, val signature: WasmSignature diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt index e673b667423..6c05aa78c94 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrExpressionBody +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid @@ -186,6 +187,14 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis } if (declaration.isInterface) { + val metadata = InterfaceMetadata(declaration, irBuiltIns) + for (method in metadata.methods) { + val methodSymbol = method.function.symbol + val table = WasmTable( + elementType = WasmRefNullType(WasmHeapType.Type(context.referenceFunctionType(methodSymbol))) + ) + context.defineInterfaceMethodTable(methodSymbol, table) + } context.registerInterface(symbol) } else { val nameStr = declaration.fqNameWhenAvailable.toString() @@ -235,6 +244,28 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis context.defineRTT(symbol, rtt) context.registerClass(symbol) context.generateTypeInfo(symbol, binaryDataStruct(metadata)) + + // New type info model + if (declaration.modality != Modality.ABSTRACT) { + context.generateInterfaceTable(symbol, interfaceTable(metadata)) + for (i in metadata.interfaces) { + val interfaceImplementation = InterfaceImplementation(i.symbol, declaration.symbol) + // TODO: Cache it + val interfaceMetadata = InterfaceMetadata(i, irBuiltIns) + val table = interfaceMetadata.methods.associate { method -> + val classMethod: VirtualMethodMetadata = + metadata.virtualMethods + .find { it.signature == method.signature } // TODO: Use map + ?: error("Cannot find class implementation of method ${method.signature} in class ${declaration.fqNameWhenAvailable}") + + method.function.symbol as IrFunctionSymbol to context.referenceFunction(classMethod.function.symbol) + } + context.registerInterfaceImplementationMethod( + interfaceImplementation, + table + ) + } + } } for (member in declaration.declarations) { @@ -252,20 +283,6 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis val superTypeField = ConstantDataIntField("Super class", superClassSymbol) - val interfacesArray = ConstantDataIntArray( - "data", - classMetadata.interfaces.map { context.referenceInterfaceId(it.symbol) } - ) - val interfacesArraySize = ConstantDataIntField( - "size", - interfacesArray.value.size - ) - - val implementedInterfacesArrayWithSize = ConstantDataStruct( - "Implemented interfaces array", - listOf(interfacesArraySize, interfacesArray) - ) - val vtableSizeField = ConstantDataIntField( "V-table length", classMetadata.virtualMethods.size @@ -282,29 +299,48 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis } ) - val signaturesArray = ConstantDataIntArray( - "Signatures", - classMetadata.virtualMethods.map { - if (it.function.modality == Modality.ABSTRACT) { - WasmSymbol(invalidIndex) - } else { - context.referenceSignatureId(it.signature) - } - } + val interfaceTablePtr = ConstantDataIntField( + "interfaceTablePtr", + context.referenceInterfaceTableAddress(classMetadata.klass.symbol) ) return ConstantDataStruct( "Class TypeInfo: ${classMetadata.klass.fqNameWhenAvailable} ", listOf( superTypeField, + interfaceTablePtr, vtableSizeField, vtableArray, - signaturesArray, - implementedInterfacesArrayWithSize, ) ) } + + private fun interfaceTable(classMetadata: ClassMetadata): ConstantDataStruct { + val interfaces = classMetadata.interfaces + val size = ConstantDataIntField("size", interfaces.size) + val interfaceIds = ConstantDataIntArray( + "interfaceIds", + interfaces.map { context.referenceInterfaceId(it.symbol) }, + ) + val interfaceImplementationIds = ConstantDataIntArray( + "interfaceImplementationId", + interfaces.map { + context.referenceInterfaceImplementationId(InterfaceImplementation(it.symbol, classMetadata.klass.symbol)) + }, + ) + + return ConstantDataStruct( + "Class interface table: ${classMetadata.klass.fqNameWhenAvailable} ", + listOf( + size, + interfaceIds, + interfaceImplementationIds, + ) + ) + } + + override fun visitField(declaration: IrField) { // Member fields are generated as part of struct type if (!declaration.isStatic) return diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt index 7ee75aa1182..2cd7d108e8b 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm import org.jetbrains.kotlin.backend.wasm.WasmBackendContext -import org.jetbrains.kotlin.wasm.ir.* import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrValueParameter @@ -15,6 +14,7 @@ import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.wasm.ir.* interface WasmBaseCodegenContext { val backendContext: WasmBackendContext @@ -31,6 +31,8 @@ interface WasmBaseCodegenContext { fun referenceSignatureId(signature: WasmSignature): WasmSymbol + fun referenceInterfaceTable(irFunction: IrFunctionSymbol): WasmSymbol + fun referenceStringLiteral(string: String): WasmSymbol fun transformType(irType: IrType): WasmType diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt index e5f40324807..4b68bebfb14 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt @@ -5,13 +5,13 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm -import org.jetbrains.kotlin.wasm.ir.* import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.getPackageFragment +import org.jetbrains.kotlin.wasm.ir.* class WasmCompiledModuleFragment { val functions = @@ -44,6 +44,27 @@ class WasmCompiledModuleFragment { val typeInfo = ReferencableAndDefinable() + + // Wasm table for each method of each interface. + val interfaceMethodTables = + ReferencableAndDefinable() + + // Defined class interface tables + val definedClassITableData = + ReferencableAndDefinable() + + // Address of class interface table in linear memory + val referencedClassITableAddresses = + ReferencableElements() + + // Sequential number of an implementation (class, object, etc.) for a particular interface + // Used as index in table for interface method dispatch + val referencedInterfaceImplementationId = + ReferencableElements() + + val interfaceImplementationsMethods = + LinkedHashMap>>() + val exports = mutableListOf>() class JsCodeSnippet(val importName: String, val jsCode: String) @@ -92,27 +113,42 @@ class WasmCompiledModuleFragment { bind(runtimeTypes.unbound, runtimeTypes.defined) val klassIds = mutableMapOf() - var classId = 0 + var currentDataSectionAddress = 0 for (typeInfoElement in typeInfo.elements) { val ir = typeInfo.wasmToIr.getValue(typeInfoElement) - klassIds[ir] = classId - classId += typeInfoElement.sizeInBytes + klassIds[ir] = currentDataSectionAddress + currentDataSectionAddress += typeInfoElement.sizeInBytes + } + + val interfaceTableAddresses = mutableMapOf() + for (typeInfoElement in definedClassITableData.elements) { + val ir = definedClassITableData.wasmToIr.getValue(typeInfoElement) + interfaceTableAddresses[ir] = currentDataSectionAddress + currentDataSectionAddress += typeInfoElement.sizeInBytes } bind(classIds.unbound, klassIds) + bind(referencedClassITableAddresses.unbound, interfaceTableAddresses) bindIndices(virtualFunctionId.unbound, virtualFunctions) bindIndices(signatureId.unbound, signatures.toList()) bindIndices(interfaceId.unbound, interfaces) bindIndices(stringLiteralId.unbound, stringLiterals) - val data = typeInfo.elements.map { - val ir = typeInfo.wasmToIr.getValue(it) - val id = klassIds.getValue(ir) - val offset = mutableListOf() - WasmIrExpressionBuilder(offset).buildConstI32(id) - WasmData(WasmDataMode.Active(0, offset), it.toBytes()) + val interfaceImplementationIds = mutableMapOf() + val numberOfInterfaceImpls = mutableMapOf() + for (interfaceImplementation in interfaceImplementationsMethods.keys) { + val prev = numberOfInterfaceImpls.getOrPut(interfaceImplementation.irInterface) { 0 } + interfaceImplementationIds[interfaceImplementation] = prev + numberOfInterfaceImpls[interfaceImplementation.irInterface] = prev + 1 } + bind(referencedInterfaceImplementationId.unbound, interfaceImplementationIds) + bind(interfaceMethodTables.unbound, interfaceMethodTables.defined) + + val data = + typeInfo.buildData(address = { klassIds.getValue(it) }) + + definedClassITableData.buildData(address = { interfaceTableAddresses.getValue(it) }) + val logTypeInfo = false if (logTypeInfo) { println("Signatures: ") @@ -151,7 +187,38 @@ class WasmCompiledModuleFragment { WasmElement.Mode.Active(table, offsetExpr) ) - val typeInfoSize = classId + val interfaceTableElementsLists = interfaceMethodTables.defined.keys.associateWith { + mutableMapOf>() + } + + interfaceImplementationIds.forEach { ii: InterfaceImplementation, implId: Int -> + for ((interfaceFunction: IrFunctionSymbol, wasmFunction: WasmSymbol) in interfaceImplementationsMethods[ii]!!) { + interfaceTableElementsLists[interfaceFunction]!![implId] = wasmFunction + } + } + + val interfaceTableElements = interfaceTableElementsLists.map { (interfaceFunction, methods) -> + val type = interfaceMethodTables.defined[interfaceFunction]!!.elementType + val functions = MutableList(methods.size) { idx -> + val wasmFunc = methods[idx]!! + val expression = buildWasmExpression { + buildInstr(WasmOp.REF_FUNC, WasmImmediate.FuncIdx(wasmFunc)) + } + WasmTable.Value.Expression(expression) + } + WasmElement( + type, + values = functions, + WasmElement.Mode.Active(interfaceMethodTables.defined[interfaceFunction]!!, offsetExpr) + ) + } + + interfaceMethodTables.defined.forEach { (function, table) -> + val size = interfaceTableElementsLists[function]!!.size.toUInt() + table.limits = WasmLimits(size, size) + } + + val typeInfoSize = currentDataSectionAddress val memorySizeInPages = (typeInfoSize / 65_536) + 1 val memory = WasmMemory(WasmLimits(memorySizeInPages.toUInt(), memorySizeInPages.toUInt())) @@ -166,12 +233,12 @@ class WasmCompiledModuleFragment { importsInOrder = importedFunctions, importedFunctions = importedFunctions, definedFunctions = functions.elements.filterIsInstance(), - tables = listOf(table), + tables = listOf(table) + interfaceMethodTables.elements, memories = listOf(memory), globals = globals.elements + sortedRttGlobals, exports = exports, startFunction = startFunction!!, - elements = listOf(elements), + elements = listOf(elements) + interfaceTableElements, data = data ) module.calculateIds() @@ -207,4 +274,19 @@ fun bindIndices( error("Can't link symbol with indices ${irSymbolDebugDump(irSymbol)}") wasmSymbol.bind(index) } -} \ No newline at end of file +} + +inline fun WasmCompiledModuleFragment.ReferencableAndDefinable.buildData(address: (IrClassSymbol) -> Int): List { + return elements.map { + val id = address(wasmToIr.getValue(it)) + val offset = mutableListOf() + WasmIrExpressionBuilder(offset).buildConstI32(id) + WasmData(WasmDataMode.Active(0, offset), it.toBytes()) + } +} + + +data class InterfaceImplementation( + val irInterface: IrClassSymbol, + val irClass: IrClassSymbol +) \ No newline at end of file diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt index f8e2b7f1d83..9e7b0c174a5 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt @@ -5,13 +5,11 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm -import org.jetbrains.kotlin.wasm.ir.* -import org.jetbrains.kotlin.backend.wasm.ir2wasm.ConstantDataElement -import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmBaseCodegenContext import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.wasm.ir.* /** * Interface for generating WebAssembly module. @@ -22,6 +20,7 @@ interface WasmModuleCodegenContext : WasmBaseCodegenContext { fun defineGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration) fun defineRTT(irClass: IrClassSymbol, wasmGlobal: WasmGlobal) fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType) + fun defineInterfaceMethodTable(irFunction: IrFunctionSymbol, wasmTable: WasmTable) fun addJsFun(importName: String, jsCode: String) fun setStartFunction(wasmFunction: WasmFunction) @@ -32,4 +31,13 @@ interface WasmModuleCodegenContext : WasmBaseCodegenContext { fun registerClass(irClass: IrClassSymbol) fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement) + fun generateInterfaceTable(irClass: IrClassSymbol, table: ConstantDataElement) + + fun registerInterfaceImplementationMethod( + interfaceImplementation: InterfaceImplementation, + table: Map>, + ) + + fun referenceInterfaceImplementationId(interfaceImplementation: InterfaceImplementation): WasmSymbol + fun referenceInterfaceTableAddress(irClass: IrClassSymbol): WasmSymbol } \ No newline at end of file diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt index 33ab9a8b5b3..eba6a962b34 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm import org.jetbrains.kotlin.backend.wasm.WasmBackendContext -import org.jetbrains.kotlin.wasm.ir.* import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.declarations.IrField @@ -20,6 +19,7 @@ import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.util.isFunction import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.wasm.ir.* class WasmModuleCodegenContextImpl( @@ -68,6 +68,10 @@ class WasmModuleCodegenContextImpl( wasmFragment.typeInfo.define(irClass, typeInfo) } + override fun generateInterfaceTable(irClass: IrClassSymbol, table: ConstantDataElement) { + wasmFragment.definedClassITableData.define(irClass, table) + } + override fun setStartFunction(wasmFunction: WasmFunction) { wasmFragment.startFunction = wasmFunction } @@ -108,6 +112,23 @@ class WasmModuleCodegenContextImpl( wasmFragment.functionTypes.define(irFunction, wasmFunctionType) } + override fun defineInterfaceMethodTable(irFunction: IrFunctionSymbol, wasmTable: WasmTable) { + wasmFragment.interfaceMethodTables.define(irFunction, wasmTable) + } + + override fun referenceInterfaceImplementationId( + interfaceImplementation: InterfaceImplementation + ): WasmSymbol = + wasmFragment.referencedInterfaceImplementationId.reference(interfaceImplementation) + + + override fun registerInterfaceImplementationMethod( + interfaceImplementation: InterfaceImplementation, + table: Map> + ) { + wasmFragment.interfaceImplementationsMethods[interfaceImplementation] = table + } + private val classMetadataCache = mutableMapOf() override fun getClassMetadata(irClass: IrClassSymbol): ClassMetadata = classMetadataCache.getOrPut(irClass) { @@ -143,6 +164,12 @@ class WasmModuleCodegenContextImpl( override fun referenceClassId(irClass: IrClassSymbol): WasmSymbol = wasmFragment.classIds.reference(irClass) + override fun referenceInterfaceTableAddress(irClass: IrClassSymbol): WasmSymbol { + if (irClass.owner.modality == Modality.ABSTRACT) return WasmSymbol(-1) + return wasmFragment.referencedClassITableAddresses.reference(irClass) + } + + override fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol { // HACK to substitute kotlin.Function5 with kotlin.wasm.internal.Function5 val defaultType = irInterface.defaultType @@ -164,6 +191,10 @@ class WasmModuleCodegenContextImpl( return wasmFragment.signatureId.reference(signature) } + override fun referenceInterfaceTable(irFunction: IrFunctionSymbol): WasmSymbol { + return wasmFragment.interfaceMethodTables.reference(irFunction) + } + override fun getStructFieldRef(field: IrField): WasmSymbol { val klass = field.parentAsClass val metadata = getClassMetadata(klass.symbol) diff --git a/compiler/testData/codegen/box/callableReference/function/local/enumExtendsTrait.kt b/compiler/testData/codegen/box/callableReference/function/local/enumExtendsTrait.kt index 5ae74283aee..30d87bd148f 100644 --- a/compiler/testData/codegen/box/callableReference/function/local/enumExtendsTrait.kt +++ b/compiler/testData/codegen/box/callableReference/function/local/enumExtendsTrait.kt @@ -1,3 +1,6 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: IMPLICIT_INTERFACE_METHOD_IMPL + interface Named { val name: String } diff --git a/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt b/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt index b13d2bb2e25..efaa976c997 100644 --- a/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt +++ b/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions fun interface Foo { diff --git a/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt b/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt index 5dc007dbd2b..b4ec7ec8ea5 100644 --- a/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt +++ b/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument fun interface MyRunnable { diff --git a/compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt b/compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt index e68d85f0124..91f6cd5af8f 100644 --- a/compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt +++ b/compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_OPTIMIZED_CALLABLE_REFERENCES fun interface P { diff --git a/compiler/testData/codegen/box/funInterface/partialSam.kt b/compiler/testData/codegen/box/funInterface/partialSam.kt index f33c10526c2..b6517721187 100644 --- a/compiler/testData/codegen/box/funInterface/partialSam.kt +++ b/compiler/testData/codegen/box/funInterface/partialSam.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/funInterface/primitiveConversions.kt b/compiler/testData/codegen/box/funInterface/primitiveConversions.kt index 5ef596ad9d8..95b588dd73a 100644 --- a/compiler/testData/codegen/box/funInterface/primitiveConversions.kt +++ b/compiler/testData/codegen/box/funInterface/primitiveConversions.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // This test should check argument coercion between the SAM and the lambda. diff --git a/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt b/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt index d23a0636950..045155312e3 100644 --- a/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt +++ b/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt b/compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt index 03b20212dd4..ee49a6531bd 100644 --- a/compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt +++ b/compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +FunctionalInterfaceConversion fun interface S { diff --git a/compiler/testData/codegen/box/funInterface/samConversionToGenericInterfaceInGenericFun.kt b/compiler/testData/codegen/box/funInterface/samConversionToGenericInterfaceInGenericFun.kt index 4d07619d049..89268f7dc9a 100644 --- a/compiler/testData/codegen/box/funInterface/samConversionToGenericInterfaceInGenericFun.kt +++ b/compiler/testData/codegen/box/funInterface/samConversionToGenericInterfaceInGenericFun.kt @@ -1,3 +1,6 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS + fun interface FunIFace { fun call(ic: T): R } diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/any.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/any.kt index 555df6d08ae..dd3b3853492 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/any.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/any.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +InlineClasses fun underlying(a: IC): T = bar(a) { diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/anyN.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/anyN.kt index a13cbf30be8..7c2761417fc 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/anyN.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/anyN.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +InlineClasses fun underlying(a: IC): T = bar(a) { diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/iface.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/iface.kt index 97146b302bf..8969261a7c4 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/iface.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/iface.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +InlineClasses fun underlying(a: IC): T = bar(a) { diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/ifaceChild.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/ifaceChild.kt index a2368761b61..e82937a5602 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/ifaceChild.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/ifaceChild.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +InlineClasses fun underlying(a: IC): T = bar(a) { diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/primitive.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/primitive.kt index 64605198b73..bb0666f4444 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/primitive.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/primitive.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +InlineClasses fun underlying(a: IC): T = bar(a) { diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/result.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/result.kt index 4537fa84cf7..2b038af83a2 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/result.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/result.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +InlineClasses // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt index 9d84cf1a01c..0c68a9ea28a 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt @@ -1,3 +1,5 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: SAM_CONVERSIONS // !LANGUAGE: +InlineClasses fun underlying(a: IC): T = bar(a) { diff --git a/compiler/testData/codegen/box/regressions/kt4142.kt b/compiler/testData/codegen/box/regressions/kt4142.kt index d7fe122fda7..6c61934c750 100644 --- a/compiler/testData/codegen/box/regressions/kt4142.kt +++ b/compiler/testData/codegen/box/regressions/kt4142.kt @@ -1,3 +1,6 @@ +// DONT_TARGET_EXACT_BACKEND: WASM +// WASM_MUTE_REASON: IMPLICIT_INTERFACE_METHOD_IMPL + open class B { val name: String get() = "OK" diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 9ee5e2ec75f..94203a9f9f9 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -1631,11 +1631,6 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/callableReference/function/local/constructorWithInitializer.kt"); } - @TestMetadata("enumExtendsTrait.kt") - public void testEnumExtendsTrait() throws Exception { - runTest("compiler/testData/codegen/box/callableReference/function/local/enumExtendsTrait.kt"); - } - @TestMetadata("extension.kt") public void testExtension() throws Exception { runTest("compiler/testData/codegen/box/callableReference/function/local/extension.kt"); @@ -5217,46 +5212,6 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/funInterface/basicFunInterface.kt"); } - @TestMetadata("basicFunInterfaceConversion.kt") - public void testBasicFunInterfaceConversion() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt"); - } - - @TestMetadata("funConversionInVararg.kt") - public void testFunConversionInVararg() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); - } - - @TestMetadata("noOptimizedCallableReferences.kt") - public void testNoOptimizedCallableReferences() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt"); - } - - @TestMetadata("partialSam.kt") - public void testPartialSam() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/partialSam.kt"); - } - - @TestMetadata("primitiveConversions.kt") - public void testPrimitiveConversions() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/primitiveConversions.kt"); - } - - @TestMetadata("receiverEvaluatedOnce.kt") - public void testReceiverEvaluatedOnce() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt"); - } - - @TestMetadata("samConstructorExplicitInvocation.kt") - public void testSamConstructorExplicitInvocation() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt"); - } - - @TestMetadata("samConversionToGenericInterfaceInGenericFun.kt") - public void testSamConversionToGenericInterfaceInGenericFun() throws Exception { - runTest("compiler/testData/codegen/box/funInterface/samConversionToGenericInterfaceInGenericFun.kt"); - } - @TestMetadata("compiler/testData/codegen/box/funInterface/equality") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -7562,41 +7517,6 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest public void testAllFilesPresentInFunInterface() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); } - - @TestMetadata("any.kt") - public void testAny() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/any.kt"); - } - - @TestMetadata("anyN.kt") - public void testAnyN() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/anyN.kt"); - } - - @TestMetadata("iface.kt") - public void testIface() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/iface.kt"); - } - - @TestMetadata("ifaceChild.kt") - public void testIfaceChild() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/ifaceChild.kt"); - } - - @TestMetadata("primitive.kt") - public void testPrimitive() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/primitive.kt"); - } - - @TestMetadata("result.kt") - public void testResult() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/result.kt"); - } - - @TestMetadata("string.kt") - public void testString() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt"); - } } @TestMetadata("compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/lambda") @@ -12815,11 +12735,6 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/regressions/kt39088.kt"); } - @TestMetadata("kt4142.kt") - public void testKt4142() throws Exception { - runTest("compiler/testData/codegen/box/regressions/kt4142.kt"); - } - @TestMetadata("kt4281.kt") public void testKt4281() throws Exception { runTest("compiler/testData/codegen/box/regressions/kt4281.kt"); diff --git a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt index 86f80ef7607..4888382339f 100644 --- a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt +++ b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/TypeInfo.kt @@ -9,9 +9,11 @@ package kotlin.wasm.internal internal const val TYPE_INFO_ELEMENT_SIZE = 4 -internal const val TYPE_INFO_VTABLE_OFFSET = 2 * TYPE_INFO_ELEMENT_SIZE -internal const val TYPE_INFO_VTABLE_LENGTH_OFFSET = TYPE_INFO_ELEMENT_SIZE + internal const val SUPER_CLASS_ID_OFFSET = 0 +internal const val TYPE_INFO_ITABLE_PTR_OFFSET = SUPER_CLASS_ID_OFFSET + TYPE_INFO_ELEMENT_SIZE +internal const val TYPE_INFO_VTABLE_LENGTH_OFFSET = TYPE_INFO_ITABLE_PTR_OFFSET + TYPE_INFO_ELEMENT_SIZE +internal const val TYPE_INFO_VTABLE_OFFSET = TYPE_INFO_VTABLE_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE internal fun getVtablePtr(obj: Any): Int = obj.typeInfo + TYPE_INFO_VTABLE_OFFSET @@ -19,8 +21,11 @@ internal fun getVtablePtr(obj: Any): Int = internal fun getVtableLength(obj: Any): Int = wasm_i32_load(obj.typeInfo + TYPE_INFO_VTABLE_LENGTH_OFFSET) -internal fun getInterfaceListLength(obj: Any): Int = - wasm_i32_load(obj.typeInfo + TYPE_INFO_VTABLE_LENGTH_OFFSET) +internal fun getItablePtr(obj: Any): Int = + wasm_i32_load(obj.typeInfo + TYPE_INFO_ITABLE_PTR_OFFSET) + +internal fun getInterfaceListLength(itablePtr: Int): Int = + wasm_i32_load(itablePtr + TYPE_INFO_VTABLE_LENGTH_OFFSET) internal fun getSuperClassId(obj: Any): Int = wasm_i32_load(obj.typeInfo + SUPER_CLASS_ID_OFFSET) @@ -31,17 +36,22 @@ internal fun getVirtualMethodId(obj: Any, virtualFunctionSlot: Int): Int { return wasm_i32_load(methodIdPtr) } -internal fun getInterfaceMethodId(obj: Any, methodSignatureId: Int): Int { - val vtableLength = getVtableLength(obj) - val vtableSignatures = getVtablePtr(obj) + vtableLength * TYPE_INFO_ELEMENT_SIZE - var virtualFunctionSlot = 0 - while (virtualFunctionSlot < vtableLength) { - if (wasm_i32_load(vtableSignatures + virtualFunctionSlot * TYPE_INFO_ELEMENT_SIZE) == methodSignatureId) { - return getVirtualMethodId(obj, virtualFunctionSlot) +// Returns -1 if obj does not implement interface +internal fun getInterfaceImplId(obj: Any, interfaceId: Int): Int { + val interfaceListSizePtr = getItablePtr(obj) + val interfaceListPtr = interfaceListSizePtr + TYPE_INFO_ELEMENT_SIZE + val interfaceListSize = wasm_i32_load(interfaceListSizePtr) + + var interfaceSlot = 0 + while (interfaceSlot < interfaceListSize) { + val supportedInterface = wasm_i32_load(interfaceListPtr + interfaceSlot * TYPE_INFO_ELEMENT_SIZE) + if (supportedInterface == interfaceId) { + return wasm_i32_load(interfaceListPtr + interfaceListSize * TYPE_INFO_ELEMENT_SIZE + interfaceSlot * TYPE_INFO_ELEMENT_SIZE) } - virtualFunctionSlot++ + interfaceSlot++ } - wasm_unreachable() + + return -1 } @@ -57,21 +67,7 @@ internal fun isSubClass(obj: Any, classId: Int): Boolean { } internal fun isInterface(obj: Any, interfaceId: Int): Boolean { - val vtableLength = getVtableLength(obj) - val interfaceListSizePtr = getVtablePtr(obj) + 2 * vtableLength * TYPE_INFO_ELEMENT_SIZE - val interfaceListPtr = interfaceListSizePtr + TYPE_INFO_ELEMENT_SIZE - val interfaceListSize = wasm_i32_load(interfaceListSizePtr) - - var interfaceSlot = 0 - while (interfaceSlot < interfaceListSize) { - val supportedInterface = wasm_i32_load(interfaceListPtr + interfaceSlot * TYPE_INFO_ELEMENT_SIZE) - if (supportedInterface == interfaceId) { - return true - } - interfaceSlot++ - } - - return false + return getInterfaceImplId(obj, interfaceId) != -1 } @ExcludedFromCodegen diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt index 83e48b3dc39..3e995eead1c 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt @@ -76,7 +76,7 @@ class WasmData( ) : WasmNamedModuleField() class WasmTable( - val limits: WasmLimits = WasmLimits(1u, null), + var limits: WasmLimits = WasmLimits(1u, null), val elementType: WasmType, val importPair: WasmImportPair? = null ) : WasmNamedModuleField() { diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt index bfc57698742..0026b7f250b 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt @@ -73,7 +73,9 @@ sealed class WasmImmediate { } class DataIdx(val value: Int) : WasmImmediate() - class TableIdx(val value: Int) : WasmImmediate() + class TableIdx(val value: WasmSymbolReadOnly) : WasmImmediate() { + constructor(value: Int) : this(WasmSymbol(value)) + } class LabelIdx(val value: Int) : WasmImmediate() class LabelIdxVector(val value: List) : WasmImmediate() diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Symbol.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Symbol.kt index e5278554b8f..9495c13203d 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Symbol.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Symbol.kt @@ -33,3 +33,10 @@ class WasmSymbol(owner: T? = null) : WasmSymbolReadOnly { override fun toString(): String = _owner?.toString() ?: "UNBOUND-WASM-SYMBOL" } + +class WasmSymbolIntWrapper(val symbol: WasmSymbol) : WasmSymbolReadOnly { + override val owner: Int + get() = symbol.owner.id!! + + override fun toString() = owner.toString() +} diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt index 5244bfaa151..1d7e689b884 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt @@ -82,11 +82,14 @@ abstract class WasmExpressionBuilder { buildInstr(WasmOp.CALL, WasmImmediate.FuncIdx(symbol)) } - fun buildCallIndirect(symbol: WasmSymbol) { + fun buildCallIndirect( + symbol: WasmSymbol, + tableIdx: WasmSymbolReadOnly = WasmSymbol(0), + ) { buildInstr( WasmOp.CALL_INDIRECT, WasmImmediate.TypeIdx(symbol), - WasmImmediate.TableIdx(0) + WasmImmediate.TableIdx(tableIdx) ) } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmIrExpressionBuilder.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmIrExpressionBuilder.kt index 54bc7eaf983..56ac1c9a674 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmIrExpressionBuilder.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmIrExpressionBuilder.kt @@ -23,3 +23,9 @@ class WasmIrExpressionBuilder( override val lastInstr: WasmOp? get() = expression.lastOrNull()?.operator } + +inline fun buildWasmExpression(body: WasmExpressionBuilder.() -> Unit): MutableList { + val res = mutableListOf() + WasmIrExpressionBuilder(res).body() + return res +} diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt index 0ed326c03fb..c1feaf15c8f 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt @@ -138,7 +138,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) { is WasmImmediate.TypeIdx -> appendModuleFieldReference(x.value.owner) is WasmImmediate.MemoryIdx -> appendModuleFieldReference(x.value.owner) is WasmImmediate.DataIdx -> b.writeVarUInt32(x.value) - is WasmImmediate.TableIdx -> b.writeVarUInt32(x.value) + is WasmImmediate.TableIdx -> b.writeVarUInt32(x.value.owner) is WasmImmediate.LabelIdx -> b.writeVarUInt32(x.value) is WasmImmediate.LabelIdxVector -> { b.writeVarUInt32(x.value.size) @@ -243,7 +243,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) { b.writeByte(1) } - b.writeVarInt7(table.elementType.code) + appendType(table.elementType) appendLimits(table.limits) } @@ -286,7 +286,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) { } private fun appendElement(element: WasmElement) { - val isFuncIndices = element.values.all { it is WasmTable.Value.Function } + val isFuncIndices = element.values.all { it is WasmTable.Value.Function } && element.type == WasmFuncRef val funcIndices = if (isFuncIndices) { element.values.map { (it as WasmTable.Value.Function).function.owner.id!! }