[UNFINISHED, Wasm] Component Model: Possible skeleton for canon ABI type translation
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmComponentModelLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmComponentModelLowering.kt index 570893e..35e72798 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmComponentModelLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmComponentModelLowering.kt
@@ -7,35 +7,29 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.config.IrVerificationMode import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver -import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.impl.IrAnnotationImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.fromSymbolOwner import org.jetbrains.kotlin.ir.util.constructors -import org.jetbrains.kotlin.ir.util.copyFunctionSignatureFrom import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols -import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.findAnnotation import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.isFakeOverride @@ -44,14 +38,112 @@ import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.expressions.IrGetValue -import org.jetbrains.kotlin.ir.util.parentsWithSelf -import org.jetbrains.kotlin.ir.util.setDeclarationsParent import org.jetbrains.kotlin.ir.validation.IrValidatorConfig import org.jetbrains.kotlin.ir.validation.validateIr import org.jetbrains.kotlin.ir.validation.withBasicChecks -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.zipIfSizesAreEqual +import kotlin.math.ceil +import kotlin.math.log2 +import kotlin.math.max + +// TODO maybe this whole thing should rather be in @WasmExport? But prob not, would be a bit weird for "normal" exports to implicitly support this +sealed interface WitType { + val size: ULong + val alignment: ULong + + fun flattened(): List<WitType> +} + +// TODO better representation for things that are already flat? maybe an "isFullyFlat" in top-level iface? +interface WitTypeFullyFlattened : WitType { + override fun flattened(): List<WitType> = listOf(this) +} + +class WitPointer(val pointedToTy: WitType) : WitTypeFullyFlattened { + // TODO wasm32 only for now, find canon abi spec specifics for this + override val size: ULong = 4u + override val alignment: ULong = 4u + + override fun flattened(): List<WitType> = listOf(this) + +} + +abstract class WitPrimitiveInt( + sizeAndAlignment: ULong, + override val size: ULong = sizeAndAlignment, + override val alignment: ULong = sizeAndAlignment, +) : WitTypeFullyFlattened { +} + +class U8 : WitPrimitiveInt(1u) +class U16 : WitPrimitiveInt(2u) +class U32 : WitPrimitiveInt(4u) +class U64 : WitPrimitiveInt(8u) + +class S8 : WitPrimitiveInt(1u) +class S16 : WitPrimitiveInt(2u) +class S32 : WitPrimitiveInt(4u) +class S64 : WitPrimitiveInt(8u) + +class WitList(val elemTy: WitType, val optionalFixedLength: ULong? = null) : WitType { + override val size: ULong + get() { + if (optionalFixedLength == null) + return 8u + return elemTy.size * optionalFixedLength + } + // TODO think about getters vs by lazy vs functions vs eager init in init{} block vs direct init + override val alignment: ULong by lazy{ + if (optionalFixedLength == null) + return@lazy 4u + return@lazy elemTy.alignment + } + + override fun flattened(): List<WitType> = listOf(WitPointer(elemTy), U32()) +} + +class WitVariant(val cases: List<WitType>) : WitType { + // TODO toInt() doesn't exist, just toUInt()??? + val discriminantType: WitType = when(ceil(log2(cases.size.toDouble())/8).toUInt()){ + 0u -> U8() + 1u -> U8() + 2u -> U16() + 3u -> U32() + else -> error("PANIC") //TODO proper + } + + /* + def elem_size_variant(cases): + s = elem_size(discriminant_type(cases)) + s = align_to(s, max_case_alignment(cases)) + cs = 0 + for c in cases: + if c.t is not None: + cs = max(cs, elem_size(c.t)) + s += cs + return align_to(s, alignment_variant(cases)) + */ + override val size: ULong = run { + /* + TODO this is pretty wrong so far + val discriminantSize = this@WitVariant.discriminantType.size + val discrimantAlign = this@WitVariant.discriminantType.alignment + + var maxCaseSize = 0uL + for (case in cases) { + maxCaseSize = max(maxCaseSize, case.size) + } + + // TODO alignTo + return@run alignTo(discriminantSize + maxCaseSize, discrimantAlign) + */ + 0uL + } + override val alignment: ULong = 4u + override fun flattened(): List<WitType> = TODO("Not yet implemented") + +} class WasmComponentModelLowering(val context: WasmBackendContext) : FileLoweringPass { // TODO with all of the names in this file, make them so that there can't be any conflicts @@ -62,18 +154,11 @@ for (decl in irFile.declarations) { - - - // The problem is the body of the <init> function of the companion object would be null, because the surrounding interface is external. // Theres a special change in ClassMemberGenerator.kt in fir2ir, that makes sure that external interfaces that are // annotated with @WitInterface/their companion objects with @WitImport are actually treated as non-external for the purposes of generating the <init> body - - - - // TODO frontend checks for the annotation that doesn't match this, i.e. on a non-interface, or a non-external interface if (decl is IrClass && decl.isInterface && decl.isExternal && decl.hasAnnotation(context.wasmSymbols.witInterface)) { @@ -119,7 +204,7 @@ .find { it.isFakeOverride && it.name == functionDecl.name }!! // TODO think about a better check for this than comparing names companionObject.factory.stageController.restrictTo(implFunction) { - // TODO actual offsets? rewrite original functions offsets? + // TODO actual offsets? rewrite original functions offsets? val irb = context.createIrBuilder(implFunction.symbol) implFunction.body = irb.irBlockBody { +irReturn(
diff --git a/compiler/testData/codegen/box/wasm-component-model/basicImport.kt b/compiler/testData/codegen/box/wasm-component-model/basicImport.kt index 8039f76..8e643fa 100644 --- a/compiler/testData/codegen/box/wasm-component-model/basicImport.kt +++ b/compiler/testData/codegen/box/wasm-component-model/basicImport.kt
@@ -1,3 +1,4 @@ +// import kotlin.wasm.WasmImport /*
diff --git a/libraries/stdlib/wasm/src/kotlin/annotations.kt b/libraries/stdlib/wasm/src/kotlin/annotations.kt index 200d18b..f97e3b3 100644 --- a/libraries/stdlib/wasm/src/kotlin/annotations.kt +++ b/libraries/stdlib/wasm/src/kotlin/annotations.kt
@@ -23,13 +23,13 @@ * Classes and interfaces annotated with `@WitInterface` are treated as WIT interface * definitions by the Kotlin/Wasm compiler backend. * - * @property name The WIT interface name. If not specified, the Kotlin name is used. + * @property name The WIT interface name. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) @MustBeDocumented @SinceKotlin("2.4") -public annotation class WitInterface(val witName: String = "") +public annotation class WitInterface(val witName:String) /** * TODO proper doc comment