[Wasm] Add comments to .wat files

This commit is contained in:
Svyatoslav Kuzmich
2022-12-16 13:57:59 +00:00
committed by Space Team
parent 41dbbd1fc8
commit 62ac77ca39
6 changed files with 78 additions and 1 deletions
@@ -181,6 +181,7 @@ class BodyGenerator(
} }
} else { } else {
body.buildGetGlobal(context.referenceGlobalField(field.symbol)) 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.GcType(context.referenceGcType(field.parentAsClass.symbol)),
WasmImmediate.StructFieldIdx(context.getStructFieldRef(field)) WasmImmediate.StructFieldIdx(context.getStructFieldRef(field))
) )
body.commentPreviousInstr { "name: ${field.name.asString()}, type: ${field.type.render()}" }
} }
override fun visitSetField(expression: IrSetField) { override fun visitSetField(expression: IrSetField) {
@@ -215,9 +217,11 @@ class BodyGenerator(
struct = context.referenceGcType(field.parentAsClass.symbol), struct = context.referenceGcType(field.parentAsClass.symbol),
fieldId = context.getStructFieldRef(field), fieldId = context.getStructFieldRef(field),
) )
body.commentPreviousInstr { "name: ${field.name}, type: ${field.type.render()}" }
} else { } else {
generateExpression(expression.value) generateExpression(expression.value)
body.buildSetGlobal(context.referenceGlobalField(expression.symbol)) body.buildSetGlobal(context.referenceGlobalField(expression.symbol))
body.commentPreviousInstr { "type: ${field.type.render()}" }
} }
body.buildGetUnit() body.buildGetUnit()
@@ -234,11 +238,13 @@ class BodyGenerator(
else else
functionContext.referenceLocal(valueSymbol) functionContext.referenceLocal(valueSymbol)
) )
body.commentPreviousInstr { "type: ${valueDeclaration.type.render()}" }
} }
override fun visitSetValue(expression: IrSetValue) { override fun visitSetValue(expression: IrSetValue) {
generateExpression(expression.value) generateExpression(expression.value)
body.buildSetLocal(functionContext.referenceLocal(expression.symbol)) body.buildSetLocal(functionContext.referenceLocal(expression.symbol))
body.commentPreviousInstr { "type: ${expression.symbol.owner.type.render()}" }
body.buildGetUnit() body.buildGetUnit()
} }
@@ -263,6 +269,7 @@ class BodyGenerator(
WasmOp.ARRAY_NEW_DEFAULT, WasmOp.ARRAY_NEW_DEFAULT,
WasmImmediate.GcType(wasmGcType) WasmImmediate.GcType(wasmGcType)
) )
body.commentPreviousInstr { "@WasmArrayOf ctor call: ${klass.fqNameWhenAvailable}" }
return return
} }
@@ -272,6 +279,7 @@ class BodyGenerator(
generateExpression(expression.getValueArgument(i)!!) generateExpression(expression.getValueArgument(i)!!)
} }
body.buildStructNew(wasmGcType) body.buildStructNew(wasmGcType)
body.commentPreviousInstr { "@WasmPrimitiveConstructor ctor call: ${klass.fqNameWhenAvailable}" }
return return
} }
@@ -281,6 +289,7 @@ class BodyGenerator(
private fun generateAnyParameters(klassSymbol: IrClassSymbol) { private fun generateAnyParameters(klassSymbol: IrClassSymbol) {
//ClassITable and VTable load //ClassITable and VTable load
body.commentGroupStart { "Any parameters" }
body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol)) body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol))
if (klassSymbol.owner.hasInterfaceSuperClass()) { if (klassSymbol.owner.hasInterfaceSuperClass()) {
body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol)) body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol))
@@ -290,6 +299,7 @@ class BodyGenerator(
body.buildConstI32Symbol(context.referenceClassId(klassSymbol)) body.buildConstI32Symbol(context.referenceClassId(klassSymbol))
body.buildConstI32(0) // Any::_hashCode body.buildConstI32(0) // Any::_hashCode
body.commentGroupEnd()
} }
fun generateObjectCreationPrefixIfNeeded(constructor: IrConstructor) { fun generateObjectCreationPrefixIfNeeded(constructor: IrConstructor) {
@@ -297,6 +307,7 @@ class BodyGenerator(
if (constructor.origin == PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR) return if (constructor.origin == PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR) return
if (parentClass.isAbstractOrSealed) return if (parentClass.isAbstractOrSealed) return
val thisParameter = functionContext.referenceLocal(parentClass.thisReceiver!!.symbol) val thisParameter = functionContext.referenceLocal(parentClass.thisReceiver!!.symbol)
body.commentGroupStart { "Object creation prefix" }
body.buildGetLocal(thisParameter) body.buildGetLocal(thisParameter)
body.buildInstr(WasmOp.REF_IS_NULL) body.buildInstr(WasmOp.REF_IS_NULL)
body.buildIf("this_init") body.buildIf("this_init")
@@ -310,6 +321,7 @@ class BodyGenerator(
body.buildStructNew(context.referenceGcType(parentClass.symbol)) body.buildStructNew(context.referenceGcType(parentClass.symbol))
body.buildSetLocal(thisParameter) body.buildSetLocal(thisParameter)
body.buildEnd() body.buildEnd()
body.commentGroupEnd()
} }
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
@@ -330,6 +342,7 @@ class BodyGenerator(
generateAnyParameters(klassSymbol) generateAnyParameters(klassSymbol)
generateExpression(expression) generateExpression(expression)
body.buildStructNew(context.referenceGcType(klassSymbol)) body.buildStructNew(context.referenceGcType(klassSymbol))
body.commentPreviousInstr { "box" }
} }
private fun generateCall(call: IrFunctionAccessExpression) { private fun generateCall(call: IrFunctionAccessExpression) {
@@ -394,17 +407,21 @@ class BodyGenerator(
val receiver = call.dispatchReceiver!! val receiver = call.dispatchReceiver!!
generateExpression(receiver) generateExpression(receiver)
body.commentGroupStart { "virtual call: ${function.fqNameWhenAvailable}" }
//TODO: check why it could be needed //TODO: check why it could be needed
generateRefNullCast(receiver.type, klass.defaultType) generateRefNullCast(receiver.type, klass.defaultType)
body.buildStructGet(context.referenceGcType(klass.symbol), WasmSymbol(0)) body.buildStructGet(context.referenceGcType(klass.symbol), WasmSymbol(0))
body.buildStructGet(context.referenceVTableGcType(klass.symbol), WasmSymbol(vfSlot)) body.buildStructGet(context.referenceVTableGcType(klass.symbol), WasmSymbol(vfSlot))
body.buildInstr(WasmOp.CALL_REF, WasmImmediate.TypeIdx(context.referenceFunctionType(function.symbol))) body.buildInstr(WasmOp.CALL_REF, WasmImmediate.TypeIdx(context.referenceFunctionType(function.symbol)))
body.commentGroupEnd()
} else { } else {
val symbol = klass.symbol val symbol = klass.symbol
if (symbol in hierarchyDisjointUnions) { if (symbol in hierarchyDisjointUnions) {
generateExpression(call.dispatchReceiver!!) generateExpression(call.dispatchReceiver!!)
body.commentGroupStart { "interface call: ${function.fqNameWhenAvailable}" }
body.buildStructGet(context.referenceGcType(irBuiltIns.anyClass), WasmSymbol(1)) body.buildStructGet(context.referenceGcType(irBuiltIns.anyClass), WasmSymbol(1))
val classITableReference = context.referenceClassITableGcType(symbol) val classITableReference = context.referenceClassITableGcType(symbol)
@@ -416,6 +433,7 @@ class BodyGenerator(
body.buildStructGet(context.referenceVTableGcType(symbol), WasmSymbol(vfSlot)) body.buildStructGet(context.referenceVTableGcType(symbol), WasmSymbol(vfSlot))
body.buildInstr(WasmOp.CALL_REF, WasmImmediate.TypeIdx(context.referenceFunctionType(function.symbol))) body.buildInstr(WasmOp.CALL_REF, WasmImmediate.TypeIdx(context.referenceFunctionType(function.symbol)))
body.commentGroupEnd()
} else { } else {
body.buildUnreachable() body.buildUnreachable()
} }
@@ -494,10 +494,12 @@ fun generateConstExpression(expression: IrConst<*>, body: WasmExpressionBuilder,
is IrConstKind.String -> { is IrConstKind.String -> {
val stringValue = kind.valueOf(expression) val stringValue = kind.valueOf(expression)
val (literalAddress, literalPoolId) = context.referenceStringLiteralAddressAndId(stringValue) val (literalAddress, literalPoolId) = context.referenceStringLiteralAddressAndId(stringValue)
body.commentGroupStart { "const string: \"$stringValue\"" }
body.buildConstI32Symbol(literalPoolId) body.buildConstI32Symbol(literalPoolId)
body.buildConstI32Symbol(literalAddress) body.buildConstI32Symbol(literalAddress)
body.buildConstI32(stringValue.length) body.buildConstI32(stringValue.length)
body.buildCall(context.referenceFunction(context.backendContext.wasmSymbols.stringGetLiteral)) body.buildCall(context.referenceFunction(context.backendContext.wasmSymbols.stringGetLiteral))
body.commentGroupEnd()
} }
else -> error("Unknown constant kind") else -> error("Unknown constant kind")
} }
@@ -95,6 +95,9 @@ sealed class WasmImmediate {
class HeapType(val value: WasmHeapType) : WasmImmediate() { class HeapType(val value: WasmHeapType) : WasmImmediate() {
constructor(type: WasmType) : this(type.getHeapType()) 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. // 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("<comment-single>", WASM_OP_PSEUDO_OPCODE),
PSEUDO_COMMENT_GROUP_START("<comment-group-start>", WASM_OP_PSEUDO_OPCODE),
PSEUDO_COMMENT_GROUP_END("<comment-group-end>", WASM_OP_PSEUDO_OPCODE),
; ;
constructor(mnemonic: String, opcode: Int, vararg immediates: WasmImmediateKind) : this(mnemonic, opcode, immediates.toList()) constructor(mnemonic: String, opcode: Int, vararg immediates: WasmImmediateKind) : this(mnemonic, opcode, immediates.toList())
} }
const val WASM_OP_PSEUDO_OPCODE = 0xFFFF
val opcodesToOp: Map<Int, WasmOp> = val opcodesToOp: Map<Int, WasmOp> =
enumValues<WasmOp>().associateBy { it.opcode } enumValues<WasmOp>().associateBy { it.opcode }
@@ -178,4 +178,16 @@ abstract class WasmExpressionBuilder {
fun buildDrop() { fun buildDrop() {
buildInstr(WasmOp.DROP) 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)
}
} }
@@ -210,6 +210,10 @@ class WasmIrToBinary(
} }
val opcode = instr.operator.opcode val opcode = instr.operator.opcode
if (opcode == WASM_OP_PSEUDO_OPCODE)
return
if (opcode > 0xFF) { if (opcode > 0xFF) {
b.writeByte((opcode ushr 8).toByte()) b.writeByte((opcode ushr 8).toByte())
b.writeByte((opcode and 0xFF).toByte()) b.writeByte((opcode and 0xFF).toByte())
@@ -259,6 +263,8 @@ class WasmIrToBinary(
is WasmImmediate.GcType -> appendModuleFieldReference(x.value.owner) is WasmImmediate.GcType -> appendModuleFieldReference(x.value.owner)
is WasmImmediate.StructFieldIdx -> b.writeVarUInt32(x.value.owner) is WasmImmediate.StructFieldIdx -> b.writeVarUInt32(x.value.owner)
is WasmImmediate.HeapType -> appendHeapType(x.value) is WasmImmediate.HeapType -> appendHeapType(x.value)
is WasmImmediate.ConstString ->
error("Instructions with pseudo immediates should be skipped")
} }
} }
@@ -60,6 +60,34 @@ class WasmIrToText : SExpressionBuilder() {
private fun appendInstr(wasmInstr: WasmInstr) { private fun appendInstr(wasmInstr: WasmInstr) {
val op = wasmInstr.operator 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) if (op == WasmOp.END || op == WasmOp.ELSE || op == WasmOp.CATCH)
indent-- indent--
@@ -113,6 +141,8 @@ class WasmIrToText : SExpressionBuilder() {
is WasmImmediate.HeapType -> { is WasmImmediate.HeapType -> {
appendHeapType(x.value) appendHeapType(x.value)
} }
is WasmImmediate.ConstString -> error("Pseudo immediate")
} }
} }