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 393093b31a6..1014f3e87cf 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 @@ -206,7 +206,7 @@ class BodyGenerator( //ClassITable and VTable load body.buildGetGlobal(context.referenceGlobalVTable(klass.symbol)) - if (klass.hasInterfaceForClass()) { + if (klass.hasInterfaceSuperClass()) { body.buildGetGlobal(context.referenceGlobalClassITable(klass.symbol)) } else { body.buildRefNull(WasmHeapType.Simple.Data) @@ -249,7 +249,7 @@ class BodyGenerator( //ClassITable and VTable load body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol)) - if (klass.hasInterfaceForClass()) { + if (klass.hasInterfaceSuperClass()) { body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol)) } else { body.buildRefNull(WasmHeapType.Simple.Data) 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 8c57c6f0100..cf89dc70773 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 @@ -5,20 +5,56 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm -import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature -import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature +import org.jetbrains.kotlin.ir.util.isOverridableOrOverrides import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.backend.js.utils.eraseGenerics import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.isInterface -import org.jetbrains.kotlin.ir.util.isOverridableOrOverrides +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.name.Name + +data class WasmSignature( + val name: Name, + val extensionReceiverType: IrType?, + val valueParametersType: List, + val returnType: IrType, + // Needed for bridges to final non-override methods + // that indirectly implement interfaces. For example: + // interface I { fun foo() } + // class C1 { fun foo() {} } + // class C2 : C1(), I + val isVirtual: Boolean, +) { + override fun toString(): String { + val er = extensionReceiverType?.let { "(er: ${it.render()}) " } ?: "" + val parameters = valueParametersType.joinToString(", ") { it.render() } + val nonVirtual = if (!isVirtual) "(non-virtual) " else "" + return "[$nonVirtual$er$name($parameters) -> ${returnType.render()}]" + } +} + +fun IrSimpleFunction.wasmSignature(irBuiltIns: IrBuiltIns): WasmSignature = + WasmSignature( + name, + extensionReceiverParameter?.type?.eraseGenerics(irBuiltIns), + valueParameters.map { it.type.eraseGenerics(irBuiltIns) }, + returnType.eraseGenerics(irBuiltIns), + isOverridableOrOverrides + ) + +class VirtualMethodMetadata( + val function: IrSimpleFunction, + val signature: WasmSignature +) class ClassMetadata( val klass: IrClass, @@ -36,27 +72,23 @@ class ClassMetadata( // Virtual methods in Wasm order // TODO: Collect interface methods separately val virtualMethods: List = run { - val virtualFunctions = - klass.declarations - .filterVirtualFunctions() - .map { - VirtualMethodMetadata( - it, - it.wasmSignature(irBuiltIns) - ) - } + val virtualFunctions = klass.declarations + .asSequence() + .filterVirtualFunctions() + .mapTo(mutableListOf()) { VirtualMethodMetadata(it, it.wasmSignature(irBuiltIns)) } + + val superClassVirtualMethods = superClass?.virtualMethods + if (superClassVirtualMethods.isNullOrEmpty()) return@run virtualFunctions + + val result = mutableListOf() val signatureToVirtualFunction = virtualFunctions.associateBy { it.signature } + superClassVirtualMethods.mapTo(result) { signatureToVirtualFunction[it.signature] ?: it } - val superSignatures = superClass?.virtualMethodsSignatures.orEmpty() + val superSignatures = superClassVirtualMethods.mapTo(mutableSetOf()) { it.signature } + virtualFunctions.filterTo(result) { it.signature !in superSignatures } - val newVirtualMethods = virtualFunctions.filter { it.signature !in superSignatures } - val superVirtualMethods = superClass?.virtualMethods.orEmpty().map { - signatureToVirtualFunction[it.signature] ?: it - } - val orderedVirtualFunctions = superVirtualMethods + newVirtualMethods - - orderedVirtualFunctions + result } init { @@ -69,64 +101,60 @@ class ClassMetadata( if (functions.size > 1) { val funcList = functions.joinToString { " ---- ${it.fqNameWhenAvailable} \n" } // TODO: Check in FE - error( - "Class ${klass.fqNameWhenAvailable} has ${functions.size} methods with the same signature $sig\n $funcList" - ) + error("Class ${klass.fqNameWhenAvailable} has ${functions.size} methods with the same signature $sig\n $funcList") } } } - - private val virtualMethodsSignatures: Set = - 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 InterfaceMetadata(val iFace: IrClass, irBuiltIns: IrBuiltIns) { + val methods: List = iFace.declarations + .asSequence() + .filterIsInstance() + .filter { !it.isFakeOverride && it.visibility != DescriptorVisibilities.PRIVATE && it.modality != Modality.FINAL } + .mapTo(mutableListOf()) { VirtualMethodMetadata(it, it.wasmSignature(irBuiltIns)) } } - -class VirtualMethodMetadata( - val function: IrSimpleFunction, - val signature: WasmSignature -) - -fun IrClass.allSuperInterfaces(): List = - superTypes.map { - it.classifierOrFail.owner as IrClass - }.flatMap { - (if (it.isInterface) listOf(it) else emptyList()) + it.allSuperInterfaces() +fun IrClass.allSuperInterfaces(): List { + fun allSuperInterfacesImpl(currentClass: IrClass, result: MutableList) { + for (superType in currentClass.superTypes) { + allSuperInterfacesImpl(superType.classifierOrFail.owner as IrClass, result) + } + if (currentClass.isInterface) result.add(currentClass) } -fun List.filterVirtualFunctions(): List = - asSequence() - .filterIsInstance() + return mutableListOf().also { + allSuperInterfacesImpl(this, it) + } +} + +fun Sequence.filterVirtualFunctions(): Sequence = + this.filterIsInstance() .filter { it.dispatchReceiverParameter != null } .map { it.realOverrideTarget } .filter { it.isOverridableOrOverrides } .distinct() - .toList() fun IrClass.getSuperClass(builtIns: IrBuiltIns): IrClass? = when (this) { builtIns.anyClass.owner -> null - else -> { - superTypes - .map { it.classifierOrFail.owner as IrClass } - .singleOrNull { !it.isInterface } ?: builtIns.anyClass.owner - } + else -> superTypes + .map { it.classifierOrFail.owner as IrClass } + .singleOrNull { !it.isInterface } ?: builtIns.anyClass.owner } fun IrClass.allFields(builtIns: IrBuiltIns): List = getSuperClass(builtIns)?.allFields(builtIns).orEmpty() + declarations.filterIsInstance() + +fun IrClass.hasInterfaceSuperClass(): Boolean { + var superClass: IrClass? = null + for (superType in superTypes) { + val typeAsClass = superType.classifierOrFail.owner as IrClass + if (typeAsClass.isInterface) { + return true + } else { + superClass = typeAsClass + } + } + return superClass?.hasInterfaceSuperClass() ?: false +} \ No newline at end of file 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 a1bc8a7725e..34ce59ac0d2 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 @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm import org.jetbrains.kotlin.backend.wasm.WasmBackendContext -import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature import org.jetbrains.kotlin.backend.wasm.utils.* import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass import org.jetbrains.kotlin.config.languageVersionSettings diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmBridgesConstruction.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmBridgesConstruction.kt index 6d7b9b4df8b..6818dbe7e01 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmBridgesConstruction.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmBridgesConstruction.kt @@ -5,16 +5,12 @@ package org.jetbrains.kotlin.backend.wasm.lower -import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmSignature +import org.jetbrains.kotlin.backend.wasm.ir2wasm.wasmSignature import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext import org.jetbrains.kotlin.ir.backend.js.lower.BridgesConstruction -import org.jetbrains.kotlin.ir.backend.js.utils.eraseGenerics import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.util.isOverridableOrOverrides -import org.jetbrains.kotlin.ir.util.render -import org.jetbrains.kotlin.name.Name class WasmBridgesConstruction(context: JsCommonBackendContext) : BridgesConstruction(context) { override fun getFunctionSignature(function: IrSimpleFunction): WasmSignature = @@ -24,33 +20,4 @@ class WasmBridgesConstruction(context: JsCommonBackendContext) : BridgesConstruc override val shouldCastDispatchReceiver: Boolean = true override fun getBridgeOrigin(bridge: IrSimpleFunction): IrDeclarationOrigin = IrDeclarationOrigin.BRIDGE -} - -data class WasmSignature( - val name: Name, - val extensionReceiverType: IrType?, - val valueParametersType: List, - val returnType: IrType, - // Needed for bridges to final non-override methods - // that indirectly implement interfaces. For example: - // interface I { fun foo() } - // class C1 { fun foo() {} } - // class C2 : C1(), I - val isVirtual: Boolean, -) { - override fun toString(): String { - val er = extensionReceiverType?.let { "(er: ${it.render()}) " } ?: "" - val parameters = valueParametersType.joinToString(", ") { it.render() } - val nonVirtual = if (!isVirtual) "(non-virtual) " else "" - return "[$nonVirtual$er$name($parameters) -> ${returnType.render()}]" - } -} - -fun IrSimpleFunction.wasmSignature(irBuiltIns: IrBuiltIns): WasmSignature = - WasmSignature( - name, - extensionReceiverParameter?.type?.eraseGenerics(irBuiltIns), - valueParameters.map { it.type.eraseGenerics(irBuiltIns) }, - returnType.eraseGenerics(irBuiltIns), - isOverridableOrOverrides - ) \ No newline at end of file +} \ No newline at end of file