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 083f08f3a75..1df5c93541f 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 @@ -35,7 +35,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV private val unitGetInstance by lazy { backendContext.findUnitGetInstanceFunction() } fun WasmExpressionBuilder.buildGetUnit() { - buildCall(context.referenceFunction(unitGetInstance.symbol)) + buildInstr(WasmOp.GET_UNIT, WasmImmediate.FuncIdx(context.referenceFunction(unitGetInstance.symbol))) } // Generates code for the given IR element and *always* leaves something on the stack @@ -264,6 +264,12 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV return } + // Get unit is a special case because it is the only function which returns the real unit instance. + if (call.symbol == unitGetInstance.symbol) { + body.buildGetUnit() + return + } + call.dispatchReceiver?.let { generateExpression(it) } call.extensionReceiver?.let { generateExpression(it) } for (i in 0 until call.valueArgumentsCount) { @@ -319,7 +325,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV } // Unit types don't cross function boundaries - if (function.returnType == irBuiltIns.unitType && function.symbol != unitGetInstance.symbol) + if (function.returnType == irBuiltIns.unitType) body.buildGetUnit() } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt index 7db83235bc1..f63f43edbe9 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt @@ -367,6 +367,9 @@ enum class WasmOp( REF_CAST("ref.cast", 0xFB_41), BR_ON_CAST("br_on_cast", 0xFB_42, listOf(LABEL_IDX)), + + // Pseudo-instruction, just alias for a normal call. It's used to easily spot get_unit on the wasm level. + GET_UNIT("call", 0x10, FUNC_IDX) ; constructor(mnemonic: String, opcode: Int, vararg immediates: WasmImmediateKind) : this(mnemonic, opcode, immediates.toList()) diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Utils.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Utils.kt index 4a70db2bfd3..c406f5affde 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Utils.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Utils.kt @@ -42,6 +42,16 @@ fun foldWasmInstructions(prev: WasmInstr?, next: WasmInstr): List? { if (next.operator == WasmOp.UNREACHABLE && prev.operator in listOf(WasmOp.UNREACHABLE, WasmOp.RETURN)) return listOf(prev) + if (next.operator == WasmOp.DROP) { + // simple pure instruction + drop -> nothing + if (prev.operator == WasmOp.GET_UNIT || prev.operator == WasmOp.REF_NULL) + return listOf() + + // return + drop -> return + if (prev.operator == WasmOp.RETURN) + return listOf(prev) + } + return null }