[Wasm] Improve interface method dispatch
- Use typed Wasm tables for each interface method to avoid runtime function type check - Use linear search by implemented interface rather than by individual virtual function signature
This commit is contained in:
@@ -126,7 +126,7 @@ class WasmSymbols(
|
|||||||
val wasmInterfaceId = getInternalFunction("wasmInterfaceId")
|
val wasmInterfaceId = getInternalFunction("wasmInterfaceId")
|
||||||
|
|
||||||
val getVirtualMethodId = getInternalFunction("getVirtualMethodId")
|
val getVirtualMethodId = getInternalFunction("getVirtualMethodId")
|
||||||
val getInterfaceMethodId = getInternalFunction("getInterfaceMethodId")
|
val getInterfaceImplId = getInternalFunction("getInterfaceImplId")
|
||||||
|
|
||||||
val isSubClass = getInternalFunction("isSubClass")
|
val isSubClass = getInternalFunction("isSubClass")
|
||||||
val isInterface = getInternalFunction("isInterface")
|
val isInterface = getInternalFunction("isInterface")
|
||||||
|
|||||||
+9
-7
@@ -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.common.ir.returnType
|
||||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.wasm.WasmSymbols
|
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.backend.wasm.utils.*
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
@@ -219,16 +218,19 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
|||||||
generateExpression(call.dispatchReceiver!!)
|
generateExpression(call.dispatchReceiver!!)
|
||||||
body.buildConstI32(vfSlot)
|
body.buildConstI32(vfSlot)
|
||||||
body.buildCall(context.referenceFunction(wasmSymbols.getVirtualMethodId))
|
body.buildCall(context.referenceFunction(wasmSymbols.getVirtualMethodId))
|
||||||
|
body.buildCallIndirect(
|
||||||
|
symbol = context.referenceFunctionType(function.symbol)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
val signatureId = context.referenceSignatureId(function.wasmSignature(backendContext.irBuiltIns))
|
|
||||||
generateExpression(call.dispatchReceiver!!)
|
generateExpression(call.dispatchReceiver!!)
|
||||||
body.buildConstI32Symbol(signatureId)
|
body.buildConstI32Symbol(context.referenceInterfaceId(klass.symbol))
|
||||||
body.buildCall(context.referenceFunction(wasmSymbols.getInterfaceMethodId))
|
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 {
|
} else {
|
||||||
// Static function call
|
// Static function call
|
||||||
body.buildCall(context.referenceFunction(function.symbol))
|
body.buildCall(context.referenceFunction(function.symbol))
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
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.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.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
|
||||||
@@ -78,6 +80,23 @@ class ClassMetadata(
|
|||||||
virtualMethods.map { it.signature }.toSet()
|
virtualMethods.map { it.signature }.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InterfaceMetadata(
|
||||||
|
val iface: IrClass,
|
||||||
|
irBuiltIns: IrBuiltIns
|
||||||
|
) {
|
||||||
|
val methods: List<VirtualMethodMetadata> =
|
||||||
|
iface.declarations
|
||||||
|
.filterIsInstance<IrSimpleFunction>()
|
||||||
|
.filter { !it.isFakeOverride && it.visibility != DescriptorVisibilities.PRIVATE && it.modality != Modality.FINAL }
|
||||||
|
.map {
|
||||||
|
VirtualMethodMetadata(
|
||||||
|
it,
|
||||||
|
it.wasmSignature(irBuiltIns)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class VirtualMethodMetadata(
|
class VirtualMethodMetadata(
|
||||||
val function: IrSimpleFunction,
|
val function: IrSimpleFunction,
|
||||||
val signature: WasmSignature
|
val signature: WasmSignature
|
||||||
|
|||||||
+61
-25
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
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.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
@@ -186,6 +187,14 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (declaration.isInterface) {
|
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)
|
context.registerInterface(symbol)
|
||||||
} else {
|
} else {
|
||||||
val nameStr = declaration.fqNameWhenAvailable.toString()
|
val nameStr = declaration.fqNameWhenAvailable.toString()
|
||||||
@@ -235,6 +244,28 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis
|
|||||||
context.defineRTT(symbol, rtt)
|
context.defineRTT(symbol, rtt)
|
||||||
context.registerClass(symbol)
|
context.registerClass(symbol)
|
||||||
context.generateTypeInfo(symbol, binaryDataStruct(metadata))
|
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) {
|
for (member in declaration.declarations) {
|
||||||
@@ -252,20 +283,6 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis
|
|||||||
val superTypeField =
|
val superTypeField =
|
||||||
ConstantDataIntField("Super class", superClassSymbol)
|
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(
|
val vtableSizeField = ConstantDataIntField(
|
||||||
"V-table length",
|
"V-table length",
|
||||||
classMetadata.virtualMethods.size
|
classMetadata.virtualMethods.size
|
||||||
@@ -282,29 +299,48 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val signaturesArray = ConstantDataIntArray(
|
val interfaceTablePtr = ConstantDataIntField(
|
||||||
"Signatures",
|
"interfaceTablePtr",
|
||||||
classMetadata.virtualMethods.map {
|
context.referenceInterfaceTableAddress(classMetadata.klass.symbol)
|
||||||
if (it.function.modality == Modality.ABSTRACT) {
|
|
||||||
WasmSymbol(invalidIndex)
|
|
||||||
} else {
|
|
||||||
context.referenceSignatureId(it.signature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return ConstantDataStruct(
|
return ConstantDataStruct(
|
||||||
"Class TypeInfo: ${classMetadata.klass.fqNameWhenAvailable} ",
|
"Class TypeInfo: ${classMetadata.klass.fqNameWhenAvailable} ",
|
||||||
listOf(
|
listOf(
|
||||||
superTypeField,
|
superTypeField,
|
||||||
|
interfaceTablePtr,
|
||||||
vtableSizeField,
|
vtableSizeField,
|
||||||
vtableArray,
|
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) {
|
override fun visitField(declaration: IrField) {
|
||||||
// Member fields are generated as part of struct type
|
// Member fields are generated as part of struct type
|
||||||
if (!declaration.isStatic) return
|
if (!declaration.isStatic) return
|
||||||
|
|||||||
+3
-1
@@ -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.wasm.ir.*
|
|
||||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
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.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.wasm.ir.*
|
||||||
|
|
||||||
interface WasmBaseCodegenContext {
|
interface WasmBaseCodegenContext {
|
||||||
val backendContext: WasmBackendContext
|
val backendContext: WasmBackendContext
|
||||||
@@ -31,6 +31,8 @@ interface WasmBaseCodegenContext {
|
|||||||
|
|
||||||
fun referenceSignatureId(signature: WasmSignature): WasmSymbol<Int>
|
fun referenceSignatureId(signature: WasmSignature): WasmSymbol<Int>
|
||||||
|
|
||||||
|
fun referenceInterfaceTable(irFunction: IrFunctionSymbol): WasmSymbol<WasmTable>
|
||||||
|
|
||||||
fun referenceStringLiteral(string: String): WasmSymbol<Int>
|
fun referenceStringLiteral(string: String): WasmSymbol<Int>
|
||||||
|
|
||||||
fun transformType(irType: IrType): WasmType
|
fun transformType(irType: IrType): WasmType
|
||||||
|
|||||||
+95
-13
@@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
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.backend.wasm.lower.WasmSignature
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
|
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||||
|
import org.jetbrains.kotlin.wasm.ir.*
|
||||||
|
|
||||||
class WasmCompiledModuleFragment {
|
class WasmCompiledModuleFragment {
|
||||||
val functions =
|
val functions =
|
||||||
@@ -44,6 +44,27 @@ class WasmCompiledModuleFragment {
|
|||||||
|
|
||||||
val typeInfo =
|
val typeInfo =
|
||||||
ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>()
|
ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>()
|
||||||
|
|
||||||
|
// Wasm table for each method of each interface.
|
||||||
|
val interfaceMethodTables =
|
||||||
|
ReferencableAndDefinable<IrFunctionSymbol, WasmTable>()
|
||||||
|
|
||||||
|
// Defined class interface tables
|
||||||
|
val definedClassITableData =
|
||||||
|
ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>()
|
||||||
|
|
||||||
|
// Address of class interface table in linear memory
|
||||||
|
val referencedClassITableAddresses =
|
||||||
|
ReferencableElements<IrClassSymbol, Int>()
|
||||||
|
|
||||||
|
// Sequential number of an implementation (class, object, etc.) for a particular interface
|
||||||
|
// Used as index in table for interface method dispatch
|
||||||
|
val referencedInterfaceImplementationId =
|
||||||
|
ReferencableElements<InterfaceImplementation, Int>()
|
||||||
|
|
||||||
|
val interfaceImplementationsMethods =
|
||||||
|
LinkedHashMap<InterfaceImplementation, Map<IrFunctionSymbol, WasmSymbol<WasmFunction>>>()
|
||||||
|
|
||||||
val exports = mutableListOf<WasmExport<*>>()
|
val exports = mutableListOf<WasmExport<*>>()
|
||||||
|
|
||||||
class JsCodeSnippet(val importName: String, val jsCode: String)
|
class JsCodeSnippet(val importName: String, val jsCode: String)
|
||||||
@@ -92,27 +113,42 @@ class WasmCompiledModuleFragment {
|
|||||||
bind(runtimeTypes.unbound, runtimeTypes.defined)
|
bind(runtimeTypes.unbound, runtimeTypes.defined)
|
||||||
|
|
||||||
val klassIds = mutableMapOf<IrClassSymbol, Int>()
|
val klassIds = mutableMapOf<IrClassSymbol, Int>()
|
||||||
var classId = 0
|
var currentDataSectionAddress = 0
|
||||||
for (typeInfoElement in typeInfo.elements) {
|
for (typeInfoElement in typeInfo.elements) {
|
||||||
val ir = typeInfo.wasmToIr.getValue(typeInfoElement)
|
val ir = typeInfo.wasmToIr.getValue(typeInfoElement)
|
||||||
klassIds[ir] = classId
|
klassIds[ir] = currentDataSectionAddress
|
||||||
classId += typeInfoElement.sizeInBytes
|
currentDataSectionAddress += typeInfoElement.sizeInBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
val interfaceTableAddresses = mutableMapOf<IrClassSymbol, Int>()
|
||||||
|
for (typeInfoElement in definedClassITableData.elements) {
|
||||||
|
val ir = definedClassITableData.wasmToIr.getValue(typeInfoElement)
|
||||||
|
interfaceTableAddresses[ir] = currentDataSectionAddress
|
||||||
|
currentDataSectionAddress += typeInfoElement.sizeInBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
bind(classIds.unbound, klassIds)
|
bind(classIds.unbound, klassIds)
|
||||||
|
bind(referencedClassITableAddresses.unbound, interfaceTableAddresses)
|
||||||
bindIndices(virtualFunctionId.unbound, virtualFunctions)
|
bindIndices(virtualFunctionId.unbound, virtualFunctions)
|
||||||
bindIndices(signatureId.unbound, signatures.toList())
|
bindIndices(signatureId.unbound, signatures.toList())
|
||||||
bindIndices(interfaceId.unbound, interfaces)
|
bindIndices(interfaceId.unbound, interfaces)
|
||||||
bindIndices(stringLiteralId.unbound, stringLiterals)
|
bindIndices(stringLiteralId.unbound, stringLiterals)
|
||||||
|
|
||||||
val data = typeInfo.elements.map {
|
val interfaceImplementationIds = mutableMapOf<InterfaceImplementation, Int>()
|
||||||
val ir = typeInfo.wasmToIr.getValue(it)
|
val numberOfInterfaceImpls = mutableMapOf<IrClassSymbol, Int>()
|
||||||
val id = klassIds.getValue(ir)
|
for (interfaceImplementation in interfaceImplementationsMethods.keys) {
|
||||||
val offset = mutableListOf<WasmInstr>()
|
val prev = numberOfInterfaceImpls.getOrPut(interfaceImplementation.irInterface) { 0 }
|
||||||
WasmIrExpressionBuilder(offset).buildConstI32(id)
|
interfaceImplementationIds[interfaceImplementation] = prev
|
||||||
WasmData(WasmDataMode.Active(0, offset), it.toBytes())
|
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
|
val logTypeInfo = false
|
||||||
if (logTypeInfo) {
|
if (logTypeInfo) {
|
||||||
println("Signatures: ")
|
println("Signatures: ")
|
||||||
@@ -151,7 +187,38 @@ class WasmCompiledModuleFragment {
|
|||||||
WasmElement.Mode.Active(table, offsetExpr)
|
WasmElement.Mode.Active(table, offsetExpr)
|
||||||
)
|
)
|
||||||
|
|
||||||
val typeInfoSize = classId
|
val interfaceTableElementsLists = interfaceMethodTables.defined.keys.associateWith {
|
||||||
|
mutableMapOf<Int, WasmSymbol<WasmFunction>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceImplementationIds.forEach { ii: InterfaceImplementation, implId: Int ->
|
||||||
|
for ((interfaceFunction: IrFunctionSymbol, wasmFunction: WasmSymbol<WasmFunction>) 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 memorySizeInPages = (typeInfoSize / 65_536) + 1
|
||||||
val memory = WasmMemory(WasmLimits(memorySizeInPages.toUInt(), memorySizeInPages.toUInt()))
|
val memory = WasmMemory(WasmLimits(memorySizeInPages.toUInt(), memorySizeInPages.toUInt()))
|
||||||
|
|
||||||
@@ -166,12 +233,12 @@ class WasmCompiledModuleFragment {
|
|||||||
importsInOrder = importedFunctions,
|
importsInOrder = importedFunctions,
|
||||||
importedFunctions = importedFunctions,
|
importedFunctions = importedFunctions,
|
||||||
definedFunctions = functions.elements.filterIsInstance<WasmFunction.Defined>(),
|
definedFunctions = functions.elements.filterIsInstance<WasmFunction.Defined>(),
|
||||||
tables = listOf(table),
|
tables = listOf(table) + interfaceMethodTables.elements,
|
||||||
memories = listOf(memory),
|
memories = listOf(memory),
|
||||||
globals = globals.elements + sortedRttGlobals,
|
globals = globals.elements + sortedRttGlobals,
|
||||||
exports = exports,
|
exports = exports,
|
||||||
startFunction = startFunction!!,
|
startFunction = startFunction!!,
|
||||||
elements = listOf(elements),
|
elements = listOf(elements) + interfaceTableElements,
|
||||||
data = data
|
data = data
|
||||||
)
|
)
|
||||||
module.calculateIds()
|
module.calculateIds()
|
||||||
@@ -208,3 +275,18 @@ fun <IrSymbolType> bindIndices(
|
|||||||
wasmSymbol.bind(index)
|
wasmSymbol.bind(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun WasmCompiledModuleFragment.ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>.buildData(address: (IrClassSymbol) -> Int): List<WasmData> {
|
||||||
|
return elements.map {
|
||||||
|
val id = address(wasmToIr.getValue(it))
|
||||||
|
val offset = mutableListOf<WasmInstr>()
|
||||||
|
WasmIrExpressionBuilder(offset).buildConstI32(id)
|
||||||
|
WasmData(WasmDataMode.Active(0, offset), it.toBytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class InterfaceImplementation(
|
||||||
|
val irInterface: IrClassSymbol,
|
||||||
|
val irClass: IrClassSymbol
|
||||||
|
)
|
||||||
+11
-3
@@ -5,13 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
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.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.wasm.ir.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for generating WebAssembly module.
|
* Interface for generating WebAssembly module.
|
||||||
@@ -22,6 +20,7 @@ interface WasmModuleCodegenContext : WasmBaseCodegenContext {
|
|||||||
fun defineGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration)
|
fun defineGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration)
|
||||||
fun defineRTT(irClass: IrClassSymbol, wasmGlobal: WasmGlobal)
|
fun defineRTT(irClass: IrClassSymbol, wasmGlobal: WasmGlobal)
|
||||||
fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType)
|
fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType)
|
||||||
|
fun defineInterfaceMethodTable(irFunction: IrFunctionSymbol, wasmTable: WasmTable)
|
||||||
fun addJsFun(importName: String, jsCode: String)
|
fun addJsFun(importName: String, jsCode: String)
|
||||||
|
|
||||||
fun setStartFunction(wasmFunction: WasmFunction)
|
fun setStartFunction(wasmFunction: WasmFunction)
|
||||||
@@ -32,4 +31,13 @@ interface WasmModuleCodegenContext : WasmBaseCodegenContext {
|
|||||||
fun registerClass(irClass: IrClassSymbol)
|
fun registerClass(irClass: IrClassSymbol)
|
||||||
|
|
||||||
fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement)
|
fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement)
|
||||||
|
fun generateInterfaceTable(irClass: IrClassSymbol, table: ConstantDataElement)
|
||||||
|
|
||||||
|
fun registerInterfaceImplementationMethod(
|
||||||
|
interfaceImplementation: InterfaceImplementation,
|
||||||
|
table: Map<IrFunctionSymbol, WasmSymbol<WasmFunction>>,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun referenceInterfaceImplementationId(interfaceImplementation: InterfaceImplementation): WasmSymbol<Int>
|
||||||
|
fun referenceInterfaceTableAddress(irClass: IrClassSymbol): WasmSymbol<Int>
|
||||||
}
|
}
|
||||||
+32
-1
@@ -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.wasm.ir.*
|
|
||||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
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.types.isNothing
|
||||||
import org.jetbrains.kotlin.ir.util.isFunction
|
import org.jetbrains.kotlin.ir.util.isFunction
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
|
import org.jetbrains.kotlin.wasm.ir.*
|
||||||
|
|
||||||
|
|
||||||
class WasmModuleCodegenContextImpl(
|
class WasmModuleCodegenContextImpl(
|
||||||
@@ -68,6 +68,10 @@ class WasmModuleCodegenContextImpl(
|
|||||||
wasmFragment.typeInfo.define(irClass, typeInfo)
|
wasmFragment.typeInfo.define(irClass, typeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun generateInterfaceTable(irClass: IrClassSymbol, table: ConstantDataElement) {
|
||||||
|
wasmFragment.definedClassITableData.define(irClass, table)
|
||||||
|
}
|
||||||
|
|
||||||
override fun setStartFunction(wasmFunction: WasmFunction) {
|
override fun setStartFunction(wasmFunction: WasmFunction) {
|
||||||
wasmFragment.startFunction = wasmFunction
|
wasmFragment.startFunction = wasmFunction
|
||||||
}
|
}
|
||||||
@@ -108,6 +112,23 @@ class WasmModuleCodegenContextImpl(
|
|||||||
wasmFragment.functionTypes.define(irFunction, wasmFunctionType)
|
wasmFragment.functionTypes.define(irFunction, wasmFunctionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun defineInterfaceMethodTable(irFunction: IrFunctionSymbol, wasmTable: WasmTable) {
|
||||||
|
wasmFragment.interfaceMethodTables.define(irFunction, wasmTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun referenceInterfaceImplementationId(
|
||||||
|
interfaceImplementation: InterfaceImplementation
|
||||||
|
): WasmSymbol<Int> =
|
||||||
|
wasmFragment.referencedInterfaceImplementationId.reference(interfaceImplementation)
|
||||||
|
|
||||||
|
|
||||||
|
override fun registerInterfaceImplementationMethod(
|
||||||
|
interfaceImplementation: InterfaceImplementation,
|
||||||
|
table: Map<IrFunctionSymbol, WasmSymbol<WasmFunction>>
|
||||||
|
) {
|
||||||
|
wasmFragment.interfaceImplementationsMethods[interfaceImplementation] = table
|
||||||
|
}
|
||||||
|
|
||||||
private val classMetadataCache = mutableMapOf<IrClassSymbol, ClassMetadata>()
|
private val classMetadataCache = mutableMapOf<IrClassSymbol, ClassMetadata>()
|
||||||
override fun getClassMetadata(irClass: IrClassSymbol): ClassMetadata =
|
override fun getClassMetadata(irClass: IrClassSymbol): ClassMetadata =
|
||||||
classMetadataCache.getOrPut(irClass) {
|
classMetadataCache.getOrPut(irClass) {
|
||||||
@@ -143,6 +164,12 @@ class WasmModuleCodegenContextImpl(
|
|||||||
override fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int> =
|
override fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int> =
|
||||||
wasmFragment.classIds.reference(irClass)
|
wasmFragment.classIds.reference(irClass)
|
||||||
|
|
||||||
|
override fun referenceInterfaceTableAddress(irClass: IrClassSymbol): WasmSymbol<Int> {
|
||||||
|
if (irClass.owner.modality == Modality.ABSTRACT) return WasmSymbol(-1)
|
||||||
|
return wasmFragment.referencedClassITableAddresses.reference(irClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int> {
|
override fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int> {
|
||||||
// HACK to substitute kotlin.Function5 with kotlin.wasm.internal.Function5
|
// HACK to substitute kotlin.Function5 with kotlin.wasm.internal.Function5
|
||||||
val defaultType = irInterface.defaultType
|
val defaultType = irInterface.defaultType
|
||||||
@@ -164,6 +191,10 @@ class WasmModuleCodegenContextImpl(
|
|||||||
return wasmFragment.signatureId.reference(signature)
|
return wasmFragment.signatureId.reference(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun referenceInterfaceTable(irFunction: IrFunctionSymbol): WasmSymbol<WasmTable> {
|
||||||
|
return wasmFragment.interfaceMethodTables.reference(irFunction)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getStructFieldRef(field: IrField): WasmSymbol<Int> {
|
override fun getStructFieldRef(field: IrField): WasmSymbol<Int> {
|
||||||
val klass = field.parentAsClass
|
val klass = field.parentAsClass
|
||||||
val metadata = getClassMetadata(klass.symbol)
|
val metadata = getClassMetadata(klass.symbol)
|
||||||
|
|||||||
+3
@@ -1,3 +1,6 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: IMPLICIT_INTERFACE_METHOD_IMPL
|
||||||
|
|
||||||
interface Named {
|
interface Named {
|
||||||
val name: String
|
val name: String
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
||||||
|
|
||||||
fun interface Foo {
|
fun interface Foo {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument
|
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument
|
||||||
|
|
||||||
fun interface MyRunnable {
|
fun interface MyRunnable {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_OPTIMIZED_CALLABLE_REFERENCES
|
// KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_OPTIMIZED_CALLABLE_REFERENCES
|
||||||
|
|
||||||
fun interface P {
|
fun interface P {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
||||||
|
|
||||||
// This test should check argument coercion between the SAM and the lambda.
|
// This test should check argument coercion between the SAM and the lambda.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +FunctionalInterfaceConversion
|
// !LANGUAGE: +FunctionalInterfaceConversion
|
||||||
|
|
||||||
fun interface S {
|
fun interface S {
|
||||||
|
|||||||
+3
@@ -1,3 +1,6 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
|
|
||||||
fun interface FunIFace<T, R> {
|
fun interface FunIFace<T, R> {
|
||||||
fun call(ic: T): R
|
fun call(ic: T): R
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
fun <T> underlying(a: IC): T = bar(a) {
|
fun <T> underlying(a: IC): T = bar(a) {
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
fun <T> underlying(a: IC): T = bar(a) {
|
fun <T> underlying(a: IC): T = bar(a) {
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
fun <T> underlying(a: IC): T = bar(a) {
|
fun <T> underlying(a: IC): T = bar(a) {
|
||||||
|
|||||||
Vendored
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
fun <T> underlying(a: IC): T = bar(a) {
|
fun <T> underlying(a: IC): T = bar(a) {
|
||||||
|
|||||||
Vendored
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
fun <T> underlying(a: IC): T = bar(a) {
|
fun <T> underlying(a: IC): T = bar(a) {
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: SAM_CONVERSIONS
|
||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
fun <T> underlying(a: IC): T = bar(a) {
|
fun <T> underlying(a: IC): T = bar(a) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||||
|
// WASM_MUTE_REASON: IMPLICIT_INTERFACE_METHOD_IMPL
|
||||||
|
|
||||||
open class B {
|
open class B {
|
||||||
val name: String
|
val name: String
|
||||||
get() = "OK"
|
get() = "OK"
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
-85
@@ -1631,11 +1631,6 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
runTest("compiler/testData/codegen/box/callableReference/function/local/constructorWithInitializer.kt");
|
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")
|
@TestMetadata("extension.kt")
|
||||||
public void testExtension() throws Exception {
|
public void testExtension() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/callableReference/function/local/extension.kt");
|
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");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/funInterface/equality")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
@@ -7562,41 +7517,6 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
public void testAllFilesPresentInFunInterface() throws Exception {
|
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);
|
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")
|
@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");
|
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")
|
@TestMetadata("kt4281.kt")
|
||||||
public void testKt4281() throws Exception {
|
public void testKt4281() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/regressions/kt4281.kt");
|
runTest("compiler/testData/codegen/box/regressions/kt4281.kt");
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ package kotlin.wasm.internal
|
|||||||
|
|
||||||
internal const val TYPE_INFO_ELEMENT_SIZE = 4
|
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 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 =
|
internal fun getVtablePtr(obj: Any): Int =
|
||||||
obj.typeInfo + TYPE_INFO_VTABLE_OFFSET
|
obj.typeInfo + TYPE_INFO_VTABLE_OFFSET
|
||||||
@@ -19,8 +21,11 @@ internal fun getVtablePtr(obj: Any): Int =
|
|||||||
internal fun getVtableLength(obj: Any): Int =
|
internal fun getVtableLength(obj: Any): Int =
|
||||||
wasm_i32_load(obj.typeInfo + TYPE_INFO_VTABLE_LENGTH_OFFSET)
|
wasm_i32_load(obj.typeInfo + TYPE_INFO_VTABLE_LENGTH_OFFSET)
|
||||||
|
|
||||||
internal fun getInterfaceListLength(obj: Any): Int =
|
internal fun getItablePtr(obj: Any): Int =
|
||||||
wasm_i32_load(obj.typeInfo + TYPE_INFO_VTABLE_LENGTH_OFFSET)
|
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 =
|
internal fun getSuperClassId(obj: Any): Int =
|
||||||
wasm_i32_load(obj.typeInfo + SUPER_CLASS_ID_OFFSET)
|
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)
|
return wasm_i32_load(methodIdPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getInterfaceMethodId(obj: Any, methodSignatureId: Int): Int {
|
// Returns -1 if obj does not implement interface
|
||||||
val vtableLength = getVtableLength(obj)
|
internal fun getInterfaceImplId(obj: Any, interfaceId: Int): Int {
|
||||||
val vtableSignatures = getVtablePtr(obj) + vtableLength * TYPE_INFO_ELEMENT_SIZE
|
val interfaceListSizePtr = getItablePtr(obj)
|
||||||
var virtualFunctionSlot = 0
|
val interfaceListPtr = interfaceListSizePtr + TYPE_INFO_ELEMENT_SIZE
|
||||||
while (virtualFunctionSlot < vtableLength) {
|
val interfaceListSize = wasm_i32_load(interfaceListSizePtr)
|
||||||
if (wasm_i32_load(vtableSignatures + virtualFunctionSlot * TYPE_INFO_ELEMENT_SIZE) == methodSignatureId) {
|
|
||||||
return getVirtualMethodId(obj, virtualFunctionSlot)
|
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 {
|
internal fun isInterface(obj: Any, interfaceId: Int): Boolean {
|
||||||
val vtableLength = getVtableLength(obj)
|
return getInterfaceImplId(obj, interfaceId) != -1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExcludedFromCodegen
|
@ExcludedFromCodegen
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class WasmData(
|
|||||||
) : WasmNamedModuleField()
|
) : WasmNamedModuleField()
|
||||||
|
|
||||||
class WasmTable(
|
class WasmTable(
|
||||||
val limits: WasmLimits = WasmLimits(1u, null),
|
var limits: WasmLimits = WasmLimits(1u, null),
|
||||||
val elementType: WasmType,
|
val elementType: WasmType,
|
||||||
val importPair: WasmImportPair? = null
|
val importPair: WasmImportPair? = null
|
||||||
) : WasmNamedModuleField() {
|
) : WasmNamedModuleField() {
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ sealed class WasmImmediate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DataIdx(val value: Int) : WasmImmediate()
|
class DataIdx(val value: Int) : WasmImmediate()
|
||||||
class TableIdx(val value: Int) : WasmImmediate()
|
class TableIdx(val value: WasmSymbolReadOnly<Int>) : WasmImmediate() {
|
||||||
|
constructor(value: Int) : this(WasmSymbol(value))
|
||||||
|
}
|
||||||
|
|
||||||
class LabelIdx(val value: Int) : WasmImmediate()
|
class LabelIdx(val value: Int) : WasmImmediate()
|
||||||
class LabelIdxVector(val value: List<Int>) : WasmImmediate()
|
class LabelIdxVector(val value: List<Int>) : WasmImmediate()
|
||||||
|
|||||||
@@ -33,3 +33,10 @@ class WasmSymbol<out T : Any>(owner: T? = null) : WasmSymbolReadOnly<T> {
|
|||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
_owner?.toString() ?: "UNBOUND-WASM-SYMBOL"
|
_owner?.toString() ?: "UNBOUND-WASM-SYMBOL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WasmSymbolIntWrapper(val symbol: WasmSymbol<WasmNamedModuleField>) : WasmSymbolReadOnly<Int> {
|
||||||
|
override val owner: Int
|
||||||
|
get() = symbol.owner.id!!
|
||||||
|
|
||||||
|
override fun toString() = owner.toString()
|
||||||
|
}
|
||||||
|
|||||||
@@ -82,11 +82,14 @@ abstract class WasmExpressionBuilder {
|
|||||||
buildInstr(WasmOp.CALL, WasmImmediate.FuncIdx(symbol))
|
buildInstr(WasmOp.CALL, WasmImmediate.FuncIdx(symbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildCallIndirect(symbol: WasmSymbol<WasmFunctionType>) {
|
fun buildCallIndirect(
|
||||||
|
symbol: WasmSymbol<WasmFunctionType>,
|
||||||
|
tableIdx: WasmSymbolReadOnly<Int> = WasmSymbol(0),
|
||||||
|
) {
|
||||||
buildInstr(
|
buildInstr(
|
||||||
WasmOp.CALL_INDIRECT,
|
WasmOp.CALL_INDIRECT,
|
||||||
WasmImmediate.TypeIdx(symbol),
|
WasmImmediate.TypeIdx(symbol),
|
||||||
WasmImmediate.TableIdx(0)
|
WasmImmediate.TableIdx(tableIdx)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,9 @@ class WasmIrExpressionBuilder(
|
|||||||
override val lastInstr: WasmOp?
|
override val lastInstr: WasmOp?
|
||||||
get() = expression.lastOrNull()?.operator
|
get() = expression.lastOrNull()?.operator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun buildWasmExpression(body: WasmExpressionBuilder.() -> Unit): MutableList<WasmInstr> {
|
||||||
|
val res = mutableListOf<WasmInstr>()
|
||||||
|
WasmIrExpressionBuilder(res).body()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) {
|
|||||||
is WasmImmediate.TypeIdx -> appendModuleFieldReference(x.value.owner)
|
is WasmImmediate.TypeIdx -> appendModuleFieldReference(x.value.owner)
|
||||||
is WasmImmediate.MemoryIdx -> appendModuleFieldReference(x.value.owner)
|
is WasmImmediate.MemoryIdx -> appendModuleFieldReference(x.value.owner)
|
||||||
is WasmImmediate.DataIdx -> b.writeVarUInt32(x.value)
|
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.LabelIdx -> b.writeVarUInt32(x.value)
|
||||||
is WasmImmediate.LabelIdxVector -> {
|
is WasmImmediate.LabelIdxVector -> {
|
||||||
b.writeVarUInt32(x.value.size)
|
b.writeVarUInt32(x.value.size)
|
||||||
@@ -243,7 +243,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) {
|
|||||||
b.writeByte(1)
|
b.writeByte(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.writeVarInt7(table.elementType.code)
|
appendType(table.elementType)
|
||||||
appendLimits(table.limits)
|
appendLimits(table.limits)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun appendElement(element: WasmElement) {
|
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) {
|
val funcIndices = if (isFuncIndices) {
|
||||||
element.values.map { (it as WasmTable.Value.Function).function.owner.id!! }
|
element.values.map { (it as WasmTable.Value.Function).function.owner.id!! }
|
||||||
|
|||||||
Reference in New Issue
Block a user