From a7ed496a049a1e20d7c45d41f15b813f81f516f8 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Sat, 10 Sep 2022 16:06:54 +0200 Subject: [PATCH] [WASM] Use wasm bottom types for Nothing? --- .../kotlin/backend/wasm/WasmLoweringPhases.kt | 7 ---- .../backend/wasm/ir2wasm/BodyGenerator.kt | 10 ++++-- .../wasm/ir2wasm/DeclarationGenerator.kt | 9 +++-- .../backend/wasm/ir2wasm/TypeTransformer.kt | 2 +- .../wasm/lower/WasmNullCoercionLowering.kt | 35 ------------------- .../src/org/jetbrains/kotlin/wasm/ir/Types.kt | 7 +++- 6 files changed, 22 insertions(+), 48 deletions(-) delete mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmNullCoercionLowering.kt diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index a53769178e8..3f345070944 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -427,12 +427,6 @@ private val autoboxingTransformerPhase = makeWasmModulePhase( description = "Insert box/unbox intrinsics" ) -private val wasmNullSpecializationLowering = makeWasmModulePhase( - { context -> WasmNullCoercingLowering(context) }, - name = "WasmNullCoercingLowering", - description = "Specialize assigning Nothing? values to other types." -) - private val staticMembersLoweringPhase = makeWasmModulePhase( ::StaticMembersLowering, name = "StaticMembersLowering", @@ -661,6 +655,5 @@ val wasmPhases = NamedCompilerPhase( virtualDispatchReceiverExtractionPhase then staticMembersLoweringPhase then - wasmNullSpecializationLowering then validateIrAfterLowering ) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt index 2daa4715713..9b5f82ab7c2 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt @@ -589,8 +589,14 @@ class BodyGenerator( // NOTHING -> TYPE -> TRUE if (actualType.isNothing()) return - // NOTHING? -> TYPE? -> TRUE - if (actualType.isNullableNothing() && expectedType.isNullable()) return + // NOTHING? -> TYPE? -> (NOTHING?)NULL + if (actualType.isNullableNothing() && expectedType.isNullable()) { + if (expectedType.getClass()?.isExternal == true) { + body.buildDrop() + body.buildRefNull(WasmHeapType.Simple.NullNoExtern) + } + return + } val expectedClassErased = expectedType.getRuntimeClass(irBuiltIns) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt index 22e3594e185..92222fb761e 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt @@ -22,6 +22,7 @@ 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.IrClassSymbol +import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid @@ -442,13 +443,14 @@ class DeclarationGenerator( } } - fun generateDefaultInitializerForType(type: WasmType, g: WasmExpressionBuilder) = when (type) { WasmI32 -> g.buildConstI32(0) WasmI64 -> g.buildConstI64(0) WasmF32 -> g.buildConstF32(0f) WasmF64 -> g.buildConstF64(0.0) is WasmRefNullType -> g.buildRefNull(type.heapType) + is WasmRefNullNoneType -> g.buildRefNull(WasmHeapType.Simple.NullNone) + is WasmRefNullExternrefType -> g.buildRefNull(WasmHeapType.Simple.NullNoExtern) is WasmAnyRef -> g.buildRefNull(WasmHeapType.Simple.Any) is WasmExternRef -> g.buildRefNull(WasmHeapType.Simple.Extern) WasmUnreachableType -> error("Unreachable type can't be initialized") @@ -466,7 +468,10 @@ fun IrFunction.isExported(): Boolean = fun generateConstExpression(expression: IrConst<*>, body: WasmExpressionBuilder, context: WasmBaseCodegenContext) { when (val kind = expression.kind) { - is IrConstKind.Null -> generateDefaultInitializerForType(context.transformType(expression.type), body) + is IrConstKind.Null -> { + val bottomType = if (expression.type.getClass()?.isExternal == true) WasmRefNullExternrefType else WasmRefNullNoneType + body.buildInstr(WasmOp.REF_NULL, WasmImmediate.HeapType(bottomType)) + } is IrConstKind.Boolean -> body.buildConstI32(if (kind.valueOf(expression)) 1 else 0) is IrConstKind.Byte -> body.buildConstI32(kind.valueOf(expression).toInt()) is IrConstKind.Short -> body.buildConstI32(kind.valueOf(expression).toInt()) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt index 54b699f5152..d06e2b494bf 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt @@ -82,7 +82,7 @@ class WasmTypeTransformer( WasmF64 builtIns.nothingNType -> - WasmAnyRef + WasmRefNullNoneType // Value will not be created. Just using a random Wasm type. builtIns.nothingType -> diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmNullCoercionLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmNullCoercionLowering.kt deleted file mode 100644 index 94f60656112..00000000000 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmNullCoercionLowering.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010-2020 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.lower - -import org.jetbrains.kotlin.backend.wasm.WasmBackendContext -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext -import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.backend.js.lower.AbstractValueUsageLowering -import org.jetbrains.kotlin.ir.expressions.IrConstKind -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.isNothing -import org.jetbrains.kotlin.ir.types.isNullable -import org.jetbrains.kotlin.ir.types.makeNotNull - -/** - * Replace null constants of type Nothing? with null constants of a concrete class types. - * - * Wasm GC doesn't have a nullref type anymore. - */ -class WasmNullCoercingLowering(private val contextx: WasmBackendContext) : AbstractValueUsageLowering(contextx) { - override fun IrExpression.useExpressionAsType(actualType: IrType, expectedType: IrType): IrExpression = - if (actualType.makeNotNull().isNothing() && actualType.isNullable() && !expectedType.makeNotNull().isNothing() && expectedType != contextx.wasmSymbols.voidType) - JsIrBuilder.buildComposite( - expectedType, - listOf(this, IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, expectedType, IrConstKind.Null, null)) - ) - else - this -} \ No newline at end of file diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt index 22d671a287d..37d8f364d4c 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt @@ -25,6 +25,8 @@ object WasmFuncRef : WasmType("funcref", -0x10) object WasmExternRef : WasmType("externref", -0x11) object WasmAnyRef : WasmType("anyref", -0x12) object WasmEqRef : WasmType("eqref", -0x13) +object WasmRefNullNoneType : WasmType("nullnone", -0x1b) +object WasmRefNullExternrefType : WasmType("nullexternref", -0x17) data class WasmRefNullType(val heapType: WasmHeapType) : WasmType("ref null", -0x14) data class WasmRefType(val heapType: WasmHeapType) : WasmType("ref", -0x15) @@ -47,8 +49,9 @@ sealed class WasmHeapType { object Extern : Simple("extern", -0x11) object Any : Simple("any", -0x12) object Eq : Simple("eq", -0x13) - object Data : Simple("data", -0x19) + object NullNone : Simple("nullref", -0x1b) + object NullNoExtern : Simple("nullexternref", -0x17) override fun toString(): String { return "Simple:$name(${code.toString(16)})" @@ -66,6 +69,8 @@ fun WasmType.getHeapType(): WasmHeapType = when (this) { is WasmRefType -> heapType is WasmRefNullType -> heapType + is WasmRefNullNoneType -> WasmHeapType.Simple.NullNone + is WasmRefNullExternrefType -> WasmHeapType.Simple.NullNoExtern is WasmEqRef -> WasmHeapType.Simple.Eq is WasmAnyRef -> WasmHeapType.Simple.Any is WasmFuncRef -> WasmHeapType.Simple.Func