[WASM] Minor refactorings

This commit is contained in:
Igor Yakovlev
2022-04-09 17:35:53 +02:00
parent 8da6ab7a04
commit 1eaa266a95
4 changed files with 93 additions and 99 deletions
@@ -206,7 +206,7 @@ class BodyGenerator(
//ClassITable and VTable load //ClassITable and VTable load
body.buildGetGlobal(context.referenceGlobalVTable(klass.symbol)) body.buildGetGlobal(context.referenceGlobalVTable(klass.symbol))
if (klass.hasInterfaceForClass()) { if (klass.hasInterfaceSuperClass()) {
body.buildGetGlobal(context.referenceGlobalClassITable(klass.symbol)) body.buildGetGlobal(context.referenceGlobalClassITable(klass.symbol))
} else { } else {
body.buildRefNull(WasmHeapType.Simple.Data) body.buildRefNull(WasmHeapType.Simple.Data)
@@ -249,7 +249,7 @@ class BodyGenerator(
//ClassITable and VTable load //ClassITable and VTable load
body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol)) body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol))
if (klass.hasInterfaceForClass()) { if (klass.hasInterfaceSuperClass()) {
body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol)) body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol))
} else { } else {
body.buildRefNull(WasmHeapType.Simple.Data) body.buildRefNull(WasmHeapType.Simple.Data)
@@ -5,20 +5,56 @@
package org.jetbrains.kotlin.backend.wasm.ir2wasm package org.jetbrains.kotlin.backend.wasm.ir2wasm
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature import org.jetbrains.kotlin.ir.util.isOverridableOrOverrides
import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns 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.backend.js.utils.realOverrideTarget
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction 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.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.isInterface 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<IrType>,
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( class ClassMetadata(
val klass: IrClass, val klass: IrClass,
@@ -36,27 +72,23 @@ class ClassMetadata(
// Virtual methods in Wasm order // Virtual methods in Wasm order
// TODO: Collect interface methods separately // TODO: Collect interface methods separately
val virtualMethods: List<VirtualMethodMetadata> = run { val virtualMethods: List<VirtualMethodMetadata> = run {
val virtualFunctions = val virtualFunctions = klass.declarations
klass.declarations .asSequence()
.filterVirtualFunctions() .filterVirtualFunctions()
.map { .mapTo(mutableListOf()) { VirtualMethodMetadata(it, it.wasmSignature(irBuiltIns)) }
VirtualMethodMetadata(
it, val superClassVirtualMethods = superClass?.virtualMethods
it.wasmSignature(irBuiltIns) if (superClassVirtualMethods.isNullOrEmpty()) return@run virtualFunctions
)
} val result = mutableListOf<VirtualMethodMetadata>()
val signatureToVirtualFunction = virtualFunctions.associateBy { it.signature } 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 } result
val superVirtualMethods = superClass?.virtualMethods.orEmpty().map {
signatureToVirtualFunction[it.signature] ?: it
}
val orderedVirtualFunctions = superVirtualMethods + newVirtualMethods
orderedVirtualFunctions
} }
init { init {
@@ -69,64 +101,60 @@ class ClassMetadata(
if (functions.size > 1) { if (functions.size > 1) {
val funcList = functions.joinToString { " ---- ${it.fqNameWhenAvailable} \n" } val funcList = functions.joinToString { " ---- ${it.fqNameWhenAvailable} \n" }
// TODO: Check in FE // TODO: Check in FE
error( error("Class ${klass.fqNameWhenAvailable} has ${functions.size} methods with the same signature $sig\n $funcList")
"Class ${klass.fqNameWhenAvailable} has ${functions.size} methods with the same signature $sig\n $funcList"
)
} }
} }
} }
private val virtualMethodsSignatures: Set<WasmSignature> =
virtualMethods.map { it.signature }.toSet()
} }
class InterfaceMetadata( class InterfaceMetadata(val iFace: IrClass, irBuiltIns: IrBuiltIns) {
val iface: IrClass, val methods: List<VirtualMethodMetadata> = iFace.declarations
irBuiltIns: IrBuiltIns .asSequence()
) { .filterIsInstance<IrSimpleFunction>()
val methods: List<VirtualMethodMetadata> = .filter { !it.isFakeOverride && it.visibility != DescriptorVisibilities.PRIVATE && it.modality != Modality.FINAL }
iface.declarations .mapTo(mutableListOf()) { VirtualMethodMetadata(it, it.wasmSignature(irBuiltIns)) }
.filterIsInstance<IrSimpleFunction>()
.filter { !it.isFakeOverride && it.visibility != DescriptorVisibilities.PRIVATE && it.modality != Modality.FINAL }
.map {
VirtualMethodMetadata(
it,
it.wasmSignature(irBuiltIns)
)
}
} }
fun IrClass.allSuperInterfaces(): List<IrClass> {
class VirtualMethodMetadata( fun allSuperInterfacesImpl(currentClass: IrClass, result: MutableList<IrClass>) {
val function: IrSimpleFunction, for (superType in currentClass.superTypes) {
val signature: WasmSignature allSuperInterfacesImpl(superType.classifierOrFail.owner as IrClass, result)
) }
if (currentClass.isInterface) result.add(currentClass)
fun IrClass.allSuperInterfaces(): List<IrClass> =
superTypes.map {
it.classifierOrFail.owner as IrClass
}.flatMap {
(if (it.isInterface) listOf(it) else emptyList()) + it.allSuperInterfaces()
} }
fun List<IrDeclaration>.filterVirtualFunctions(): List<IrSimpleFunction> = return mutableListOf<IrClass>().also {
asSequence() allSuperInterfacesImpl(this, it)
.filterIsInstance<IrSimpleFunction>() }
}
fun Sequence<IrDeclaration>.filterVirtualFunctions(): Sequence<IrSimpleFunction> =
this.filterIsInstance<IrSimpleFunction>()
.filter { it.dispatchReceiverParameter != null } .filter { it.dispatchReceiverParameter != null }
.map { it.realOverrideTarget } .map { it.realOverrideTarget }
.filter { it.isOverridableOrOverrides } .filter { it.isOverridableOrOverrides }
.distinct() .distinct()
.toList()
fun IrClass.getSuperClass(builtIns: IrBuiltIns): IrClass? = fun IrClass.getSuperClass(builtIns: IrBuiltIns): IrClass? =
when (this) { when (this) {
builtIns.anyClass.owner -> null builtIns.anyClass.owner -> null
else -> { else -> superTypes
superTypes .map { it.classifierOrFail.owner as IrClass }
.map { it.classifierOrFail.owner as IrClass } .singleOrNull { !it.isInterface } ?: builtIns.anyClass.owner
.singleOrNull { !it.isInterface } ?: builtIns.anyClass.owner
}
} }
fun IrClass.allFields(builtIns: IrBuiltIns): List<IrField> = fun IrClass.allFields(builtIns: IrBuiltIns): List<IrField> =
getSuperClass(builtIns)?.allFields(builtIns).orEmpty() + declarations.filterIsInstance<IrField>() getSuperClass(builtIns)?.allFields(builtIns).orEmpty() + declarations.filterIsInstance<IrField>()
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
}
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.wasm.ir2wasm package org.jetbrains.kotlin.backend.wasm.ir2wasm
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext 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.backend.wasm.utils.*
import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
@@ -5,16 +5,12 @@
package org.jetbrains.kotlin.backend.wasm.lower 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.JsCommonBackendContext
import org.jetbrains.kotlin.ir.backend.js.lower.BridgesConstruction 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.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction 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<JsCommonBackendContext>(context) { class WasmBridgesConstruction(context: JsCommonBackendContext) : BridgesConstruction<JsCommonBackendContext>(context) {
override fun getFunctionSignature(function: IrSimpleFunction): WasmSignature = override fun getFunctionSignature(function: IrSimpleFunction): WasmSignature =
@@ -25,32 +21,3 @@ class WasmBridgesConstruction(context: JsCommonBackendContext) : BridgesConstruc
override fun getBridgeOrigin(bridge: IrSimpleFunction): IrDeclarationOrigin = override fun getBridgeOrigin(bridge: IrSimpleFunction): IrDeclarationOrigin =
IrDeclarationOrigin.BRIDGE IrDeclarationOrigin.BRIDGE
} }
data class WasmSignature(
val name: Name,
val extensionReceiverType: IrType?,
val valueParametersType: List<IrType>,
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
)