From 62ac77ca39bd8b062f35c8c6fd784992fb19d793 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Fri, 16 Dec 2022 13:57:59 +0000 Subject: [PATCH] [Wasm] Add comments to .wat files --- .../backend/wasm/ir2wasm/BodyGenerator.kt | 18 +++++++++++ .../wasm/ir2wasm/DeclarationGenerator.kt | 2 ++ .../org/jetbrains/kotlin/wasm/ir/Operators.kt | 11 ++++++- .../kotlin/wasm/ir/WasmExpressionBuilder.kt | 12 ++++++++ .../wasm/ir/convertors/WasmIrToBinary.kt | 6 ++++ .../kotlin/wasm/ir/convertors/WasmIrToText.kt | 30 +++++++++++++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) 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 68342cf3202..8643cada378 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 @@ -181,6 +181,7 @@ class BodyGenerator( } } else { body.buildGetGlobal(context.referenceGlobalField(field.symbol)) + body.commentPreviousInstr { "type: ${field.type.render()}" } } } @@ -202,6 +203,7 @@ class BodyGenerator( WasmImmediate.GcType(context.referenceGcType(field.parentAsClass.symbol)), WasmImmediate.StructFieldIdx(context.getStructFieldRef(field)) ) + body.commentPreviousInstr { "name: ${field.name.asString()}, type: ${field.type.render()}" } } override fun visitSetField(expression: IrSetField) { @@ -215,9 +217,11 @@ class BodyGenerator( struct = context.referenceGcType(field.parentAsClass.symbol), fieldId = context.getStructFieldRef(field), ) + body.commentPreviousInstr { "name: ${field.name}, type: ${field.type.render()}" } } else { generateExpression(expression.value) body.buildSetGlobal(context.referenceGlobalField(expression.symbol)) + body.commentPreviousInstr { "type: ${field.type.render()}" } } body.buildGetUnit() @@ -234,11 +238,13 @@ class BodyGenerator( else functionContext.referenceLocal(valueSymbol) ) + body.commentPreviousInstr { "type: ${valueDeclaration.type.render()}" } } override fun visitSetValue(expression: IrSetValue) { generateExpression(expression.value) body.buildSetLocal(functionContext.referenceLocal(expression.symbol)) + body.commentPreviousInstr { "type: ${expression.symbol.owner.type.render()}" } body.buildGetUnit() } @@ -263,6 +269,7 @@ class BodyGenerator( WasmOp.ARRAY_NEW_DEFAULT, WasmImmediate.GcType(wasmGcType) ) + body.commentPreviousInstr { "@WasmArrayOf ctor call: ${klass.fqNameWhenAvailable}" } return } @@ -272,6 +279,7 @@ class BodyGenerator( generateExpression(expression.getValueArgument(i)!!) } body.buildStructNew(wasmGcType) + body.commentPreviousInstr { "@WasmPrimitiveConstructor ctor call: ${klass.fqNameWhenAvailable}" } return } @@ -281,6 +289,7 @@ class BodyGenerator( private fun generateAnyParameters(klassSymbol: IrClassSymbol) { //ClassITable and VTable load + body.commentGroupStart { "Any parameters" } body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol)) if (klassSymbol.owner.hasInterfaceSuperClass()) { body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol)) @@ -290,6 +299,7 @@ class BodyGenerator( body.buildConstI32Symbol(context.referenceClassId(klassSymbol)) body.buildConstI32(0) // Any::_hashCode + body.commentGroupEnd() } fun generateObjectCreationPrefixIfNeeded(constructor: IrConstructor) { @@ -297,6 +307,7 @@ class BodyGenerator( if (constructor.origin == PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR) return if (parentClass.isAbstractOrSealed) return val thisParameter = functionContext.referenceLocal(parentClass.thisReceiver!!.symbol) + body.commentGroupStart { "Object creation prefix" } body.buildGetLocal(thisParameter) body.buildInstr(WasmOp.REF_IS_NULL) body.buildIf("this_init") @@ -310,6 +321,7 @@ class BodyGenerator( body.buildStructNew(context.referenceGcType(parentClass.symbol)) body.buildSetLocal(thisParameter) body.buildEnd() + body.commentGroupEnd() } override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) { @@ -330,6 +342,7 @@ class BodyGenerator( generateAnyParameters(klassSymbol) generateExpression(expression) body.buildStructNew(context.referenceGcType(klassSymbol)) + body.commentPreviousInstr { "box" } } private fun generateCall(call: IrFunctionAccessExpression) { @@ -394,17 +407,21 @@ class BodyGenerator( val receiver = call.dispatchReceiver!! generateExpression(receiver) + body.commentGroupStart { "virtual call: ${function.fqNameWhenAvailable}" } + //TODO: check why it could be needed generateRefNullCast(receiver.type, klass.defaultType) body.buildStructGet(context.referenceGcType(klass.symbol), WasmSymbol(0)) body.buildStructGet(context.referenceVTableGcType(klass.symbol), WasmSymbol(vfSlot)) body.buildInstr(WasmOp.CALL_REF, WasmImmediate.TypeIdx(context.referenceFunctionType(function.symbol))) + body.commentGroupEnd() } else { val symbol = klass.symbol if (symbol in hierarchyDisjointUnions) { generateExpression(call.dispatchReceiver!!) + body.commentGroupStart { "interface call: ${function.fqNameWhenAvailable}" } body.buildStructGet(context.referenceGcType(irBuiltIns.anyClass), WasmSymbol(1)) val classITableReference = context.referenceClassITableGcType(symbol) @@ -416,6 +433,7 @@ class BodyGenerator( body.buildStructGet(context.referenceVTableGcType(symbol), WasmSymbol(vfSlot)) body.buildInstr(WasmOp.CALL_REF, WasmImmediate.TypeIdx(context.referenceFunctionType(function.symbol))) + body.commentGroupEnd() } else { body.buildUnreachable() } 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 49ca7a68e9d..dc00e28a80d 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 @@ -494,10 +494,12 @@ fun generateConstExpression(expression: IrConst<*>, body: WasmExpressionBuilder, is IrConstKind.String -> { val stringValue = kind.valueOf(expression) val (literalAddress, literalPoolId) = context.referenceStringLiteralAddressAndId(stringValue) + body.commentGroupStart { "const string: \"$stringValue\"" } body.buildConstI32Symbol(literalPoolId) body.buildConstI32Symbol(literalAddress) body.buildConstI32(stringValue.length) body.buildCall(context.referenceFunction(context.backendContext.wasmSymbols.stringGetLiteral)) + body.commentGroupEnd() } else -> error("Unknown constant kind") } 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 0f41a7f56d6..7810ef26614 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 @@ -95,6 +95,9 @@ sealed class WasmImmediate { class HeapType(val value: WasmHeapType) : WasmImmediate() { constructor(type: WasmType) : this(type.getHeapType()) } + + // Pseudo-immediates + class ConstString(val value: String) : WasmImmediate() } @@ -403,11 +406,17 @@ enum class WasmOp( // ============================================================ // 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) + GET_UNIT("call", 0x10, FUNC_IDX), + + PSEUDO_COMMENT_PREVIOUS_INSTR("", WASM_OP_PSEUDO_OPCODE), + PSEUDO_COMMENT_GROUP_START("", WASM_OP_PSEUDO_OPCODE), + PSEUDO_COMMENT_GROUP_END("", WASM_OP_PSEUDO_OPCODE), ; constructor(mnemonic: String, opcode: Int, vararg immediates: WasmImmediateKind) : this(mnemonic, opcode, immediates.toList()) } +const val WASM_OP_PSEUDO_OPCODE = 0xFFFF + val opcodesToOp: Map = enumValues().associateBy { it.opcode } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt index 1f59b8b33e0..24245e8bdf5 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt @@ -178,4 +178,16 @@ abstract class WasmExpressionBuilder { fun buildDrop() { buildInstr(WasmOp.DROP) } + + inline fun commentPreviousInstr(text: () -> String) { + buildInstr(WasmOp.PSEUDO_COMMENT_PREVIOUS_INSTR, WasmImmediate.ConstString(text())) + } + + inline fun commentGroupStart(text: () -> String) { + buildInstr(WasmOp.PSEUDO_COMMENT_GROUP_START, WasmImmediate.ConstString(text())) + } + + fun commentGroupEnd() { + buildInstr(WasmOp.PSEUDO_COMMENT_GROUP_END) + } } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt index 99502a1398c..345c7ac173b 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt @@ -210,6 +210,10 @@ class WasmIrToBinary( } val opcode = instr.operator.opcode + + if (opcode == WASM_OP_PSEUDO_OPCODE) + return + if (opcode > 0xFF) { b.writeByte((opcode ushr 8).toByte()) b.writeByte((opcode and 0xFF).toByte()) @@ -259,6 +263,8 @@ class WasmIrToBinary( is WasmImmediate.GcType -> appendModuleFieldReference(x.value.owner) is WasmImmediate.StructFieldIdx -> b.writeVarUInt32(x.value.owner) is WasmImmediate.HeapType -> appendHeapType(x.value) + is WasmImmediate.ConstString -> + error("Instructions with pseudo immediates should be skipped") } } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt index 5f2f57a5d05..b83cbfcb563 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt @@ -60,6 +60,34 @@ class WasmIrToText : SExpressionBuilder() { private fun appendInstr(wasmInstr: WasmInstr) { val op = wasmInstr.operator + + if (op.opcode == WASM_OP_PSEUDO_OPCODE) { + fun commentText() = + (wasmInstr.immediates.single() as WasmImmediate.ConstString).value + + when (op) { + WasmOp.PSEUDO_COMMENT_PREVIOUS_INSTR -> { + val text = commentText() + require(text.lineSequence().count() < 2) { "Comments for single instruction should be in one line" } + stringBuilder.append(" ;; ") + stringBuilder.append(text) + } + WasmOp.PSEUDO_COMMENT_GROUP_START -> { + newLine() + commentText().lines().forEach { line -> + newLine() + stringBuilder.append(";; ") + stringBuilder.append(line) + } + } + WasmOp.PSEUDO_COMMENT_GROUP_END -> { + newLine() + } + else -> error("Unknown pseudo op $op") + } + return + } + if (op == WasmOp.END || op == WasmOp.ELSE || op == WasmOp.CATCH) indent-- @@ -113,6 +141,8 @@ class WasmIrToText : SExpressionBuilder() { is WasmImmediate.HeapType -> { appendHeapType(x.value) } + + is WasmImmediate.ConstString -> error("Pseudo immediate") } }