[WASM] New VTable format
This commit is contained in:
@@ -173,9 +173,6 @@ class WasmSymbols(
|
||||
val wasmClassId = getInternalFunction("wasmClassId")
|
||||
val wasmInterfaceId = getInternalFunction("wasmInterfaceId")
|
||||
|
||||
val getVirtualMethodId = getInternalFunction("getVirtualMethodId")
|
||||
val getInterfaceImplId = getInternalFunction("getInterfaceImplId")
|
||||
|
||||
val isInterface = getInternalFunction("isInterface")
|
||||
|
||||
val nullableEquals = getInternalFunction("nullableEquals")
|
||||
|
||||
@@ -80,6 +80,7 @@ fun compileWasm(
|
||||
): WasmCompilerResult {
|
||||
val compiledWasmModule = WasmCompiledModuleFragment(backendContext.irBuiltIns)
|
||||
val codeGenerator = WasmModuleFragmentGenerator(backendContext, compiledWasmModule, allowIncompleteImplementations = allowIncompleteImplementations)
|
||||
allModules.forEach { codeGenerator.collectInterfaceTables(it) }
|
||||
allModules.forEach { codeGenerator.generateModule(it) }
|
||||
|
||||
val linkedModule = compiledWasmModule.linkWasmCompiledFragments()
|
||||
|
||||
+2
-5
@@ -97,11 +97,8 @@ internal class WasmUsefulDeclarationProcessor(
|
||||
val isSuperCall = expression.superQualifierSymbol != null
|
||||
if (function is IrSimpleFunction && function.isOverridable && !isSuperCall) {
|
||||
val klass = function.parentAsClass
|
||||
if (!klass.isInterface) {
|
||||
context.wasmSymbols.getVirtualMethodId.owner.enqueue(data, "call on class receiver")
|
||||
} else {
|
||||
if (klass.isInterface) {
|
||||
klass.enqueue(data, "receiver class")
|
||||
context.wasmSymbols.getInterfaceImplId.owner.enqueue(data, "call on interface receiver")
|
||||
}
|
||||
function.enqueue(data, "method call")
|
||||
}
|
||||
@@ -134,7 +131,7 @@ internal class WasmUsefulDeclarationProcessor(
|
||||
}
|
||||
|
||||
private fun IrType.enqueueRuntimeClassOrAny(from: IrDeclaration, info: String): Unit =
|
||||
(this.getRuntimeClass ?: context.wasmSymbols.any.owner).enqueue(from, info, isContagious = false)
|
||||
this.getRuntimeClass(context.irBuiltIns).enqueue(from, info, isContagious = false)
|
||||
|
||||
private fun IrType.enqueueType(from: IrDeclaration, info: String) {
|
||||
getInlinedValueTypeIfAny()
|
||||
|
||||
+115
-71
@@ -10,9 +10,7 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
||||
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.utils.getWasmArrayAnnotation
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.getWasmOpAnnotation
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.hasWasmNoOpCastAnnotation
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.*
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.isCanonical
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -29,7 +27,10 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
|
||||
class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorVoid {
|
||||
class BodyGenerator(
|
||||
val context: WasmFunctionCodegenContext,
|
||||
private val hierarchyDisjointUnions: DisjointUnions<IrClassSymbol>
|
||||
) : IrElementVisitorVoid {
|
||||
val body: WasmExpressionBuilder = context.bodyGen
|
||||
|
||||
// Shortcuts
|
||||
@@ -117,7 +118,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
generateInstanceFieldAccess(field)
|
||||
}
|
||||
} else {
|
||||
body.buildGetGlobal(context.referenceGlobal(field.symbol))
|
||||
body.buildGetGlobal(context.referenceGlobalField(field.symbol))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +155,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
)
|
||||
} else {
|
||||
generateExpression(expression.value)
|
||||
body.buildSetGlobal(context.referenceGlobal(expression.symbol))
|
||||
body.buildSetGlobal(context.referenceGlobalField(expression.symbol))
|
||||
}
|
||||
|
||||
body.buildGetUnit()
|
||||
@@ -203,6 +204,14 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
return
|
||||
}
|
||||
|
||||
//ClassITable and VTable load
|
||||
body.buildGetGlobal(context.referenceGlobalVTable(klass.symbol))
|
||||
if (klass.hasInterfaceForClass()) {
|
||||
body.buildGetGlobal(context.referenceGlobalClassITable(klass.symbol))
|
||||
} else {
|
||||
body.buildRefNull(WasmHeapType.Simple.Data)
|
||||
}
|
||||
|
||||
val wasmClassId = context.referenceClassId(klass.symbol)
|
||||
|
||||
val irFields: List<IrField> = klass.allFields(backendContext.irBuiltIns)
|
||||
@@ -214,7 +223,6 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
generateDefaultInitializerForType(context.transformType(field.type), body)
|
||||
}
|
||||
|
||||
generateClassRTT(klass.symbol)
|
||||
body.buildStructNew(wasmGcType)
|
||||
generateCall(expression)
|
||||
}
|
||||
@@ -236,16 +244,21 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
// Box intrinsic has an additional klass ID argument.
|
||||
// Processing it separately
|
||||
if (call.symbol == wasmSymbols.boxIntrinsic) {
|
||||
val toType = call.getTypeArgument(0)!!
|
||||
val klass = toType.getRuntimeClass!!
|
||||
val structTypeName = context.referenceGcType(klass.symbol)
|
||||
val klassId = context.referenceClassId(klass.symbol)
|
||||
val klass = call.getTypeArgument(0)!!.getRuntimeClass(irBuiltIns)
|
||||
val klassSymbol = klass.symbol
|
||||
|
||||
body.buildConstI32Symbol(klassId)
|
||||
//ClassITable and VTable load
|
||||
body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol))
|
||||
if (klass.hasInterfaceForClass()) {
|
||||
body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol))
|
||||
} else {
|
||||
body.buildRefNull(WasmHeapType.Simple.Data)
|
||||
}
|
||||
|
||||
body.buildConstI32Symbol(context.referenceClassId(klassSymbol))
|
||||
body.buildConstI32(0) // Any::_hashCode
|
||||
generateExpression(call.getValueArgument(0)!!)
|
||||
generateClassRTT(klass.symbol)
|
||||
body.buildStructNew(structTypeName)
|
||||
body.buildStructNew(context.referenceGcType(klassSymbol))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -296,20 +309,35 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
val vfSlot = classMetadata.virtualMethods.indexOfFirst { it.function == function }
|
||||
// Dispatch receiver should be simple and without side effects at this point
|
||||
// TODO: Verify
|
||||
generateExpression(call.dispatchReceiver!!)
|
||||
body.buildConstI32(vfSlot)
|
||||
body.buildCall(context.referenceFunction(wasmSymbols.getVirtualMethodId))
|
||||
body.buildCallIndirect(
|
||||
symbol = context.referenceFunctionType(function.symbol)
|
||||
)
|
||||
val receiver = call.dispatchReceiver!!
|
||||
generateExpression(receiver)
|
||||
|
||||
if (!receiver.type.getRuntimeClass(irBuiltIns).isSubclassOf(klass)) {
|
||||
body.buildRefCastStatic(toType = context.referenceGcType(klass.symbol))
|
||||
}
|
||||
|
||||
body.buildStructGet(context.referenceGcType(klass.symbol), WasmSymbol(0))
|
||||
body.buildStructGet(context.referenceVTableGcType(klass.symbol), WasmSymbol(vfSlot))
|
||||
body.buildInstr(WasmOp.CALL_REF)
|
||||
} else {
|
||||
generateExpression(call.dispatchReceiver!!)
|
||||
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)
|
||||
)
|
||||
val symbol = klass.symbol
|
||||
if (symbol in hierarchyDisjointUnions) {
|
||||
generateExpression(call.dispatchReceiver!!)
|
||||
|
||||
body.buildStructGet(context.referenceGcType(irBuiltIns.anyClass), WasmSymbol(1))
|
||||
|
||||
val classITableReference = context.referenceClassITableGcType(symbol)
|
||||
body.buildRefCastStatic(classITableReference)
|
||||
body.buildStructGet(classITableReference, context.referenceClassITableInterfaceSlot(symbol))
|
||||
|
||||
val vfSlot = context.getInterfaceMetadata(symbol).methods
|
||||
.indexOfFirst { it.function == function }
|
||||
|
||||
body.buildStructGet(context.referenceVTableGcType(symbol), WasmSymbol(vfSlot))
|
||||
body.buildInstr(WasmOp.CALL_REF)
|
||||
} else {
|
||||
body.buildUnreachable()
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -322,13 +350,14 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
body.buildGetUnit()
|
||||
}
|
||||
|
||||
private fun generateTypeRTT(type: IrType) {
|
||||
val klass = type.getRuntimeClass?.symbol ?: context.backendContext.irBuiltIns.anyClass
|
||||
generateClassRTT(klass)
|
||||
private fun generateRefCast(type: IrType) {
|
||||
body.buildRefCastStatic(
|
||||
context.referenceGcType(type.getRuntimeClass(irBuiltIns).symbol)
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateClassRTT(klass: IrClassSymbol) {
|
||||
body.buildRttCanon(context.referenceGcType(klass))
|
||||
private fun generateTypeRTT(type: IrType) {
|
||||
body.buildRttCanon(context.referenceGcType(type.getRuntimeClass(irBuiltIns).symbol))
|
||||
}
|
||||
|
||||
// Return true if generated.
|
||||
@@ -356,10 +385,35 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
body.buildConstI32Symbol(context.referenceInterfaceId(irInterface.symbol))
|
||||
}
|
||||
|
||||
wasmSymbols.isInterface -> {
|
||||
val irInterface = call.getTypeArgument(0)!!.getClass()
|
||||
?: error("No interface given for wasmInterfaceId intrinsic")
|
||||
assert(irInterface.isInterface)
|
||||
if (irInterface.symbol in hierarchyDisjointUnions) {
|
||||
val classITable = context.referenceClassITableGcType(irInterface.symbol)
|
||||
val parameterLocal = context.referenceLocal(SyntheticLocalType.IS_INTERFACE_PARAMETER)
|
||||
body.buildSetLocal(parameterLocal)
|
||||
body.buildBlock("isInterface", WasmI32) { outerLabel ->
|
||||
body.buildBlock("isInterface", WasmRefNullType(WasmHeapType.Simple.Data)) { innerLabel ->
|
||||
body.buildGetLocal(parameterLocal)
|
||||
body.buildStructGet(context.referenceGcType(irBuiltIns.anyClass), WasmSymbol(1))
|
||||
body.buildBrInstr(WasmOp.BR_ON_CAST_STATIC_FAIL, innerLabel, classITable)
|
||||
body.buildStructGet(classITable, context.referenceClassITableInterfaceSlot(irInterface.symbol))
|
||||
body.buildInstr(WasmOp.REF_IS_NULL)
|
||||
body.buildInstr(WasmOp.I32_EQZ)
|
||||
body.buildBr(outerLabel)
|
||||
}
|
||||
body.buildDrop()
|
||||
body.buildConstI32(0)
|
||||
}
|
||||
} else {
|
||||
body.buildDrop()
|
||||
body.buildConstI32(0)
|
||||
}
|
||||
}
|
||||
|
||||
wasmSymbols.wasmRefCast -> {
|
||||
val toType = call.getTypeArgument(0)!!
|
||||
generateTypeRTT(toType)
|
||||
body.buildRefCast()
|
||||
generateRefCast(call.getTypeArgument(0)!!)
|
||||
}
|
||||
|
||||
wasmSymbols.refTest -> {
|
||||
@@ -443,7 +497,8 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
|
||||
override fun visitReturn(expression: IrReturn) {
|
||||
if (expression.returnTargetSymbol.owner.returnType(backendContext) == irBuiltIns.unitType &&
|
||||
expression.returnTargetSymbol.owner != unitGetInstance) {
|
||||
expression.returnTargetSymbol.owner != unitGetInstance
|
||||
) {
|
||||
generateStatement(expression.value)
|
||||
} else {
|
||||
generateExpression(expression.value)
|
||||
@@ -499,24 +554,17 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
|
||||
val label = loop.label
|
||||
|
||||
body.buildLoop(label)
|
||||
val wasmLoop = body.numberOfNestedBlocks
|
||||
|
||||
body.buildBlock("BREAK_$label")
|
||||
val wasmBreakBlock = body.numberOfNestedBlocks
|
||||
|
||||
body.buildBlock("CONTINUE_$label")
|
||||
val wasmContinueBlock = body.numberOfNestedBlocks
|
||||
|
||||
context.defineLoopLevel(loop, LoopLabelType.BREAK, wasmBreakBlock)
|
||||
context.defineLoopLevel(loop, LoopLabelType.CONTINUE, wasmContinueBlock)
|
||||
|
||||
loop.body?.let { generateStatement(it) }
|
||||
body.buildEnd()
|
||||
generateExpression(loop.condition)
|
||||
body.buildBrIf(wasmLoop)
|
||||
body.buildEnd()
|
||||
body.buildEnd()
|
||||
body.buildLoop(label) { wasmLoop ->
|
||||
body.buildBlock("BREAK_$label") { wasmBreakBlock ->
|
||||
body.buildBlock("CONTINUE_$label") { wasmContinueBlock ->
|
||||
context.defineLoopLevel(loop, LoopLabelType.BREAK, wasmBreakBlock)
|
||||
context.defineLoopLevel(loop, LoopLabelType.CONTINUE, wasmContinueBlock)
|
||||
loop.body?.let { generateStatement(it) }
|
||||
}
|
||||
generateExpression(loop.condition)
|
||||
body.buildBrIf(wasmLoop)
|
||||
}
|
||||
}
|
||||
|
||||
body.buildGetUnit()
|
||||
}
|
||||
@@ -530,24 +578,20 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
|
||||
val label = loop.label
|
||||
|
||||
body.buildLoop(label)
|
||||
val wasmLoop = body.numberOfNestedBlocks
|
||||
body.buildLoop(label) { wasmLoop ->
|
||||
body.buildBlock("BREAK_$label") { wasmBreakBlock ->
|
||||
context.defineLoopLevel(loop, LoopLabelType.BREAK, wasmBreakBlock)
|
||||
context.defineLoopLevel(loop, LoopLabelType.CONTINUE, wasmLoop)
|
||||
|
||||
body.buildBlock("BREAK_$label")
|
||||
val wasmBreakBlock = body.numberOfNestedBlocks
|
||||
|
||||
context.defineLoopLevel(loop, LoopLabelType.BREAK, wasmBreakBlock)
|
||||
context.defineLoopLevel(loop, LoopLabelType.CONTINUE, wasmLoop)
|
||||
|
||||
generateExpression(loop.condition)
|
||||
body.buildInstr(WasmOp.I32_EQZ)
|
||||
body.buildBrIf(wasmBreakBlock)
|
||||
loop.body?.let {
|
||||
generateStatement(it)
|
||||
generateExpression(loop.condition)
|
||||
body.buildInstr(WasmOp.I32_EQZ)
|
||||
body.buildBrIf(wasmBreakBlock)
|
||||
loop.body?.let {
|
||||
generateStatement(it)
|
||||
}
|
||||
body.buildBr(wasmLoop)
|
||||
}
|
||||
}
|
||||
body.buildBr(wasmLoop)
|
||||
body.buildEnd()
|
||||
body.buildEnd()
|
||||
|
||||
body.buildGetUnit()
|
||||
}
|
||||
@@ -564,7 +608,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
|
||||
}
|
||||
|
||||
// Return true if function is recognized as intrinsic.
|
||||
fun tryToGenerateWasmOpIntrinsicCall(call: IrFunctionAccessExpression, function: IrFunction): Boolean {
|
||||
private fun tryToGenerateWasmOpIntrinsicCall(call: IrFunctionAccessExpression, function: IrFunction): Boolean {
|
||||
if (function.hasWasmNoOpCastAnnotation()) {
|
||||
return true
|
||||
}
|
||||
|
||||
+178
-100
@@ -22,14 +22,18 @@ import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.parentOrNull
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
|
||||
class DeclarationGenerator(val context: WasmModuleCodegenContext, private val allowIncompleteImplementations: Boolean) : IrElementVisitorVoid {
|
||||
class DeclarationGenerator(
|
||||
val context: WasmModuleCodegenContext,
|
||||
private val allowIncompleteImplementations: Boolean,
|
||||
private val hierarchyDisjointUnions: DisjointUnions<IrClassSymbol>,
|
||||
) : IrElementVisitorVoid {
|
||||
|
||||
// Shortcuts
|
||||
private val backendContext: WasmBackendContext = context.backendContext
|
||||
@@ -90,13 +94,8 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
)
|
||||
context.defineFunctionType(declaration.symbol, wasmFunctionType)
|
||||
|
||||
if (declaration is IrSimpleFunction) {
|
||||
if (declaration.modality == Modality.ABSTRACT) return
|
||||
if (declaration.isOverridableOrOverrides) {
|
||||
// Register function as virtual, meaning this function
|
||||
// will be stored Wasm table and could be called indirectly.
|
||||
context.registerVirtualFunction(declaration.symbol)
|
||||
}
|
||||
if (declaration is IrSimpleFunction && declaration.modality == Modality.ABSTRACT) {
|
||||
return
|
||||
}
|
||||
|
||||
assert(declaration == declaration.realOverrideTarget) {
|
||||
@@ -128,7 +127,7 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
}
|
||||
|
||||
val exprGen = functionCodegenContext.bodyGen
|
||||
val bodyBuilder = BodyGenerator(functionCodegenContext)
|
||||
val bodyBuilder = BodyGenerator(functionCodegenContext, hierarchyDisjointUnions)
|
||||
|
||||
require(declaration.body is IrBlockBody) { "Only IrBlockBody is supported" }
|
||||
declaration.body?.acceptVoid(bodyBuilder)
|
||||
@@ -167,12 +166,143 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDeclarationByInterface(iFace: IrClassSymbol) {
|
||||
if (context.isAlreadyDefinedClassITableGcType(iFace)) return
|
||||
if (iFace !in hierarchyDisjointUnions) return
|
||||
|
||||
val iFacesUnion = hierarchyDisjointUnions[iFace]
|
||||
|
||||
val fields = iFacesUnion.mapIndexed { index, unionIFace ->
|
||||
context.defineClassITableInterfaceSlot(unionIFace, index)
|
||||
WasmStructFieldDeclaration(
|
||||
name = "${unionIFace.owner.fqNameWhenAvailable.toString()}.itable",
|
||||
type = WasmRefNullType(WasmHeapType.Type(context.referenceVTableGcType(unionIFace))),
|
||||
isMutable = false
|
||||
)
|
||||
}
|
||||
|
||||
val struct = WasmStructDeclaration(
|
||||
name = "classITable",
|
||||
fields = fields,
|
||||
superType = null
|
||||
)
|
||||
|
||||
iFacesUnion.forEach {
|
||||
context.defineClassITableGcType(it, struct)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createVirtualTableStruct(
|
||||
methods: List<VirtualMethodMetadata>,
|
||||
name: String,
|
||||
superType: WasmSymbolReadOnly<WasmTypeDeclaration>? = null,
|
||||
): WasmStructDeclaration {
|
||||
val tableFields = methods.map {
|
||||
WasmStructFieldDeclaration(
|
||||
name = it.signature.name.asString(),
|
||||
type = WasmRefNullType(WasmHeapType.Type(context.referenceFunctionType(it.function.symbol))),
|
||||
isMutable = false
|
||||
)
|
||||
}
|
||||
|
||||
return WasmStructDeclaration(
|
||||
name = name,
|
||||
fields = tableFields,
|
||||
superType = superType,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createVTable(metadata: ClassMetadata) {
|
||||
val klass = metadata.klass
|
||||
val symbol = klass.symbol
|
||||
val vtableName = "${klass.fqNameWhenAvailable}.vtable"
|
||||
val vtableStruct = createVirtualTableStruct(
|
||||
metadata.virtualMethods,
|
||||
vtableName,
|
||||
superType = metadata.superClass?.klass?.symbol?.let(context::referenceVTableGcType)
|
||||
)
|
||||
context.defineVTableGcType(metadata.klass.symbol, vtableStruct)
|
||||
|
||||
if (klass.isAbstractOrSealed) return
|
||||
|
||||
val vTableTypeReference = context.referenceVTableGcType(symbol)
|
||||
val vTableRefGcType = WasmRefType(WasmHeapType.Type(vTableTypeReference))
|
||||
|
||||
val initVTableGlobal = buildWasmExpression {
|
||||
metadata.virtualMethods.forEachIndexed { i, method ->
|
||||
if (method.function.modality != Modality.ABSTRACT) {
|
||||
buildInstr(WasmOp.REF_FUNC, WasmImmediate.FuncIdx(context.referenceFunction(method.function.symbol)))
|
||||
} else {
|
||||
check(allowIncompleteImplementations) {
|
||||
"Cannot find class implementation of method ${method.signature} in class ${klass.fqNameWhenAvailable}"
|
||||
}
|
||||
//This erased by DCE so abstract version appeared in non-abstract class
|
||||
buildRefNull(vtableStruct.fields[i].type.getHeapType())
|
||||
}
|
||||
}
|
||||
buildStructNew(vTableTypeReference)
|
||||
}
|
||||
context.defineGlobalVTable(
|
||||
irClass = symbol,
|
||||
wasmGlobal = WasmGlobal(vtableName, vTableRefGcType, false, initVTableGlobal)
|
||||
)
|
||||
}
|
||||
|
||||
private fun createClassITable(metadata: ClassMetadata) {
|
||||
val klass = metadata.klass
|
||||
if (klass.isAbstractOrSealed) return
|
||||
val supportedInterface = metadata.interfaces.firstOrNull()?.symbol ?: return
|
||||
|
||||
createDeclarationByInterface(supportedInterface)
|
||||
|
||||
val classInterfaceType = context.referenceClassITableGcType(supportedInterface)
|
||||
val interfaceList = hierarchyDisjointUnions[supportedInterface]
|
||||
|
||||
val initITableGlobal = buildWasmExpression {
|
||||
for (iFace in interfaceList) {
|
||||
val iFaceVTableGcType = context.referenceVTableGcType(iFace)
|
||||
val iFaceVTableGcNullHeapType = WasmHeapType.Type(iFaceVTableGcType)
|
||||
|
||||
if (!metadata.interfaces.contains(iFace.owner)) {
|
||||
buildRefNull(iFaceVTableGcNullHeapType)
|
||||
continue
|
||||
}
|
||||
|
||||
for (method in context.getInterfaceMetadata(iFace).methods) {
|
||||
val classMethod: VirtualMethodMetadata? = metadata.virtualMethods
|
||||
.find { it.signature == method.signature && it.function.modality != Modality.ABSTRACT } // TODO: Use map
|
||||
|
||||
if (classMethod == null && !allowIncompleteImplementations) {
|
||||
error("Cannot find interface implementation of method ${method.signature} in class ${klass.fqNameWhenAvailable}")
|
||||
}
|
||||
|
||||
if (classMethod != null) {
|
||||
val functionTypeReference = context.referenceFunction(classMethod.function.symbol)
|
||||
buildInstr(WasmOp.REF_FUNC, WasmImmediate.FuncIdx(functionTypeReference))
|
||||
} else {
|
||||
//This erased by DCE so abstract version appeared in non-abstract class
|
||||
buildRefNull(WasmHeapType.Type(context.referenceFunctionType(method.function.symbol)))
|
||||
}
|
||||
}
|
||||
buildStructNew(iFaceVTableGcType)
|
||||
}
|
||||
buildStructNew(classInterfaceType)
|
||||
}
|
||||
|
||||
val wasmClassIFaceGlobal = WasmGlobal(
|
||||
name = "${klass.fqNameWhenAvailable.toString()}.classITable",
|
||||
type = WasmRefType(WasmHeapType.Type(classInterfaceType)),
|
||||
isMutable = false,
|
||||
init = initITableGlobal
|
||||
)
|
||||
context.defineGlobalClassITable(klass.symbol, wasmClassIFaceGlobal)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (declaration.isAnnotationClass) return
|
||||
if (declaration.isExternal) return
|
||||
val symbol = declaration.symbol
|
||||
|
||||
|
||||
// Handle arrays
|
||||
declaration.getWasmArrayAnnotation()?.let { wasmArrayAnnotation ->
|
||||
val nameStr = declaration.fqNameWhenAvailable.toString()
|
||||
@@ -189,60 +319,43 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
return
|
||||
}
|
||||
|
||||
val nameStr = declaration.fqNameWhenAvailable.toString()
|
||||
|
||||
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)))
|
||||
if (symbol in hierarchyDisjointUnions) {
|
||||
val vtableStruct = createVirtualTableStruct(
|
||||
methods = context.getInterfaceMetadata(symbol).methods,
|
||||
name = "$nameStr.itable"
|
||||
)
|
||||
context.defineInterfaceMethodTable(methodSymbol, table)
|
||||
context.defineVTableGcType(symbol, vtableStruct)
|
||||
}
|
||||
context.registerInterface(symbol)
|
||||
} else {
|
||||
val nameStr = declaration.fqNameWhenAvailable.toString()
|
||||
val metadata = context.getClassMetadata(symbol)
|
||||
|
||||
createVTable(metadata)
|
||||
createClassITable(metadata)
|
||||
|
||||
val vtableRefGcType = WasmRefType(WasmHeapType.Type(context.referenceVTableGcType(symbol)))
|
||||
val classITableRefGcType = WasmRefNullType(WasmHeapType.Simple.Data)
|
||||
val fields = mutableListOf<WasmStructFieldDeclaration>()
|
||||
fields.add(WasmStructFieldDeclaration("vtable", vtableRefGcType, false))
|
||||
fields.add(WasmStructFieldDeclaration("itable", classITableRefGcType, false))
|
||||
declaration.allFields(irBuiltIns).mapTo(fields) {
|
||||
WasmStructFieldDeclaration(
|
||||
name = it.name.toString(),
|
||||
type = context.transformFieldType(it.type),
|
||||
isMutable = true
|
||||
)
|
||||
}
|
||||
|
||||
val superClass = metadata.superClass
|
||||
val structType = WasmStructDeclaration(
|
||||
name = nameStr,
|
||||
fields = declaration.allFields(irBuiltIns).map {
|
||||
WasmStructFieldDeclaration(
|
||||
name = it.name.toString(),
|
||||
type = context.transformFieldType(it.type),
|
||||
isMutable = true
|
||||
)
|
||||
},
|
||||
superClass?.let { context.referenceGcType(superClass.klass.symbol) }
|
||||
fields = fields,
|
||||
superType = superClass?.let { context.referenceGcType(superClass.klass.symbol) }
|
||||
)
|
||||
|
||||
context.defineGcType(symbol, structType)
|
||||
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 && it.function.modality != Modality.ABSTRACT } // TODO: Use map
|
||||
|
||||
if (classMethod == null && !allowIncompleteImplementations) {
|
||||
error("Cannot find class implementation of method ${method.signature} in class ${declaration.fqNameWhenAvailable}")
|
||||
}
|
||||
val matchedMethod = classMethod?.let { context.referenceFunction(it.function.symbol) }
|
||||
method.function.symbol as IrFunctionSymbol to matchedMethod
|
||||
}
|
||||
|
||||
context.registerInterfaceImplementationMethod(
|
||||
interfaceImplementation,
|
||||
table
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (member in declaration.declarations) {
|
||||
@@ -251,15 +364,13 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
}
|
||||
|
||||
private fun binaryDataStruct(classMetadata: ClassMetadata): ConstantDataStruct {
|
||||
val invalidIndex = -1
|
||||
|
||||
val fqnShouldBeEmitted = context.backendContext.configuration.languageVersionSettings.getFlag(allowFullyQualifiedNameInKClass)
|
||||
//TODO("FqName for inner classes could be invalid due to topping it out from outer class")
|
||||
val packageName = if (fqnShouldBeEmitted) classMetadata.klass.kotlinFqName.parentOrNull()?.asString() ?: "" else ""
|
||||
val simpleName = classMetadata.klass.kotlinFqName.shortName().asString()
|
||||
val typeInfo = ConstantDataStruct(
|
||||
"TypeInfo",
|
||||
listOf(
|
||||
name = "TypeInfo",
|
||||
elements = listOf(
|
||||
ConstantDataIntField("TypePackageNameLength", packageName.length),
|
||||
ConstantDataIntField("TypePackageNamePtr", context.referenceStringLiteral(packageName)),
|
||||
ConstantDataIntField("TypeNameLength", simpleName.length),
|
||||
@@ -272,40 +383,17 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
ConstantDataIntField("SuperTypeId", context.referenceClassId(it.symbol))
|
||||
} ?: ConstantDataIntField("SuperTypeId", -1)
|
||||
|
||||
val vtableSizeField = ConstantDataIntField(
|
||||
"V-table length",
|
||||
classMetadata.virtualMethods.size
|
||||
)
|
||||
|
||||
val vtableArray = ConstantDataIntArray(
|
||||
"V-table",
|
||||
classMetadata.virtualMethods.map {
|
||||
if (it.function.modality == Modality.ABSTRACT) {
|
||||
WasmSymbol(invalidIndex)
|
||||
} else {
|
||||
context.referenceVirtualFunctionId(it.function.symbol)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val interfaceTablePtr = ConstantDataIntField(
|
||||
"interfaceTablePtr",
|
||||
context.referenceInterfaceTableAddress(classMetadata.klass.symbol)
|
||||
)
|
||||
val typeInfoContent = mutableListOf(typeInfo, superTypeId)
|
||||
if (!classMetadata.klass.isAbstractOrSealed) {
|
||||
typeInfoContent.add(interfaceTable(classMetadata))
|
||||
}
|
||||
|
||||
return ConstantDataStruct(
|
||||
"Class TypeInfo: ${classMetadata.klass.fqNameWhenAvailable} ",
|
||||
listOf(
|
||||
typeInfo,
|
||||
superTypeId,
|
||||
interfaceTablePtr,
|
||||
vtableSizeField,
|
||||
vtableArray,
|
||||
)
|
||||
name = "Class TypeInfo: ${classMetadata.klass.fqNameWhenAvailable} ",
|
||||
elements = typeInfoContent
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun interfaceTable(classMetadata: ClassMetadata): ConstantDataStruct {
|
||||
val interfaces = classMetadata.interfaces
|
||||
val size = ConstantDataIntField("size", interfaces.size)
|
||||
@@ -313,20 +401,10 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
"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,
|
||||
)
|
||||
name = "Class interface table: ${classMetadata.klass.fqNameWhenAvailable} ",
|
||||
elements = listOf(size, interfaceIds)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -357,7 +435,7 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al
|
||||
init = initBody
|
||||
)
|
||||
|
||||
context.defineGlobal(declaration.symbol, global)
|
||||
context.defineGlobalField(declaration.symbol, global)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -44,8 +44,8 @@ class WasmTypeTransformer(
|
||||
toWasmValueType()
|
||||
}
|
||||
|
||||
fun IrType.toWasmGcRefType(): WasmType =
|
||||
WasmRefNullType(WasmHeapType.Type(context.referenceGcType(getRuntimeClass?.symbol ?: builtIns.anyClass)))
|
||||
private fun IrType.toWasmGcRefType(): WasmType =
|
||||
WasmRefNullType(WasmHeapType.Type(context.referenceGcType(getRuntimeClass(context.backendContext.irBuiltIns).symbol)))
|
||||
|
||||
fun IrType.toBoxedInlineClassType(): WasmType =
|
||||
toWasmGcRefType()
|
||||
@@ -122,8 +122,5 @@ fun isBuiltInWasmRefType(type: IrType): Boolean {
|
||||
fun isExternalType(type: IrType): Boolean =
|
||||
type.erasedUpperBound?.isExternal ?: false
|
||||
|
||||
val IrType.getRuntimeClass: IrClass?
|
||||
get() = erasedUpperBound.let {
|
||||
if (it?.isInterface == true) null
|
||||
else it
|
||||
}
|
||||
fun IrType.getRuntimeClass(irBuiltIns: IrBuiltIns): IrClass =
|
||||
erasedUpperBound?.takeIf { !it.isInterface } ?: irBuiltIns.anyClass.owner
|
||||
+11
-11
@@ -6,13 +6,9 @@
|
||||
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.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
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.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
|
||||
@@ -22,17 +18,20 @@ interface WasmBaseCodegenContext {
|
||||
val scratchMemAddr: WasmSymbol<Int>
|
||||
|
||||
fun referenceFunction(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunction>
|
||||
fun referenceGlobal(irField: IrFieldSymbol): WasmSymbol<WasmGlobal>
|
||||
fun referenceGlobalField(irField: IrFieldSymbol): WasmSymbol<WasmGlobal>
|
||||
fun referenceGlobalVTable(irClass: IrClassSymbol): WasmSymbol<WasmGlobal>
|
||||
fun referenceGlobalClassITable(irClass: IrClassSymbol): WasmSymbol<WasmGlobal>
|
||||
fun referenceGcType(irClass: IrClassSymbol): WasmSymbol<WasmTypeDeclaration>
|
||||
fun referenceVTableGcType(irClass: IrClassSymbol): WasmSymbol<WasmTypeDeclaration>
|
||||
fun referenceClassITableGcType(irClass: IrClassSymbol): WasmSymbol<WasmTypeDeclaration>
|
||||
fun defineClassITableGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration)
|
||||
fun isAlreadyDefinedClassITableGcType(irClass: IrClassSymbol): Boolean
|
||||
fun referenceClassITableInterfaceSlot(irClass: IrClassSymbol): WasmSymbol<Int>
|
||||
fun defineClassITableInterfaceSlot(irClass: IrClassSymbol, slot: Int)
|
||||
fun referenceFunctionType(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunctionType>
|
||||
|
||||
fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int>
|
||||
fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int>
|
||||
fun referenceVirtualFunctionId(irFunction: IrSimpleFunctionSymbol): WasmSymbol<Int>
|
||||
|
||||
fun referenceSignatureId(signature: WasmSignature): WasmSymbol<Int>
|
||||
|
||||
fun referenceInterfaceTable(irFunction: IrFunctionSymbol): WasmSymbol<WasmTable>
|
||||
|
||||
fun referenceStringLiteral(string: String): WasmSymbol<Int>
|
||||
|
||||
@@ -47,4 +46,5 @@ interface WasmBaseCodegenContext {
|
||||
|
||||
fun getStructFieldRef(field: IrField): WasmSymbol<Int>
|
||||
fun getClassMetadata(irClass: IrClassSymbol): ClassMetadata
|
||||
fun getInterfaceMetadata(irClass: IrClassSymbol): InterfaceMetadata
|
||||
}
|
||||
+35
-168
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
|
||||
@@ -17,24 +16,30 @@ import org.jetbrains.kotlin.wasm.ir.*
|
||||
class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
val functions =
|
||||
ReferencableAndDefinable<IrFunctionSymbol, WasmFunction>()
|
||||
val globals =
|
||||
val globalFields =
|
||||
ReferencableAndDefinable<IrFieldSymbol, WasmGlobal>()
|
||||
val globalVTables =
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmGlobal>()
|
||||
val globalClassITables =
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmGlobal>()
|
||||
val functionTypes =
|
||||
ReferencableAndDefinable<IrFunctionSymbol, WasmFunctionType>()
|
||||
val gcTypes =
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmTypeDeclaration>()
|
||||
val vTableGcTypes =
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmTypeDeclaration>()
|
||||
val classITableGcType =
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmTypeDeclaration>()
|
||||
val classITableInterfaceSlot =
|
||||
ReferencableAndDefinable<IrClassSymbol, Int>()
|
||||
val classIds =
|
||||
ReferencableElements<IrClassSymbol, Int>()
|
||||
val interfaceId =
|
||||
ReferencableElements<IrClassSymbol, Int>()
|
||||
val virtualFunctionId =
|
||||
ReferencableElements<IrFunctionSymbol, Int>()
|
||||
val signatureId =
|
||||
ReferencableElements<WasmSignature, Int>()
|
||||
val stringLiteralId =
|
||||
ReferencableElements<String, Int>()
|
||||
|
||||
val tagFuncType = WasmFunctionType(
|
||||
private val tagFuncType = WasmFunctionType(
|
||||
listOf(
|
||||
WasmRefNullType(WasmHeapType.Type(gcTypes.reference(irBuiltIns.throwableClass)))
|
||||
),
|
||||
@@ -42,34 +47,7 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
)
|
||||
val tag = WasmTag(tagFuncType)
|
||||
|
||||
|
||||
val classes = mutableListOf<IrClassSymbol>()
|
||||
val interfaces = mutableListOf<IrClassSymbol>()
|
||||
val virtualFunctions = mutableListOf<IrSimpleFunctionSymbol>()
|
||||
val signatures = LinkedHashSet<WasmSignature>()
|
||||
|
||||
val typeInfo =
|
||||
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 typeInfo = ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>()
|
||||
|
||||
val exports = mutableListOf<WasmExport<*>>()
|
||||
|
||||
@@ -82,7 +60,7 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
val initFunctions = mutableListOf<FunWithPriority>()
|
||||
|
||||
val scratchMemAddr = WasmSymbol<Int>()
|
||||
val scratchMemSizeInBytes = 65_536
|
||||
private val scratchMemSizeInBytes = 65_536
|
||||
|
||||
open class ReferencableElements<Ir, Wasm : Any> {
|
||||
val unbound = mutableMapOf<Ir, WasmSymbol<Wasm>>()
|
||||
@@ -117,9 +95,13 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
fun linkWasmCompiledFragments(): WasmModule {
|
||||
bind(functions.unbound, functions.defined)
|
||||
bind(globals.unbound, globals.defined)
|
||||
|
||||
bind(globalFields.unbound, globalFields.defined)
|
||||
bind(globalVTables.unbound, globalVTables.defined)
|
||||
bind(gcTypes.unbound, gcTypes.defined)
|
||||
bind(vTableGcTypes.unbound, vTableGcTypes.defined)
|
||||
bind(classITableGcType.unbound, classITableGcType.defined)
|
||||
bind(classITableInterfaceSlot.unbound, classITableInterfaceSlot.defined)
|
||||
bind(globalClassITables.unbound, globalClassITables.defined)
|
||||
|
||||
// Associate function types to a single canonical function type
|
||||
val canonicalFunctionTypes =
|
||||
@@ -139,13 +121,6 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
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
|
||||
}
|
||||
|
||||
val stringDataSectionStart = currentDataSectionAddress
|
||||
val stringDataSectionBytes = mutableListOf<Byte>()
|
||||
val stringAddrs = mutableMapOf<String, Int>()
|
||||
@@ -163,107 +138,12 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
currentDataSectionAddress += scratchMemSizeInBytes
|
||||
|
||||
bind(classIds.unbound, klassIds)
|
||||
bind(referencedClassITableAddresses.unbound, interfaceTableAddresses)
|
||||
bind(stringLiteralId.unbound, stringAddrs)
|
||||
bindIndices(virtualFunctionId.unbound, virtualFunctions)
|
||||
bindIndices(signatureId.unbound, signatures.toList())
|
||||
bindIndices(interfaceId.unbound, interfaces)
|
||||
|
||||
val interfaceImplementationIds = mutableMapOf<InterfaceImplementation, Int>()
|
||||
val numberOfInterfaceImpls = mutableMapOf<IrClassSymbol, Int>()
|
||||
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)
|
||||
interfaceId.unbound.onEachIndexed { index, entry -> entry.value.bind(index) }
|
||||
|
||||
val data = typeInfo.buildData(address = { klassIds.getValue(it) }) +
|
||||
definedClassITableData.buildData(address = { interfaceTableAddresses.getValue(it) }) +
|
||||
WasmData(WasmDataMode.Active(0, stringDataSectionStart), stringDataSectionBytes.toByteArray())
|
||||
|
||||
val logTypeInfo = false
|
||||
if (logTypeInfo) {
|
||||
println("Signatures: ")
|
||||
for ((index, signature: WasmSignature) in signatures.withIndex()) {
|
||||
println(" -- $index $signature")
|
||||
}
|
||||
|
||||
println("Interfaces: ")
|
||||
for ((index, iface: IrClassSymbol) in interfaces.withIndex()) {
|
||||
println(" -- $index ${iface.owner.fqNameWhenAvailable}")
|
||||
}
|
||||
|
||||
println("Interfaces implementations: ")
|
||||
for ((interfaceImpl, index: Int) in interfaceImplementationIds) {
|
||||
println(
|
||||
" -- $index" +
|
||||
" Interface: ${interfaceImpl.irInterface.owner.fqNameWhenAvailable}" +
|
||||
" Class: ${interfaceImpl.irClass.owner.fqNameWhenAvailable}"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
println("Virtual functions: ")
|
||||
for ((index, vf: IrSimpleFunctionSymbol) in virtualFunctions.withIndex()) {
|
||||
println(" -- $index ${vf.owner.fqNameWhenAvailable}")
|
||||
}
|
||||
|
||||
println(
|
||||
ConstantDataStruct("typeInfo", typeInfo.elements).dump("", 0)
|
||||
)
|
||||
}
|
||||
|
||||
val table = WasmTable(
|
||||
limits = WasmLimits(virtualFunctions.size.toUInt(), virtualFunctions.size.toUInt()),
|
||||
elementType = WasmFuncRef,
|
||||
)
|
||||
|
||||
val offsetExpr = mutableListOf<WasmInstr>()
|
||||
WasmIrExpressionBuilder(offsetExpr).buildConstI32(0)
|
||||
|
||||
val elements = WasmElement(
|
||||
WasmFuncRef,
|
||||
values = virtualFunctions.map {
|
||||
WasmTable.Value.Function(functions.defined.getValue(it))
|
||||
},
|
||||
WasmElement.Mode.Active(table, offsetExpr)
|
||||
)
|
||||
|
||||
val interfaceTableElementsLists = interfaceMethodTables.defined.keys.associateWith {
|
||||
mutableMapOf<Int, WasmSymbol<WasmFunction>?>()
|
||||
}
|
||||
|
||||
for ((ii: InterfaceImplementation, implId: Int) in interfaceImplementationIds) {
|
||||
for ((interfaceFunction: IrFunctionSymbol, wasmFunction: WasmSymbol<WasmFunction>?) in interfaceImplementationsMethods[ii]!!) {
|
||||
interfaceTableElementsLists[interfaceFunction]!![implId] = wasmFunction
|
||||
}
|
||||
}
|
||||
|
||||
val interfaceTableElements = interfaceTableElementsLists.map { (interfaceFunction, methods) ->
|
||||
val methodTable = interfaceMethodTables.defined[interfaceFunction]!!
|
||||
val type = methodTable.elementType
|
||||
val functions = MutableList(methods.size) { idx ->
|
||||
val wasmFunc = methods[idx]
|
||||
val expression = buildWasmExpression {
|
||||
if (wasmFunc != null) {
|
||||
buildInstr(WasmOp.REF_FUNC, WasmImmediate.FuncIdx(wasmFunc))
|
||||
} else {
|
||||
//DCE could remove implementation from class, so we should to put a stub into method implementations table
|
||||
buildRefNull(type.getHeapType())
|
||||
}
|
||||
}
|
||||
WasmTable.Value.Expression(expression)
|
||||
}
|
||||
WasmElement(
|
||||
type,
|
||||
values = functions,
|
||||
WasmElement.Mode.Active(methodTable, offsetExpr)
|
||||
)
|
||||
}
|
||||
|
||||
val masterInitFunctionType = WasmFunctionType(emptyList(), emptyList())
|
||||
val masterInitFunction = WasmFunction.Defined("__init", WasmSymbol(masterInitFunctionType))
|
||||
with(WasmIrExpressionBuilder(masterInitFunction.instructions)) {
|
||||
@@ -273,11 +153,6 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
}
|
||||
exports += WasmExport.Function("__init", masterInitFunction)
|
||||
|
||||
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()))
|
||||
@@ -297,21 +172,30 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
}
|
||||
}
|
||||
|
||||
val sortedGcTypes = gcTypes.elements.sortedBy(::wasmTypeDeclarationOrderKey)
|
||||
val typeDeclarations = mutableListOf<WasmTypeDeclaration>()
|
||||
typeDeclarations.addAll(vTableGcTypes.elements)
|
||||
typeDeclarations.addAll(gcTypes.elements)
|
||||
typeDeclarations.addAll(classITableGcType.elements.distinct())
|
||||
typeDeclarations.sortBy(::wasmTypeDeclarationOrderKey)
|
||||
|
||||
val globals = mutableListOf<WasmGlobal>()
|
||||
globals.addAll(globalFields.elements)
|
||||
globals.addAll(globalVTables.elements)
|
||||
globals.addAll(globalClassITables.elements.distinct())
|
||||
|
||||
val module = WasmModule(
|
||||
functionTypes = canonicalFunctionTypes.values.toList() + tagFuncType + masterInitFunctionType,
|
||||
gcTypes = sortedGcTypes,
|
||||
gcTypes = typeDeclarations,
|
||||
gcTypesInRecursiveGroup = true,
|
||||
importsInOrder = importedFunctions,
|
||||
importedFunctions = importedFunctions,
|
||||
definedFunctions = functions.elements.filterIsInstance<WasmFunction.Defined>() + masterInitFunction,
|
||||
tables = listOf(table) + interfaceMethodTables.elements,
|
||||
tables = emptyList(),
|
||||
memories = listOf(memory),
|
||||
globals = globals.elements,
|
||||
globals = globals,
|
||||
exports = exports,
|
||||
startFunction = null, // Module is initialized via export call
|
||||
elements = listOf(elements) + interfaceTableElements,
|
||||
elements = emptyList(),
|
||||
data = data,
|
||||
tags = listOf(tag)
|
||||
)
|
||||
@@ -338,18 +222,6 @@ private fun irSymbolDebugDump(symbol: Any?): String =
|
||||
else -> symbol.toString()
|
||||
}
|
||||
|
||||
fun <IrSymbolType> bindIndices(
|
||||
unbound: Map<IrSymbolType, WasmSymbol<Int>>,
|
||||
ordered: List<IrSymbolType>
|
||||
) {
|
||||
unbound.forEach { (irSymbol, wasmSymbol) ->
|
||||
val index = ordered.indexOf(irSymbol)
|
||||
if (index == -1)
|
||||
error("Can't link symbol with indices ${irSymbolDebugDump(irSymbol)}")
|
||||
wasmSymbol.bind(index)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun WasmCompiledModuleFragment.ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>.buildData(address: (IrClassSymbol) -> Int): List<WasmData> {
|
||||
return elements.map {
|
||||
val id = address(wasmToIr.getValue(it))
|
||||
@@ -359,11 +231,6 @@ inline fun WasmCompiledModuleFragment.ReferencableAndDefinable<IrClassSymbol, Co
|
||||
}
|
||||
}
|
||||
|
||||
data class InterfaceImplementation(
|
||||
val irInterface: IrClassSymbol,
|
||||
val irClass: IrClassSymbol
|
||||
)
|
||||
|
||||
fun alignUp(x: Int, alignment: Int): Int {
|
||||
assert(alignment and (alignment - 1) == 0) { "power of 2 expected" }
|
||||
return (x + alignment - 1) and (alignment - 1).inv()
|
||||
|
||||
+2
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.wasm.ir.WasmInstr
|
||||
import org.jetbrains.kotlin.wasm.ir.WasmLocal
|
||||
|
||||
enum class LoopLabelType { BREAK, CONTINUE }
|
||||
enum class SyntheticLocalType { IS_INTERFACE_PARAMETER }
|
||||
|
||||
interface WasmFunctionCodegenContext : WasmBaseCodegenContext {
|
||||
val irFunction: IrFunction
|
||||
@@ -20,6 +21,7 @@ interface WasmFunctionCodegenContext : WasmBaseCodegenContext {
|
||||
fun defineLocal(irValueDeclaration: IrValueSymbol)
|
||||
fun referenceLocal(irValueDeclaration: IrValueSymbol): WasmLocal
|
||||
fun referenceLocal(index: Int): WasmLocal
|
||||
fun referenceLocal(type: SyntheticLocalType): WasmLocal
|
||||
|
||||
fun defineLoopLevel(irLoop: IrLoop, labelType: LoopLabelType, level: Int)
|
||||
fun referenceLoopLevel(irLoop: IrLoop, labelType: LoopLabelType): Int
|
||||
|
||||
+12
@@ -27,6 +27,7 @@ class WasmFunctionCodegenContextImpl(
|
||||
get() = 0
|
||||
|
||||
private val wasmLocals = LinkedHashMap<IrValueSymbol, WasmLocal>()
|
||||
private val wasmSyntheticLocals = LinkedHashMap<SyntheticLocalType, WasmLocal>()
|
||||
private val loopLevels = LinkedHashMap<Pair<IrLoop, LoopLabelType>, Int>()
|
||||
|
||||
override fun defineLocal(irValueDeclaration: IrValueSymbol) {
|
||||
@@ -52,6 +53,17 @@ class WasmFunctionCodegenContextImpl(
|
||||
return wasmFunction.locals[index]
|
||||
}
|
||||
|
||||
override fun referenceLocal(type: SyntheticLocalType): WasmLocal = wasmSyntheticLocals.getOrPut(type) {
|
||||
WasmLocal(
|
||||
wasmFunction.locals.size,
|
||||
type.name,
|
||||
WasmRefNullType(WasmHeapType.Type(referenceGcType(backendContext.irBuiltIns.anyClass))),
|
||||
isParameter = false
|
||||
).also {
|
||||
wasmFunction.locals += it
|
||||
}
|
||||
}
|
||||
|
||||
override fun defineLoopLevel(irLoop: IrLoop, labelType: LoopLabelType, level: Int) {
|
||||
val loopKey = Pair(irLoop, labelType)
|
||||
assert(loopKey !in loopLevels) { "Redefinition of loop" }
|
||||
|
||||
+5
-19
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
||||
|
||||
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.ir.symbols.*
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
|
||||
/**
|
||||
@@ -16,27 +13,16 @@ import org.jetbrains.kotlin.wasm.ir.*
|
||||
*/
|
||||
interface WasmModuleCodegenContext : WasmBaseCodegenContext {
|
||||
fun defineFunction(irFunction: IrFunctionSymbol, wasmFunction: WasmFunction)
|
||||
fun defineGlobal(irField: IrFieldSymbol, wasmGlobal: WasmGlobal)
|
||||
fun defineGlobalField(irField: IrFieldSymbol, wasmGlobal: WasmGlobal)
|
||||
fun defineGlobalVTable(irClass: IrClassSymbol, wasmGlobal: WasmGlobal)
|
||||
fun defineGlobalClassITable(irClass: IrClassSymbol, wasmGlobal: WasmGlobal)
|
||||
fun defineGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration)
|
||||
fun defineVTableGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration)
|
||||
fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType)
|
||||
fun defineInterfaceMethodTable(irFunction: IrFunctionSymbol, wasmTable: WasmTable)
|
||||
fun addJsFun(importName: String, jsCode: String)
|
||||
|
||||
fun registerInitFunction(wasmFunction: WasmFunction, priority: String)
|
||||
fun addExport(wasmExport: WasmExport<*>)
|
||||
|
||||
fun registerVirtualFunction(irFunction: IrSimpleFunctionSymbol)
|
||||
fun registerInterface(irInterface: IrClassSymbol)
|
||||
fun registerClass(irClass: IrClassSymbol)
|
||||
|
||||
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>
|
||||
}
|
||||
+63
-70
@@ -6,19 +6,12 @@
|
||||
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.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
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.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
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.*
|
||||
|
||||
@@ -70,10 +63,6 @@ class WasmModuleCodegenContextImpl(
|
||||
wasmFragment.typeInfo.define(irClass, typeInfo)
|
||||
}
|
||||
|
||||
override fun generateInterfaceTable(irClass: IrClassSymbol, table: ConstantDataElement) {
|
||||
wasmFragment.definedClassITableData.define(irClass, table)
|
||||
}
|
||||
|
||||
override fun registerInitFunction(wasmFunction: WasmFunction, priority: String) {
|
||||
wasmFragment.initFunctions += WasmCompiledModuleFragment.FunWithPriority(wasmFunction, priority)
|
||||
}
|
||||
@@ -82,51 +71,34 @@ class WasmModuleCodegenContextImpl(
|
||||
wasmFragment.exports += wasmExport
|
||||
}
|
||||
|
||||
override fun registerVirtualFunction(irFunction: IrSimpleFunctionSymbol) {
|
||||
wasmFragment.virtualFunctions += irFunction
|
||||
}
|
||||
|
||||
override fun registerInterface(irInterface: IrClassSymbol) {
|
||||
wasmFragment.interfaces += irInterface
|
||||
}
|
||||
|
||||
override fun registerClass(irClass: IrClassSymbol) {
|
||||
wasmFragment.classes += irClass
|
||||
}
|
||||
|
||||
override fun defineFunction(irFunction: IrFunctionSymbol, wasmFunction: WasmFunction) {
|
||||
wasmFragment.functions.define(irFunction, wasmFunction)
|
||||
}
|
||||
|
||||
override fun defineGlobal(irField: IrFieldSymbol, wasmGlobal: WasmGlobal) {
|
||||
wasmFragment.globals.define(irField, wasmGlobal)
|
||||
override fun defineGlobalField(irField: IrFieldSymbol, wasmGlobal: WasmGlobal) {
|
||||
wasmFragment.globalFields.define(irField, wasmGlobal)
|
||||
}
|
||||
|
||||
override fun defineGlobalVTable(irClass: IrClassSymbol, wasmGlobal: WasmGlobal) {
|
||||
wasmFragment.globalVTables.define(irClass, wasmGlobal)
|
||||
}
|
||||
|
||||
override fun defineGlobalClassITable(irClass: IrClassSymbol, wasmGlobal: WasmGlobal) {
|
||||
wasmFragment.globalClassITables.define(irClass, wasmGlobal)
|
||||
}
|
||||
|
||||
override fun defineGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration) {
|
||||
wasmFragment.gcTypes.define(irClass, wasmType)
|
||||
}
|
||||
|
||||
override fun defineVTableGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration) {
|
||||
wasmFragment.vTableGcTypes.define(irClass, wasmType)
|
||||
}
|
||||
|
||||
override fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: 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>()
|
||||
override fun getClassMetadata(irClass: IrClassSymbol): ClassMetadata =
|
||||
classMetadataCache.getOrPut(irClass) {
|
||||
@@ -139,18 +111,59 @@ class WasmModuleCodegenContextImpl(
|
||||
)
|
||||
}
|
||||
|
||||
private val interfaceMetadataCache = mutableMapOf<IrClassSymbol, InterfaceMetadata>()
|
||||
override fun getInterfaceMetadata(irClass: IrClassSymbol): InterfaceMetadata =
|
||||
interfaceMetadataCache.getOrPut(irClass) { InterfaceMetadata(irClass.owner, backendContext.irBuiltIns) }
|
||||
|
||||
override fun referenceFunction(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunction> =
|
||||
wasmFragment.functions.reference(irFunction)
|
||||
|
||||
override fun referenceGlobal(irField: IrFieldSymbol): WasmSymbol<WasmGlobal> =
|
||||
wasmFragment.globals.reference(irField)
|
||||
override fun referenceGlobalField(irField: IrFieldSymbol): WasmSymbol<WasmGlobal> =
|
||||
wasmFragment.globalFields.reference(irField)
|
||||
|
||||
override fun referenceGcType(irClass: IrClassSymbol): WasmSymbol<WasmTypeDeclaration> {
|
||||
override fun referenceGlobalVTable(irClass: IrClassSymbol): WasmSymbol<WasmGlobal> =
|
||||
wasmFragment.globalVTables.reference(irClass)
|
||||
|
||||
override fun referenceGlobalClassITable(irClass: IrClassSymbol): WasmSymbol<WasmGlobal> =
|
||||
wasmFragment.globalClassITables.reference(irClass)
|
||||
|
||||
private fun referenceNonNothingType(
|
||||
irClass: IrClassSymbol,
|
||||
from: WasmCompiledModuleFragment.ReferencableAndDefinable<IrClassSymbol, WasmTypeDeclaration>
|
||||
): WasmSymbol<WasmTypeDeclaration> {
|
||||
val type = irClass.defaultType
|
||||
require(!type.isNothing()) {
|
||||
"Can't reference Nothing type"
|
||||
}
|
||||
return wasmFragment.gcTypes.reference(irClass)
|
||||
return from.reference(irClass)
|
||||
}
|
||||
|
||||
override fun referenceGcType(irClass: IrClassSymbol): WasmSymbol<WasmTypeDeclaration> =
|
||||
referenceNonNothingType(irClass, wasmFragment.gcTypes)
|
||||
|
||||
override fun referenceVTableGcType(irClass: IrClassSymbol): WasmSymbol<WasmTypeDeclaration> =
|
||||
referenceNonNothingType(irClass, wasmFragment.vTableGcTypes)
|
||||
|
||||
override fun referenceClassITableGcType(irClass: IrClassSymbol): WasmSymbol<WasmTypeDeclaration> =
|
||||
referenceNonNothingType(irClass, wasmFragment.classITableGcType)
|
||||
|
||||
override fun defineClassITableGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration) {
|
||||
wasmFragment.classITableGcType.define(irClass, wasmType)
|
||||
}
|
||||
|
||||
override fun isAlreadyDefinedClassITableGcType(irClass: IrClassSymbol): Boolean =
|
||||
wasmFragment.classITableGcType.defined.keys.contains(irClass)
|
||||
|
||||
override fun referenceClassITableInterfaceSlot(irClass: IrClassSymbol): WasmSymbol<Int> {
|
||||
val type = irClass.defaultType
|
||||
require(!type.isNothing()) {
|
||||
"Can't reference Nothing type"
|
||||
}
|
||||
return wasmFragment.classITableInterfaceSlot.reference(irClass)
|
||||
}
|
||||
|
||||
override fun defineClassITableInterfaceSlot(irClass: IrClassSymbol, slot: Int) {
|
||||
wasmFragment.classITableInterfaceSlot.define(irClass, slot)
|
||||
}
|
||||
|
||||
override fun referenceFunctionType(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunctionType> =
|
||||
@@ -159,35 +172,14 @@ class WasmModuleCodegenContextImpl(
|
||||
override fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int> =
|
||||
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> {
|
||||
return wasmFragment.interfaceId.reference(irInterface)
|
||||
}
|
||||
|
||||
override fun referenceVirtualFunctionId(irFunction: IrSimpleFunctionSymbol): WasmSymbol<Int> {
|
||||
if (irFunction.owner.modality == Modality.ABSTRACT)
|
||||
error("Abstract functions are not stored in table")
|
||||
return wasmFragment.virtualFunctionId.reference(irFunction)
|
||||
}
|
||||
|
||||
override fun referenceSignatureId(signature: WasmSignature): WasmSymbol<Int> {
|
||||
wasmFragment.signatures.add(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> {
|
||||
val klass = field.parentAsClass
|
||||
val metadata = getClassMetadata(klass.symbol)
|
||||
val fieldId = metadata.fields.indexOf(field)
|
||||
val fieldId = metadata.fields.indexOf(field) + 2 //Implicit vtable and vtable field
|
||||
return WasmSymbol(fieldId)
|
||||
}
|
||||
|
||||
@@ -195,4 +187,5 @@ class WasmModuleCodegenContextImpl(
|
||||
wasmFragment.jsFuns +=
|
||||
WasmCompiledModuleFragment.JsCodeSnippet(importName = importName, jsCode = jsCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+42
-14
@@ -6,9 +6,16 @@
|
||||
package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.DisjointUnions
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.getWasmArrayAnnotation
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.isAbstractOrSealed
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
class WasmModuleFragmentGenerator(
|
||||
@@ -16,28 +23,49 @@ class WasmModuleFragmentGenerator(
|
||||
wasmModuleFragment: WasmCompiledModuleFragment,
|
||||
allowIncompleteImplementations: Boolean,
|
||||
) {
|
||||
private val hierarchyDisjointUnions = DisjointUnions<IrClassSymbol>()
|
||||
|
||||
private val declarationGenerator =
|
||||
DeclarationGenerator(
|
||||
WasmModuleCodegenContextImpl(
|
||||
backendContext,
|
||||
wasmModuleFragment,
|
||||
),
|
||||
allowIncompleteImplementations
|
||||
allowIncompleteImplementations,
|
||||
hierarchyDisjointUnions,
|
||||
)
|
||||
|
||||
private val interfaceCollector = object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) { }
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (declaration.isAnnotationClass) return
|
||||
if (declaration.isExternal) return
|
||||
if (declaration.getWasmArrayAnnotation() != null) return
|
||||
if (declaration.isInterface) return
|
||||
if (declaration.isAbstractOrSealed) return
|
||||
|
||||
val classMetadata = declarationGenerator.context.getClassMetadata(declaration.symbol)
|
||||
if (classMetadata.interfaces.isNotEmpty()) {
|
||||
hierarchyDisjointUnions.addUnion(classMetadata.interfaces.map { it.symbol })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun collectInterfaceTables(irModuleFragment: IrModuleFragment) {
|
||||
acceptVisitor(irModuleFragment, interfaceCollector)
|
||||
hierarchyDisjointUnions.compress()
|
||||
}
|
||||
|
||||
fun generateModule(irModuleFragment: IrModuleFragment) {
|
||||
acceptVisitor(irModuleFragment, declarationGenerator)
|
||||
}
|
||||
|
||||
private fun acceptVisitor(irModuleFragment: IrModuleFragment, visitor: IrElementVisitorVoid) {
|
||||
for (irFile in irModuleFragment.files) {
|
||||
generatePackageFragment(irFile)
|
||||
for (irDeclaration in irFile.declarations) {
|
||||
irDeclaration.acceptVoid(visitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun generatePackageFragment(irPackageFragment: IrPackageFragment) {
|
||||
for (irDeclaration in irPackageFragment.declarations) {
|
||||
generateDeclaration(irDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateDeclaration(irDeclaration: IrDeclaration) {
|
||||
irDeclaration.acceptVoid(declarationGenerator)
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.getRuntimeClass
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.irSetField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
|
||||
+3
-9
@@ -101,9 +101,6 @@ class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrEleme
|
||||
private val IrType.eraseToClassOrInterface: IrClass
|
||||
get() = this.erasedUpperBound ?: builtIns.anyClass.owner
|
||||
|
||||
private val IrType.eraseToClass: IrClass
|
||||
get() = this.getRuntimeClass ?: builtIns.anyClass.owner
|
||||
|
||||
private fun generateTypeCheck(
|
||||
valueProvider: () -> IrExpression,
|
||||
toType: IrType
|
||||
@@ -302,19 +299,16 @@ class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrEleme
|
||||
}
|
||||
|
||||
private fun generateIsInterface(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val interfaceId = builder.irCall(symbols.wasmInterfaceId).apply {
|
||||
putTypeArgument(0, toType)
|
||||
}
|
||||
return builder.irCall(symbols.isInterface).apply {
|
||||
putValueArgument(0, argument)
|
||||
putValueArgument(1, interfaceId)
|
||||
putTypeArgument(0, toType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateIsSubClass(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val fromType = argument.type
|
||||
val fromTypeErased = fromType.eraseToClass
|
||||
val toTypeErased = toType.eraseToClass
|
||||
val fromTypeErased = fromType.getRuntimeClass(context.irBuiltIns)
|
||||
val toTypeErased = toType.getRuntimeClass(context.irBuiltIns)
|
||||
if (fromTypeErased.isSubclassOf(toTypeErased)) {
|
||||
return builder.irTrue()
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm.utils
|
||||
|
||||
class DisjointUnions<T> {
|
||||
private val leafParents = mutableMapOf<T, Node>()
|
||||
private var dirty: Boolean = false
|
||||
|
||||
private inner class Node(var rank: Int = 0, val leafs: MutableList<T> = mutableListOf()) {
|
||||
var parent: Node? = null
|
||||
override fun toString(): String = "${if (parent == null) "ROOT " else ""}Node with ${leafs.size} leafs and $rank rank"
|
||||
}
|
||||
|
||||
private fun findRoot(node: T): Node? =
|
||||
leafParents[node]?.let { findRoot(it) }
|
||||
|
||||
private fun findRoot(node: Node, pathWeight: Int = 0): Node {
|
||||
val strictParent = node.parent ?: return node
|
||||
val currentWeight = pathWeight + node.leafs.size
|
||||
val foundRoot = findRoot(strictParent, currentWeight)
|
||||
|
||||
if (foundRoot != node) {
|
||||
val leafs = node.leafs
|
||||
node.rank -= currentWeight
|
||||
check(node.rank >= 0)
|
||||
foundRoot.leafs.addAll(leafs)
|
||||
leafs.clear()
|
||||
node.parent = foundRoot
|
||||
}
|
||||
|
||||
return foundRoot
|
||||
}
|
||||
|
||||
private fun addToRoot(leaf: T, root: Node) {
|
||||
leafParents[leaf] = root
|
||||
root.rank++
|
||||
root.leafs.add(leaf)
|
||||
}
|
||||
|
||||
private fun mergeRoots(root1: Node, root2: Node): Node {
|
||||
if (root1 == root2) return root1
|
||||
require(root1.parent == null && root2.parent == null) { "Merge is possible only for root nodes" }
|
||||
if (root2.parent == root1) return root1
|
||||
if (root1.parent == root2) return root2
|
||||
|
||||
val rootToMove: Node
|
||||
val newParentRoot: Node
|
||||
if (root1.rank > root2.rank) {
|
||||
rootToMove = root2
|
||||
newParentRoot = root1
|
||||
} else {
|
||||
rootToMove = root1
|
||||
newParentRoot = root2
|
||||
}
|
||||
|
||||
rootToMove.parent = newParentRoot
|
||||
|
||||
val leafs = rootToMove.leafs
|
||||
newParentRoot.rank += leafs.size
|
||||
rootToMove.rank -= leafs.size
|
||||
check(rootToMove.rank >= 0)
|
||||
newParentRoot.leafs.addAll(leafs)
|
||||
leafs.clear()
|
||||
|
||||
return newParentRoot
|
||||
}
|
||||
|
||||
fun addUnion(elements: List<T>) {
|
||||
var currentRoot: Node? = null
|
||||
dirty = true
|
||||
for (leaf in elements) {
|
||||
val strictRoot = leafParents[leaf]
|
||||
if (strictRoot == null) {
|
||||
currentRoot = currentRoot?.let(::findRoot) ?: Node()
|
||||
addToRoot(leaf, currentRoot)
|
||||
} else {
|
||||
val leafRoot = findRoot(strictRoot)
|
||||
currentRoot = if (currentRoot != null) mergeRoots(currentRoot, leafRoot) else leafRoot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun compress() {
|
||||
if (dirty) {
|
||||
leafParents.keys.forEach(::findRoot)
|
||||
dirty = false
|
||||
}
|
||||
}
|
||||
|
||||
operator fun contains(element: T): Boolean =
|
||||
leafParents.containsKey(element)
|
||||
|
||||
operator fun get(element: T): List<T> {
|
||||
require(!dirty) { "Call compress before getting union" }
|
||||
val root = findRoot(element)
|
||||
require(root != null) { "Element not contains in any union" }
|
||||
check(root.rank == root.leafs.size) { "Invalid tree state after compress" }
|
||||
return root.leafs
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTry
|
||||
|
||||
// Backed codegen can only handle try/catch in canonical form.
|
||||
@@ -16,6 +18,9 @@ import org.jetbrains.kotlin.ir.expressions.IrTry
|
||||
// ...exprs
|
||||
// }
|
||||
// no-finally
|
||||
fun IrTry.isCanonical(builtIns: IrBuiltIns) =
|
||||
internal fun IrTry.isCanonical(builtIns: IrBuiltIns) =
|
||||
catches.singleOrNull()?.catchParameter?.symbol?.owner?.type == builtIns.throwableType &&
|
||||
finallyExpression == null
|
||||
finallyExpression == null
|
||||
|
||||
internal val IrClass.isAbstractOrSealed
|
||||
get() = modality == Modality.ABSTRACT || modality == Modality.SEALED
|
||||
@@ -14,9 +14,8 @@ internal const val TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET = TYPE_INFO_TYPE_PACKA
|
||||
internal const val TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET = TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||
internal const val TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||
internal const val TYPE_INFO_SUPER_TYPE_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||
internal const val TYPE_INFO_ITABLE_PTR_OFFSET = TYPE_INFO_SUPER_TYPE_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 const val TYPE_INFO_ITABLE_SIZE_OFFSET = TYPE_INFO_SUPER_TYPE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||
internal const val TYPE_INFO_ITABLE_OFFSET = TYPE_INFO_ITABLE_SIZE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||
|
||||
internal class TypeInfoData(val typeId: Int, val isInterface: Boolean, val packageName: String, val typeName: String)
|
||||
|
||||
@@ -33,45 +32,24 @@ internal fun getTypeInfoTypeDataByPtr(typeInfoPtr: Int): TypeInfoData {
|
||||
internal fun getSuperTypeId(typeInfoPtr: Int): Int =
|
||||
wasm_i32_load(typeInfoPtr + TYPE_INFO_SUPER_TYPE_OFFSET)
|
||||
|
||||
internal fun getVtablePtr(obj: Any): Int =
|
||||
obj.typeInfo + TYPE_INFO_VTABLE_OFFSET
|
||||
|
||||
internal fun getVtableLength(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 getVirtualMethodId(obj: Any, virtualFunctionSlot: Int): Int {
|
||||
val vtablePtr = getVtablePtr(obj)
|
||||
val methodIdPtr = vtablePtr + virtualFunctionSlot * TYPE_INFO_ELEMENT_SIZE
|
||||
return wasm_i32_load(methodIdPtr)
|
||||
}
|
||||
|
||||
// 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)
|
||||
internal fun isInterfaceById(obj: Any, interfaceId: Int): Boolean {
|
||||
val interfaceListSize = wasm_i32_load(obj.typeInfo + TYPE_INFO_ITABLE_SIZE_OFFSET)
|
||||
val interfaceListPtr = obj.typeInfo + TYPE_INFO_ITABLE_OFFSET
|
||||
|
||||
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)
|
||||
return true
|
||||
}
|
||||
interfaceSlot++
|
||||
}
|
||||
|
||||
return -1
|
||||
return false
|
||||
}
|
||||
|
||||
internal fun isInterface(obj: Any, interfaceId: Int): Boolean {
|
||||
return getInterfaceImplId(obj, interfaceId) != -1
|
||||
}
|
||||
@ExcludedFromCodegen
|
||||
internal fun <T> isInterface(obj: Any): Boolean =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@ExcludedFromCodegen
|
||||
internal fun <T> wasmClassId(): Int =
|
||||
|
||||
@@ -7,7 +7,7 @@ package kotlin.reflect.wasm.internal
|
||||
import kotlin.reflect.*
|
||||
import kotlin.wasm.internal.TypeInfoData
|
||||
import kotlin.wasm.internal.getSuperTypeId
|
||||
import kotlin.wasm.internal.isInterface
|
||||
import kotlin.wasm.internal.isInterfaceById
|
||||
|
||||
internal object NothingKClassImpl : KClass<Nothing> {
|
||||
override val simpleName: String = "Nothing"
|
||||
@@ -38,7 +38,7 @@ internal class KClassImpl<T : Any>(private val typeData: TypeInfoData) : KClass<
|
||||
}
|
||||
|
||||
override fun isInstance(value: Any?): Boolean = value?.let {
|
||||
if (typeData.isInterface) isInterface(it, typeData.typeId) else checkSuperTypeInstance(it)
|
||||
if (typeData.isInterface) isInterfaceById(it, typeData.typeId) else checkSuperTypeInstance(it)
|
||||
} ?: false
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
|
||||
@@ -374,6 +374,7 @@ enum class WasmOp(
|
||||
BR_ON_CAST("br_on_cast", 0xFB_42, listOf(LABEL_IDX)),
|
||||
|
||||
BR_ON_CAST_FAIL("br_on_cast_fail", 0xfb43, listOf(LABEL_IDX)),
|
||||
BR_ON_CAST_STATIC_FAIL("br_on_cast_static_fail", 0xfb47, listOf(LABEL_IDX, STRUCT_TYPE_IDX)),
|
||||
|
||||
REF_IS_FUNC("ref.is_func", 0xfb50),
|
||||
REF_IS_DATA("ref.is_data", 0xfb51),
|
||||
|
||||
@@ -34,15 +34,19 @@ abstract class WasmExpressionBuilder {
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun buildBlock(label: String?, resultType: WasmType? = null) {
|
||||
inline fun buildBlock(label: String?, resultType: WasmType? = null, body: (Int) -> Unit) {
|
||||
numberOfNestedBlocks++
|
||||
buildInstr(WasmOp.BLOCK, WasmImmediate.BlockType.Value(resultType))
|
||||
body(numberOfNestedBlocks)
|
||||
buildEnd()
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun buildLoop(label: String?, resultType: WasmType? = null) {
|
||||
inline fun buildLoop(label: String?, resultType: WasmType? = null, body: (Int) -> Unit) {
|
||||
numberOfNestedBlocks++
|
||||
buildInstr(WasmOp.LOOP, WasmImmediate.BlockType.Value(resultType))
|
||||
body(numberOfNestedBlocks)
|
||||
buildEnd()
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@@ -60,10 +64,21 @@ abstract class WasmExpressionBuilder {
|
||||
buildInstr(WasmOp.END)
|
||||
}
|
||||
|
||||
fun buildBr(absoluteBlockLevel: Int) {
|
||||
|
||||
fun buildBrInstr(brOp: WasmOp, absoluteBlockLevel: Int) {
|
||||
val relativeLevel = numberOfNestedBlocks - absoluteBlockLevel
|
||||
assert(relativeLevel >= 0) { "Negative relative block index" }
|
||||
buildInstr(WasmOp.BR, WasmImmediate.LabelIdx(relativeLevel))
|
||||
buildInstr(brOp, WasmImmediate.LabelIdx(relativeLevel))
|
||||
}
|
||||
|
||||
fun buildBrInstr(brOp: WasmOp, absoluteBlockLevel: Int, symbol: WasmSymbolReadOnly<WasmTypeDeclaration>) {
|
||||
val relativeLevel = numberOfNestedBlocks - absoluteBlockLevel
|
||||
assert(relativeLevel >= 0) { "Negative relative block index" }
|
||||
buildInstr(brOp, WasmImmediate.LabelIdx(relativeLevel), WasmImmediate.TypeIdx(symbol))
|
||||
}
|
||||
|
||||
fun buildBr(absoluteBlockLevel: Int) {
|
||||
buildBrInstr(WasmOp.BR, absoluteBlockLevel)
|
||||
}
|
||||
|
||||
fun buildThrow(tagIdx: Int) {
|
||||
@@ -81,9 +96,7 @@ abstract class WasmExpressionBuilder {
|
||||
}
|
||||
|
||||
fun buildBrIf(absoluteBlockLevel: Int) {
|
||||
val relativeLevel = numberOfNestedBlocks - absoluteBlockLevel
|
||||
assert(relativeLevel >= 0) { "Negative relative block index" }
|
||||
buildInstr(WasmOp.BR_IF, WasmImmediate.LabelIdx(relativeLevel))
|
||||
buildBrInstr(WasmOp.BR_IF, absoluteBlockLevel)
|
||||
}
|
||||
|
||||
fun buildCall(symbol: WasmSymbol<WasmFunction>) {
|
||||
@@ -126,7 +139,7 @@ abstract class WasmExpressionBuilder {
|
||||
}
|
||||
|
||||
fun buildStructNew(struct: WasmSymbol<WasmTypeDeclaration>) {
|
||||
buildInstr(WasmOp.STRUCT_NEW_WITH_RTT, WasmImmediate.GcType(struct))
|
||||
buildInstr(WasmOp.STRUCT_NEW, WasmImmediate.GcType(struct))
|
||||
}
|
||||
|
||||
fun buildStructSet(struct: WasmSymbol<WasmTypeDeclaration>, fieldId: WasmSymbol<Int>) {
|
||||
@@ -142,8 +155,8 @@ abstract class WasmExpressionBuilder {
|
||||
buildInstr(WasmOp.REF_CAST)
|
||||
}
|
||||
|
||||
fun buildRefCastStatic(type: WasmSymbolReadOnly<WasmTypeDeclaration>) {
|
||||
buildInstr(WasmOp.REF_CAST_STATIC, WasmImmediate.TypeIdx(type))
|
||||
fun buildRefCastStatic(toType: WasmSymbolReadOnly<WasmTypeDeclaration>) {
|
||||
buildInstr(WasmOp.REF_CAST_STATIC, WasmImmediate.TypeIdx(toType))
|
||||
}
|
||||
|
||||
fun buildRefNull(type: WasmHeapType) {
|
||||
|
||||
@@ -21,7 +21,6 @@ class WasmIrExpressionBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override var numberOfNestedBlocks: Int = 0
|
||||
set(value) {
|
||||
assert(value >= 0) { "end without matching block" }
|
||||
|
||||
Reference in New Issue
Block a user