diff --git a/Sources/WAT/Encoder.swift b/Sources/WAT/Encoder.swift index 1eec7a04..ec76b9a5 100644 --- a/Sources/WAT/Encoder.swift +++ b/Sources/WAT/Encoder.swift @@ -158,10 +158,6 @@ struct ElementExprCollector: AnyInstructionVisitor { typealias Output = Void var isAllRefFunc: Bool = true - var useExpression: Bool { - // if all instructions are ref.func, use function indices representation - return !isAllRefFunc - } var instructions: [Instruction] = [] mutating func parse(indices: WatParser.ElementDecl.Indices, wat: inout Wat) throws { @@ -234,8 +230,11 @@ extension WAT.WatParser.ElementDecl { var collector = ElementExprCollector() try collector.parse(indices: indices, wat: &wat) - - if collector.useExpression { + var useExpression: Bool { + // if all instructions are ref.func, use function indices representation + return !collector.isAllRefFunc || self.type != .funcRef + } + if useExpression { // use expression flags |= 0b0100 } @@ -262,7 +261,7 @@ extension WAT.WatParser.ElementDecl { } } if isPassive || hasTableIndex { - if collector.useExpression { + if useExpression { encoder.encode(type) } else { // Write ExternKind.func @@ -270,7 +269,7 @@ extension WAT.WatParser.ElementDecl { } } - if collector.useExpression { + if useExpression { try encoder.encodeVector(collector.instructions) { instruction, encoder in var exprEncoder = ExpressionEncoder() switch instruction { diff --git a/Sources/WAT/InstructionEncoder.swift b/Sources/WAT/InstructionEncoder.swift new file mode 100644 index 00000000..b39d46c3 --- /dev/null +++ b/Sources/WAT/InstructionEncoder.swift @@ -0,0 +1,411 @@ +// swift-format-ignore-file +//// Automatically generated by Utilities/Sources/WasmGen.swift +//// DO NOT EDIT DIRECTLY + +import WasmParser +import WasmTypes + +/// An instruction encoder that is responsible for encoding opcodes and immediates. +protocol InstructionEncoder: InstructionVisitor { + /// Encodes an instruction opcode. + mutating func encodeInstruction(_ opcode: UInt8, _ prefix: UInt8?) throws + + // MARK: - Immediates encoding + mutating func encodeImmediates(blockType: BlockType) throws + mutating func encodeImmediates(dataIndex: UInt32) throws + mutating func encodeImmediates(elemIndex: UInt32) throws + mutating func encodeImmediates(functionIndex: UInt32) throws + mutating func encodeImmediates(globalIndex: UInt32) throws + mutating func encodeImmediates(localIndex: UInt32) throws + mutating func encodeImmediates(memarg: MemArg) throws + mutating func encodeImmediates(memory: UInt32) throws + mutating func encodeImmediates(relativeDepth: UInt32) throws + mutating func encodeImmediates(table: UInt32) throws + mutating func encodeImmediates(targets: BrTable) throws + mutating func encodeImmediates(type: ReferenceType) throws + mutating func encodeImmediates(type: ValueType) throws + mutating func encodeImmediates(value: IEEE754.Float32) throws + mutating func encodeImmediates(value: IEEE754.Float64) throws + mutating func encodeImmediates(value: Int32) throws + mutating func encodeImmediates(value: Int64) throws + mutating func encodeImmediates(dstMem: UInt32, srcMem: UInt32) throws + mutating func encodeImmediates(dstTable: UInt32, srcTable: UInt32) throws + mutating func encodeImmediates(elemIndex: UInt32, table: UInt32) throws + mutating func encodeImmediates(typeIndex: UInt32, tableIndex: UInt32) throws +} + +/// NOTE: InstructionEncoder implements the InstructionVisitor protocol to call the corresponding encode method. +extension InstructionEncoder { + mutating func visitUnreachable() throws { try encodeInstruction(0x00, nil) } + mutating func visitNop() throws { try encodeInstruction(0x01, nil) } + mutating func visitBlock(blockType: BlockType) throws { + try encodeInstruction(0x02, nil) + try encodeImmediates(blockType: blockType) + } + mutating func visitLoop(blockType: BlockType) throws { + try encodeInstruction(0x03, nil) + try encodeImmediates(blockType: blockType) + } + mutating func visitIf(blockType: BlockType) throws { + try encodeInstruction(0x04, nil) + try encodeImmediates(blockType: blockType) + } + mutating func visitElse() throws { try encodeInstruction(0x05, nil) } + mutating func visitEnd() throws { try encodeInstruction(0x0B, nil) } + mutating func visitBr(relativeDepth: UInt32) throws { + try encodeInstruction(0x0C, nil) + try encodeImmediates(relativeDepth: relativeDepth) + } + mutating func visitBrIf(relativeDepth: UInt32) throws { + try encodeInstruction(0x0D, nil) + try encodeImmediates(relativeDepth: relativeDepth) + } + mutating func visitBrTable(targets: BrTable) throws { + try encodeInstruction(0x0E, nil) + try encodeImmediates(targets: targets) + } + mutating func visitReturn() throws { try encodeInstruction(0x0F, nil) } + mutating func visitCall(functionIndex: UInt32) throws { + try encodeInstruction(0x10, nil) + try encodeImmediates(functionIndex: functionIndex) + } + mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws { + try encodeInstruction(0x11, nil) + try encodeImmediates(typeIndex: typeIndex, tableIndex: tableIndex) + } + mutating func visitDrop() throws { try encodeInstruction(0x1A, nil) } + mutating func visitSelect() throws { try encodeInstruction(0x1B, nil) } + mutating func visitTypedSelect(type: ValueType) throws { + try encodeInstruction(0x1C, nil) + try encodeImmediates(type: type) + } + mutating func visitLocalGet(localIndex: UInt32) throws { + try encodeInstruction(0x20, nil) + try encodeImmediates(localIndex: localIndex) + } + mutating func visitLocalSet(localIndex: UInt32) throws { + try encodeInstruction(0x21, nil) + try encodeImmediates(localIndex: localIndex) + } + mutating func visitLocalTee(localIndex: UInt32) throws { + try encodeInstruction(0x22, nil) + try encodeImmediates(localIndex: localIndex) + } + mutating func visitGlobalGet(globalIndex: UInt32) throws { + try encodeInstruction(0x23, nil) + try encodeImmediates(globalIndex: globalIndex) + } + mutating func visitGlobalSet(globalIndex: UInt32) throws { + try encodeInstruction(0x24, nil) + try encodeImmediates(globalIndex: globalIndex) + } + mutating func visitI32Load(memarg: MemArg) throws { + try encodeInstruction(0x28, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Load(memarg: MemArg) throws { + try encodeInstruction(0x29, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitF32Load(memarg: MemArg) throws { + try encodeInstruction(0x2A, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitF64Load(memarg: MemArg) throws { + try encodeInstruction(0x2B, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI32Load8S(memarg: MemArg) throws { + try encodeInstruction(0x2C, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI32Load8U(memarg: MemArg) throws { + try encodeInstruction(0x2D, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI32Load16S(memarg: MemArg) throws { + try encodeInstruction(0x2E, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI32Load16U(memarg: MemArg) throws { + try encodeInstruction(0x2F, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Load8S(memarg: MemArg) throws { + try encodeInstruction(0x30, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Load8U(memarg: MemArg) throws { + try encodeInstruction(0x31, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Load16S(memarg: MemArg) throws { + try encodeInstruction(0x32, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Load16U(memarg: MemArg) throws { + try encodeInstruction(0x33, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Load32S(memarg: MemArg) throws { + try encodeInstruction(0x34, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Load32U(memarg: MemArg) throws { + try encodeInstruction(0x35, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI32Store(memarg: MemArg) throws { + try encodeInstruction(0x36, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Store(memarg: MemArg) throws { + try encodeInstruction(0x37, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitF32Store(memarg: MemArg) throws { + try encodeInstruction(0x38, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitF64Store(memarg: MemArg) throws { + try encodeInstruction(0x39, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI32Store8(memarg: MemArg) throws { + try encodeInstruction(0x3A, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI32Store16(memarg: MemArg) throws { + try encodeInstruction(0x3B, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Store8(memarg: MemArg) throws { + try encodeInstruction(0x3C, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Store16(memarg: MemArg) throws { + try encodeInstruction(0x3D, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitI64Store32(memarg: MemArg) throws { + try encodeInstruction(0x3E, nil) + try encodeImmediates(memarg: memarg) + } + mutating func visitMemorySize(memory: UInt32) throws { + try encodeInstruction(0x3F, nil) + try encodeImmediates(memory: memory) + } + mutating func visitMemoryGrow(memory: UInt32) throws { + try encodeInstruction(0x40, nil) + try encodeImmediates(memory: memory) + } + mutating func visitI32Const(value: Int32) throws { + try encodeInstruction(0x41, nil) + try encodeImmediates(value: value) + } + mutating func visitI64Const(value: Int64) throws { + try encodeInstruction(0x42, nil) + try encodeImmediates(value: value) + } + mutating func visitF32Const(value: IEEE754.Float32) throws { + try encodeInstruction(0x43, nil) + try encodeImmediates(value: value) + } + mutating func visitF64Const(value: IEEE754.Float64) throws { + try encodeInstruction(0x44, nil) + try encodeImmediates(value: value) + } + mutating func visitRefNull(type: ReferenceType) throws { + try encodeInstruction(0xD0, nil) + try encodeImmediates(type: type) + } + mutating func visitRefIsNull() throws { try encodeInstruction(0xD1, nil) } + mutating func visitRefFunc(functionIndex: UInt32) throws { + try encodeInstruction(0xD2, nil) + try encodeImmediates(functionIndex: functionIndex) + } + mutating func visitI32Eqz() throws { try encodeInstruction(0x45, nil) } + mutating func visitI32Eq() throws { try encodeInstruction(0x46, nil) } + mutating func visitI32Ne() throws { try encodeInstruction(0x47, nil) } + mutating func visitI32LtS() throws { try encodeInstruction(0x48, nil) } + mutating func visitI32LtU() throws { try encodeInstruction(0x49, nil) } + mutating func visitI32GtS() throws { try encodeInstruction(0x4A, nil) } + mutating func visitI32GtU() throws { try encodeInstruction(0x4B, nil) } + mutating func visitI32LeS() throws { try encodeInstruction(0x4C, nil) } + mutating func visitI32LeU() throws { try encodeInstruction(0x4D, nil) } + mutating func visitI32GeS() throws { try encodeInstruction(0x4E, nil) } + mutating func visitI32GeU() throws { try encodeInstruction(0x4F, nil) } + mutating func visitI64Eqz() throws { try encodeInstruction(0x50, nil) } + mutating func visitI64Eq() throws { try encodeInstruction(0x51, nil) } + mutating func visitI64Ne() throws { try encodeInstruction(0x52, nil) } + mutating func visitI64LtS() throws { try encodeInstruction(0x53, nil) } + mutating func visitI64LtU() throws { try encodeInstruction(0x54, nil) } + mutating func visitI64GtS() throws { try encodeInstruction(0x55, nil) } + mutating func visitI64GtU() throws { try encodeInstruction(0x56, nil) } + mutating func visitI64LeS() throws { try encodeInstruction(0x57, nil) } + mutating func visitI64LeU() throws { try encodeInstruction(0x58, nil) } + mutating func visitI64GeS() throws { try encodeInstruction(0x59, nil) } + mutating func visitI64GeU() throws { try encodeInstruction(0x5A, nil) } + mutating func visitF32Eq() throws { try encodeInstruction(0x5B, nil) } + mutating func visitF32Ne() throws { try encodeInstruction(0x5C, nil) } + mutating func visitF32Lt() throws { try encodeInstruction(0x5D, nil) } + mutating func visitF32Gt() throws { try encodeInstruction(0x5E, nil) } + mutating func visitF32Le() throws { try encodeInstruction(0x5F, nil) } + mutating func visitF32Ge() throws { try encodeInstruction(0x60, nil) } + mutating func visitF64Eq() throws { try encodeInstruction(0x61, nil) } + mutating func visitF64Ne() throws { try encodeInstruction(0x62, nil) } + mutating func visitF64Lt() throws { try encodeInstruction(0x63, nil) } + mutating func visitF64Gt() throws { try encodeInstruction(0x64, nil) } + mutating func visitF64Le() throws { try encodeInstruction(0x65, nil) } + mutating func visitF64Ge() throws { try encodeInstruction(0x66, nil) } + mutating func visitI32Clz() throws { try encodeInstruction(0x67, nil) } + mutating func visitI32Ctz() throws { try encodeInstruction(0x68, nil) } + mutating func visitI32Popcnt() throws { try encodeInstruction(0x69, nil) } + mutating func visitI32Add() throws { try encodeInstruction(0x6A, nil) } + mutating func visitI32Sub() throws { try encodeInstruction(0x6B, nil) } + mutating func visitI32Mul() throws { try encodeInstruction(0x6C, nil) } + mutating func visitI32DivS() throws { try encodeInstruction(0x6D, nil) } + mutating func visitI32DivU() throws { try encodeInstruction(0x6E, nil) } + mutating func visitI32RemS() throws { try encodeInstruction(0x6F, nil) } + mutating func visitI32RemU() throws { try encodeInstruction(0x70, nil) } + mutating func visitI32And() throws { try encodeInstruction(0x71, nil) } + mutating func visitI32Or() throws { try encodeInstruction(0x72, nil) } + mutating func visitI32Xor() throws { try encodeInstruction(0x73, nil) } + mutating func visitI32Shl() throws { try encodeInstruction(0x74, nil) } + mutating func visitI32ShrS() throws { try encodeInstruction(0x75, nil) } + mutating func visitI32ShrU() throws { try encodeInstruction(0x76, nil) } + mutating func visitI32Rotl() throws { try encodeInstruction(0x77, nil) } + mutating func visitI32Rotr() throws { try encodeInstruction(0x78, nil) } + mutating func visitI64Clz() throws { try encodeInstruction(0x79, nil) } + mutating func visitI64Ctz() throws { try encodeInstruction(0x7A, nil) } + mutating func visitI64Popcnt() throws { try encodeInstruction(0x7B, nil) } + mutating func visitI64Add() throws { try encodeInstruction(0x7C, nil) } + mutating func visitI64Sub() throws { try encodeInstruction(0x7D, nil) } + mutating func visitI64Mul() throws { try encodeInstruction(0x7E, nil) } + mutating func visitI64DivS() throws { try encodeInstruction(0x7F, nil) } + mutating func visitI64DivU() throws { try encodeInstruction(0x80, nil) } + mutating func visitI64RemS() throws { try encodeInstruction(0x81, nil) } + mutating func visitI64RemU() throws { try encodeInstruction(0x82, nil) } + mutating func visitI64And() throws { try encodeInstruction(0x83, nil) } + mutating func visitI64Or() throws { try encodeInstruction(0x84, nil) } + mutating func visitI64Xor() throws { try encodeInstruction(0x85, nil) } + mutating func visitI64Shl() throws { try encodeInstruction(0x86, nil) } + mutating func visitI64ShrS() throws { try encodeInstruction(0x87, nil) } + mutating func visitI64ShrU() throws { try encodeInstruction(0x88, nil) } + mutating func visitI64Rotl() throws { try encodeInstruction(0x89, nil) } + mutating func visitI64Rotr() throws { try encodeInstruction(0x8A, nil) } + mutating func visitF32Abs() throws { try encodeInstruction(0x8B, nil) } + mutating func visitF32Neg() throws { try encodeInstruction(0x8C, nil) } + mutating func visitF32Ceil() throws { try encodeInstruction(0x8D, nil) } + mutating func visitF32Floor() throws { try encodeInstruction(0x8E, nil) } + mutating func visitF32Trunc() throws { try encodeInstruction(0x8F, nil) } + mutating func visitF32Nearest() throws { try encodeInstruction(0x90, nil) } + mutating func visitF32Sqrt() throws { try encodeInstruction(0x91, nil) } + mutating func visitF32Add() throws { try encodeInstruction(0x92, nil) } + mutating func visitF32Sub() throws { try encodeInstruction(0x93, nil) } + mutating func visitF32Mul() throws { try encodeInstruction(0x94, nil) } + mutating func visitF32Div() throws { try encodeInstruction(0x95, nil) } + mutating func visitF32Min() throws { try encodeInstruction(0x96, nil) } + mutating func visitF32Max() throws { try encodeInstruction(0x97, nil) } + mutating func visitF32Copysign() throws { try encodeInstruction(0x98, nil) } + mutating func visitF64Abs() throws { try encodeInstruction(0x99, nil) } + mutating func visitF64Neg() throws { try encodeInstruction(0x9A, nil) } + mutating func visitF64Ceil() throws { try encodeInstruction(0x9B, nil) } + mutating func visitF64Floor() throws { try encodeInstruction(0x9C, nil) } + mutating func visitF64Trunc() throws { try encodeInstruction(0x9D, nil) } + mutating func visitF64Nearest() throws { try encodeInstruction(0x9E, nil) } + mutating func visitF64Sqrt() throws { try encodeInstruction(0x9F, nil) } + mutating func visitF64Add() throws { try encodeInstruction(0xA0, nil) } + mutating func visitF64Sub() throws { try encodeInstruction(0xA1, nil) } + mutating func visitF64Mul() throws { try encodeInstruction(0xA2, nil) } + mutating func visitF64Div() throws { try encodeInstruction(0xA3, nil) } + mutating func visitF64Min() throws { try encodeInstruction(0xA4, nil) } + mutating func visitF64Max() throws { try encodeInstruction(0xA5, nil) } + mutating func visitF64Copysign() throws { try encodeInstruction(0xA6, nil) } + mutating func visitI32WrapI64() throws { try encodeInstruction(0xA7, nil) } + mutating func visitI32TruncF32S() throws { try encodeInstruction(0xA8, nil) } + mutating func visitI32TruncF32U() throws { try encodeInstruction(0xA9, nil) } + mutating func visitI32TruncF64S() throws { try encodeInstruction(0xAA, nil) } + mutating func visitI32TruncF64U() throws { try encodeInstruction(0xAB, nil) } + mutating func visitI64ExtendI32S() throws { try encodeInstruction(0xAC, nil) } + mutating func visitI64ExtendI32U() throws { try encodeInstruction(0xAD, nil) } + mutating func visitI64TruncF32S() throws { try encodeInstruction(0xAE, nil) } + mutating func visitI64TruncF32U() throws { try encodeInstruction(0xAF, nil) } + mutating func visitI64TruncF64S() throws { try encodeInstruction(0xB0, nil) } + mutating func visitI64TruncF64U() throws { try encodeInstruction(0xB1, nil) } + mutating func visitF32ConvertI32S() throws { try encodeInstruction(0xB2, nil) } + mutating func visitF32ConvertI32U() throws { try encodeInstruction(0xB3, nil) } + mutating func visitF32ConvertI64S() throws { try encodeInstruction(0xB4, nil) } + mutating func visitF32ConvertI64U() throws { try encodeInstruction(0xB5, nil) } + mutating func visitF32DemoteF64() throws { try encodeInstruction(0xB6, nil) } + mutating func visitF64ConvertI32S() throws { try encodeInstruction(0xB7, nil) } + mutating func visitF64ConvertI32U() throws { try encodeInstruction(0xB8, nil) } + mutating func visitF64ConvertI64S() throws { try encodeInstruction(0xB9, nil) } + mutating func visitF64ConvertI64U() throws { try encodeInstruction(0xBA, nil) } + mutating func visitF64PromoteF32() throws { try encodeInstruction(0xBB, nil) } + mutating func visitI32ReinterpretF32() throws { try encodeInstruction(0xBC, nil) } + mutating func visitI64ReinterpretF64() throws { try encodeInstruction(0xBD, nil) } + mutating func visitF32ReinterpretI32() throws { try encodeInstruction(0xBE, nil) } + mutating func visitF64ReinterpretI64() throws { try encodeInstruction(0xBF, nil) } + mutating func visitI32Extend8S() throws { try encodeInstruction(0xC0, nil) } + mutating func visitI32Extend16S() throws { try encodeInstruction(0xC1, nil) } + mutating func visitI64Extend8S() throws { try encodeInstruction(0xC2, nil) } + mutating func visitI64Extend16S() throws { try encodeInstruction(0xC3, nil) } + mutating func visitI64Extend32S() throws { try encodeInstruction(0xC4, nil) } + mutating func visitMemoryInit(dataIndex: UInt32) throws { + try encodeInstruction(0x08, 0xFC) + try encodeImmediates(dataIndex: dataIndex) + } + mutating func visitDataDrop(dataIndex: UInt32) throws { + try encodeInstruction(0x09, 0xFC) + try encodeImmediates(dataIndex: dataIndex) + } + mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws { + try encodeInstruction(0x0A, 0xFC) + try encodeImmediates(dstMem: dstMem, srcMem: srcMem) + } + mutating func visitMemoryFill(memory: UInt32) throws { + try encodeInstruction(0x0B, 0xFC) + try encodeImmediates(memory: memory) + } + mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws { + try encodeInstruction(0x0C, 0xFC) + try encodeImmediates(elemIndex: elemIndex, table: table) + } + mutating func visitElemDrop(elemIndex: UInt32) throws { + try encodeInstruction(0x0D, 0xFC) + try encodeImmediates(elemIndex: elemIndex) + } + mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws { + try encodeInstruction(0x0E, 0xFC) + try encodeImmediates(dstTable: dstTable, srcTable: srcTable) + } + mutating func visitTableFill(table: UInt32) throws { + try encodeInstruction(0x11, 0xFC) + try encodeImmediates(table: table) + } + mutating func visitTableGet(table: UInt32) throws { + try encodeInstruction(0x25, nil) + try encodeImmediates(table: table) + } + mutating func visitTableSet(table: UInt32) throws { + try encodeInstruction(0x26, nil) + try encodeImmediates(table: table) + } + mutating func visitTableGrow(table: UInt32) throws { + try encodeInstruction(0x0F, 0xFC) + try encodeImmediates(table: table) + } + mutating func visitTableSize(table: UInt32) throws { + try encodeInstruction(0x10, 0xFC) + try encodeImmediates(table: table) + } + mutating func visitI32TruncSatF32S() throws { try encodeInstruction(0x00, 0xFC) } + mutating func visitI32TruncSatF32U() throws { try encodeInstruction(0x01, 0xFC) } + mutating func visitI32TruncSatF64S() throws { try encodeInstruction(0x02, 0xFC) } + mutating func visitI32TruncSatF64U() throws { try encodeInstruction(0x03, 0xFC) } + mutating func visitI64TruncSatF32S() throws { try encodeInstruction(0x04, 0xFC) } + mutating func visitI64TruncSatF32U() throws { try encodeInstruction(0x05, 0xFC) } + mutating func visitI64TruncSatF64S() throws { try encodeInstruction(0x06, 0xFC) } + mutating func visitI64TruncSatF64U() throws { try encodeInstruction(0x07, 0xFC) } +} diff --git a/Sources/WAT/ParseInstruction.swift b/Sources/WAT/ParseInstruction.swift index 6f2a1499..4cb90805 100644 --- a/Sources/WAT/ParseInstruction.swift +++ b/Sources/WAT/ParseInstruction.swift @@ -12,7 +12,7 @@ import WasmTypes /// - Returns: A closure that invokes the corresponding visitor method. Nil if the keyword is not recognized. /// /// Note: The returned closure does not consume any tokens. -func parseTextInstruction(keyword: String, expressionParser: inout ExpressionParser, wat: inout Wat) throws -> ((inout V) throws -> V.Output)? { +func parseTextInstruction(keyword: String, expressionParser: inout ExpressionParser, wat: inout Wat) throws -> ((inout V) throws -> Void)? { switch keyword { case "unreachable": return { return try $0.visitUnreachable() } case "nop": return { return try $0.visitNop() } @@ -329,404 +329,3 @@ func parseTextInstruction(keyword: String, expressionPars default: return nil } } - - -protocol InstructionEncoder: InstructionVisitor { - mutating func encodeInstruction(_ opcode: UInt8, _ prefix: UInt8?) throws - mutating func encodeImmediates(blockType: BlockType) throws - mutating func encodeImmediates(dataIndex: UInt32) throws - mutating func encodeImmediates(elemIndex: UInt32) throws - mutating func encodeImmediates(functionIndex: UInt32) throws - mutating func encodeImmediates(globalIndex: UInt32) throws - mutating func encodeImmediates(localIndex: UInt32) throws - mutating func encodeImmediates(memarg: MemArg) throws - mutating func encodeImmediates(memory: UInt32) throws - mutating func encodeImmediates(relativeDepth: UInt32) throws - mutating func encodeImmediates(table: UInt32) throws - mutating func encodeImmediates(targets: BrTable) throws - mutating func encodeImmediates(type: ReferenceType) throws - mutating func encodeImmediates(type: ValueType) throws - mutating func encodeImmediates(value: IEEE754.Float32) throws - mutating func encodeImmediates(value: IEEE754.Float64) throws - mutating func encodeImmediates(value: Int32) throws - mutating func encodeImmediates(value: Int64) throws - mutating func encodeImmediates(dstMem: UInt32, srcMem: UInt32) throws - mutating func encodeImmediates(dstTable: UInt32, srcTable: UInt32) throws - mutating func encodeImmediates(elemIndex: UInt32, table: UInt32) throws - mutating func encodeImmediates(typeIndex: UInt32, tableIndex: UInt32) throws -} - -extension InstructionEncoder { - mutating func visitUnreachable() throws { try encodeInstruction(0x00, nil) } - mutating func visitNop() throws { try encodeInstruction(0x01, nil) } - mutating func visitBlock(blockType: BlockType) throws { - try encodeInstruction(0x02, nil) - try encodeImmediates(blockType: blockType) - } - mutating func visitLoop(blockType: BlockType) throws { - try encodeInstruction(0x03, nil) - try encodeImmediates(blockType: blockType) - } - mutating func visitIf(blockType: BlockType) throws { - try encodeInstruction(0x04, nil) - try encodeImmediates(blockType: blockType) - } - mutating func visitElse() throws { try encodeInstruction(0x05, nil) } - mutating func visitEnd() throws { try encodeInstruction(0x0B, nil) } - mutating func visitBr(relativeDepth: UInt32) throws { - try encodeInstruction(0x0C, nil) - try encodeImmediates(relativeDepth: relativeDepth) - } - mutating func visitBrIf(relativeDepth: UInt32) throws { - try encodeInstruction(0x0D, nil) - try encodeImmediates(relativeDepth: relativeDepth) - } - mutating func visitBrTable(targets: BrTable) throws { - try encodeInstruction(0x0E, nil) - try encodeImmediates(targets: targets) - } - mutating func visitReturn() throws { try encodeInstruction(0x0F, nil) } - mutating func visitCall(functionIndex: UInt32) throws { - try encodeInstruction(0x10, nil) - try encodeImmediates(functionIndex: functionIndex) - } - mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws { - try encodeInstruction(0x11, nil) - try encodeImmediates(typeIndex: typeIndex, tableIndex: tableIndex) - } - mutating func visitDrop() throws { try encodeInstruction(0x1A, nil) } - mutating func visitSelect() throws { try encodeInstruction(0x1B, nil) } - mutating func visitTypedSelect(type: ValueType) throws { - try encodeInstruction(0x1C, nil) - try encodeImmediates(type: type) - } - mutating func visitLocalGet(localIndex: UInt32) throws { - try encodeInstruction(0x20, nil) - try encodeImmediates(localIndex: localIndex) - } - mutating func visitLocalSet(localIndex: UInt32) throws { - try encodeInstruction(0x21, nil) - try encodeImmediates(localIndex: localIndex) - } - mutating func visitLocalTee(localIndex: UInt32) throws { - try encodeInstruction(0x22, nil) - try encodeImmediates(localIndex: localIndex) - } - mutating func visitGlobalGet(globalIndex: UInt32) throws { - try encodeInstruction(0x23, nil) - try encodeImmediates(globalIndex: globalIndex) - } - mutating func visitGlobalSet(globalIndex: UInt32) throws { - try encodeInstruction(0x24, nil) - try encodeImmediates(globalIndex: globalIndex) - } - mutating func visitI32Load(memarg: MemArg) throws { - try encodeInstruction(0x28, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Load(memarg: MemArg) throws { - try encodeInstruction(0x29, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitF32Load(memarg: MemArg) throws { - try encodeInstruction(0x2A, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitF64Load(memarg: MemArg) throws { - try encodeInstruction(0x2B, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI32Load8S(memarg: MemArg) throws { - try encodeInstruction(0x2C, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI32Load8U(memarg: MemArg) throws { - try encodeInstruction(0x2D, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI32Load16S(memarg: MemArg) throws { - try encodeInstruction(0x2E, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI32Load16U(memarg: MemArg) throws { - try encodeInstruction(0x2F, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Load8S(memarg: MemArg) throws { - try encodeInstruction(0x30, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Load8U(memarg: MemArg) throws { - try encodeInstruction(0x31, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Load16S(memarg: MemArg) throws { - try encodeInstruction(0x32, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Load16U(memarg: MemArg) throws { - try encodeInstruction(0x33, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Load32S(memarg: MemArg) throws { - try encodeInstruction(0x34, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Load32U(memarg: MemArg) throws { - try encodeInstruction(0x35, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI32Store(memarg: MemArg) throws { - try encodeInstruction(0x36, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Store(memarg: MemArg) throws { - try encodeInstruction(0x37, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitF32Store(memarg: MemArg) throws { - try encodeInstruction(0x38, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitF64Store(memarg: MemArg) throws { - try encodeInstruction(0x39, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI32Store8(memarg: MemArg) throws { - try encodeInstruction(0x3A, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI32Store16(memarg: MemArg) throws { - try encodeInstruction(0x3B, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Store8(memarg: MemArg) throws { - try encodeInstruction(0x3C, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Store16(memarg: MemArg) throws { - try encodeInstruction(0x3D, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitI64Store32(memarg: MemArg) throws { - try encodeInstruction(0x3E, nil) - try encodeImmediates(memarg: memarg) - } - mutating func visitMemorySize(memory: UInt32) throws { - try encodeInstruction(0x3F, nil) - try encodeImmediates(memory: memory) - } - mutating func visitMemoryGrow(memory: UInt32) throws { - try encodeInstruction(0x40, nil) - try encodeImmediates(memory: memory) - } - mutating func visitI32Const(value: Int32) throws { - try encodeInstruction(0x41, nil) - try encodeImmediates(value: value) - } - mutating func visitI64Const(value: Int64) throws { - try encodeInstruction(0x42, nil) - try encodeImmediates(value: value) - } - mutating func visitF32Const(value: IEEE754.Float32) throws { - try encodeInstruction(0x43, nil) - try encodeImmediates(value: value) - } - mutating func visitF64Const(value: IEEE754.Float64) throws { - try encodeInstruction(0x44, nil) - try encodeImmediates(value: value) - } - mutating func visitRefNull(type: ReferenceType) throws { - try encodeInstruction(0xD0, nil) - try encodeImmediates(type: type) - } - mutating func visitRefIsNull() throws { try encodeInstruction(0xD1, nil) } - mutating func visitRefFunc(functionIndex: UInt32) throws { - try encodeInstruction(0xD2, nil) - try encodeImmediates(functionIndex: functionIndex) - } - mutating func visitI32Eqz() throws { try encodeInstruction(0x45, nil) } - mutating func visitI32Eq() throws { try encodeInstruction(0x46, nil) } - mutating func visitI32Ne() throws { try encodeInstruction(0x47, nil) } - mutating func visitI32LtS() throws { try encodeInstruction(0x48, nil) } - mutating func visitI32LtU() throws { try encodeInstruction(0x49, nil) } - mutating func visitI32GtS() throws { try encodeInstruction(0x4A, nil) } - mutating func visitI32GtU() throws { try encodeInstruction(0x4B, nil) } - mutating func visitI32LeS() throws { try encodeInstruction(0x4C, nil) } - mutating func visitI32LeU() throws { try encodeInstruction(0x4D, nil) } - mutating func visitI32GeS() throws { try encodeInstruction(0x4E, nil) } - mutating func visitI32GeU() throws { try encodeInstruction(0x4F, nil) } - mutating func visitI64Eqz() throws { try encodeInstruction(0x50, nil) } - mutating func visitI64Eq() throws { try encodeInstruction(0x51, nil) } - mutating func visitI64Ne() throws { try encodeInstruction(0x52, nil) } - mutating func visitI64LtS() throws { try encodeInstruction(0x53, nil) } - mutating func visitI64LtU() throws { try encodeInstruction(0x54, nil) } - mutating func visitI64GtS() throws { try encodeInstruction(0x55, nil) } - mutating func visitI64GtU() throws { try encodeInstruction(0x56, nil) } - mutating func visitI64LeS() throws { try encodeInstruction(0x57, nil) } - mutating func visitI64LeU() throws { try encodeInstruction(0x58, nil) } - mutating func visitI64GeS() throws { try encodeInstruction(0x59, nil) } - mutating func visitI64GeU() throws { try encodeInstruction(0x5A, nil) } - mutating func visitF32Eq() throws { try encodeInstruction(0x5B, nil) } - mutating func visitF32Ne() throws { try encodeInstruction(0x5C, nil) } - mutating func visitF32Lt() throws { try encodeInstruction(0x5D, nil) } - mutating func visitF32Gt() throws { try encodeInstruction(0x5E, nil) } - mutating func visitF32Le() throws { try encodeInstruction(0x5F, nil) } - mutating func visitF32Ge() throws { try encodeInstruction(0x60, nil) } - mutating func visitF64Eq() throws { try encodeInstruction(0x61, nil) } - mutating func visitF64Ne() throws { try encodeInstruction(0x62, nil) } - mutating func visitF64Lt() throws { try encodeInstruction(0x63, nil) } - mutating func visitF64Gt() throws { try encodeInstruction(0x64, nil) } - mutating func visitF64Le() throws { try encodeInstruction(0x65, nil) } - mutating func visitF64Ge() throws { try encodeInstruction(0x66, nil) } - mutating func visitI32Clz() throws { try encodeInstruction(0x67, nil) } - mutating func visitI32Ctz() throws { try encodeInstruction(0x68, nil) } - mutating func visitI32Popcnt() throws { try encodeInstruction(0x69, nil) } - mutating func visitI32Add() throws { try encodeInstruction(0x6A, nil) } - mutating func visitI32Sub() throws { try encodeInstruction(0x6B, nil) } - mutating func visitI32Mul() throws { try encodeInstruction(0x6C, nil) } - mutating func visitI32DivS() throws { try encodeInstruction(0x6D, nil) } - mutating func visitI32DivU() throws { try encodeInstruction(0x6E, nil) } - mutating func visitI32RemS() throws { try encodeInstruction(0x6F, nil) } - mutating func visitI32RemU() throws { try encodeInstruction(0x70, nil) } - mutating func visitI32And() throws { try encodeInstruction(0x71, nil) } - mutating func visitI32Or() throws { try encodeInstruction(0x72, nil) } - mutating func visitI32Xor() throws { try encodeInstruction(0x73, nil) } - mutating func visitI32Shl() throws { try encodeInstruction(0x74, nil) } - mutating func visitI32ShrS() throws { try encodeInstruction(0x75, nil) } - mutating func visitI32ShrU() throws { try encodeInstruction(0x76, nil) } - mutating func visitI32Rotl() throws { try encodeInstruction(0x77, nil) } - mutating func visitI32Rotr() throws { try encodeInstruction(0x78, nil) } - mutating func visitI64Clz() throws { try encodeInstruction(0x79, nil) } - mutating func visitI64Ctz() throws { try encodeInstruction(0x7A, nil) } - mutating func visitI64Popcnt() throws { try encodeInstruction(0x7B, nil) } - mutating func visitI64Add() throws { try encodeInstruction(0x7C, nil) } - mutating func visitI64Sub() throws { try encodeInstruction(0x7D, nil) } - mutating func visitI64Mul() throws { try encodeInstruction(0x7E, nil) } - mutating func visitI64DivS() throws { try encodeInstruction(0x7F, nil) } - mutating func visitI64DivU() throws { try encodeInstruction(0x80, nil) } - mutating func visitI64RemS() throws { try encodeInstruction(0x81, nil) } - mutating func visitI64RemU() throws { try encodeInstruction(0x82, nil) } - mutating func visitI64And() throws { try encodeInstruction(0x83, nil) } - mutating func visitI64Or() throws { try encodeInstruction(0x84, nil) } - mutating func visitI64Xor() throws { try encodeInstruction(0x85, nil) } - mutating func visitI64Shl() throws { try encodeInstruction(0x86, nil) } - mutating func visitI64ShrS() throws { try encodeInstruction(0x87, nil) } - mutating func visitI64ShrU() throws { try encodeInstruction(0x88, nil) } - mutating func visitI64Rotl() throws { try encodeInstruction(0x89, nil) } - mutating func visitI64Rotr() throws { try encodeInstruction(0x8A, nil) } - mutating func visitF32Abs() throws { try encodeInstruction(0x8B, nil) } - mutating func visitF32Neg() throws { try encodeInstruction(0x8C, nil) } - mutating func visitF32Ceil() throws { try encodeInstruction(0x8D, nil) } - mutating func visitF32Floor() throws { try encodeInstruction(0x8E, nil) } - mutating func visitF32Trunc() throws { try encodeInstruction(0x8F, nil) } - mutating func visitF32Nearest() throws { try encodeInstruction(0x90, nil) } - mutating func visitF32Sqrt() throws { try encodeInstruction(0x91, nil) } - mutating func visitF32Add() throws { try encodeInstruction(0x92, nil) } - mutating func visitF32Sub() throws { try encodeInstruction(0x93, nil) } - mutating func visitF32Mul() throws { try encodeInstruction(0x94, nil) } - mutating func visitF32Div() throws { try encodeInstruction(0x95, nil) } - mutating func visitF32Min() throws { try encodeInstruction(0x96, nil) } - mutating func visitF32Max() throws { try encodeInstruction(0x97, nil) } - mutating func visitF32Copysign() throws { try encodeInstruction(0x98, nil) } - mutating func visitF64Abs() throws { try encodeInstruction(0x99, nil) } - mutating func visitF64Neg() throws { try encodeInstruction(0x9A, nil) } - mutating func visitF64Ceil() throws { try encodeInstruction(0x9B, nil) } - mutating func visitF64Floor() throws { try encodeInstruction(0x9C, nil) } - mutating func visitF64Trunc() throws { try encodeInstruction(0x9D, nil) } - mutating func visitF64Nearest() throws { try encodeInstruction(0x9E, nil) } - mutating func visitF64Sqrt() throws { try encodeInstruction(0x9F, nil) } - mutating func visitF64Add() throws { try encodeInstruction(0xA0, nil) } - mutating func visitF64Sub() throws { try encodeInstruction(0xA1, nil) } - mutating func visitF64Mul() throws { try encodeInstruction(0xA2, nil) } - mutating func visitF64Div() throws { try encodeInstruction(0xA3, nil) } - mutating func visitF64Min() throws { try encodeInstruction(0xA4, nil) } - mutating func visitF64Max() throws { try encodeInstruction(0xA5, nil) } - mutating func visitF64Copysign() throws { try encodeInstruction(0xA6, nil) } - mutating func visitI32WrapI64() throws { try encodeInstruction(0xA7, nil) } - mutating func visitI32TruncF32S() throws { try encodeInstruction(0xA8, nil) } - mutating func visitI32TruncF32U() throws { try encodeInstruction(0xA9, nil) } - mutating func visitI32TruncF64S() throws { try encodeInstruction(0xAA, nil) } - mutating func visitI32TruncF64U() throws { try encodeInstruction(0xAB, nil) } - mutating func visitI64ExtendI32S() throws { try encodeInstruction(0xAC, nil) } - mutating func visitI64ExtendI32U() throws { try encodeInstruction(0xAD, nil) } - mutating func visitI64TruncF32S() throws { try encodeInstruction(0xAE, nil) } - mutating func visitI64TruncF32U() throws { try encodeInstruction(0xAF, nil) } - mutating func visitI64TruncF64S() throws { try encodeInstruction(0xB0, nil) } - mutating func visitI64TruncF64U() throws { try encodeInstruction(0xB1, nil) } - mutating func visitF32ConvertI32S() throws { try encodeInstruction(0xB2, nil) } - mutating func visitF32ConvertI32U() throws { try encodeInstruction(0xB3, nil) } - mutating func visitF32ConvertI64S() throws { try encodeInstruction(0xB4, nil) } - mutating func visitF32ConvertI64U() throws { try encodeInstruction(0xB5, nil) } - mutating func visitF32DemoteF64() throws { try encodeInstruction(0xB6, nil) } - mutating func visitF64ConvertI32S() throws { try encodeInstruction(0xB7, nil) } - mutating func visitF64ConvertI32U() throws { try encodeInstruction(0xB8, nil) } - mutating func visitF64ConvertI64S() throws { try encodeInstruction(0xB9, nil) } - mutating func visitF64ConvertI64U() throws { try encodeInstruction(0xBA, nil) } - mutating func visitF64PromoteF32() throws { try encodeInstruction(0xBB, nil) } - mutating func visitI32ReinterpretF32() throws { try encodeInstruction(0xBC, nil) } - mutating func visitI64ReinterpretF64() throws { try encodeInstruction(0xBD, nil) } - mutating func visitF32ReinterpretI32() throws { try encodeInstruction(0xBE, nil) } - mutating func visitF64ReinterpretI64() throws { try encodeInstruction(0xBF, nil) } - mutating func visitI32Extend8S() throws { try encodeInstruction(0xC0, nil) } - mutating func visitI32Extend16S() throws { try encodeInstruction(0xC1, nil) } - mutating func visitI64Extend8S() throws { try encodeInstruction(0xC2, nil) } - mutating func visitI64Extend16S() throws { try encodeInstruction(0xC3, nil) } - mutating func visitI64Extend32S() throws { try encodeInstruction(0xC4, nil) } - mutating func visitMemoryInit(dataIndex: UInt32) throws { - try encodeInstruction(0x08, 0xFC) - try encodeImmediates(dataIndex: dataIndex) - } - mutating func visitDataDrop(dataIndex: UInt32) throws { - try encodeInstruction(0x09, 0xFC) - try encodeImmediates(dataIndex: dataIndex) - } - mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws { - try encodeInstruction(0x0A, 0xFC) - try encodeImmediates(dstMem: dstMem, srcMem: srcMem) - } - mutating func visitMemoryFill(memory: UInt32) throws { - try encodeInstruction(0x0B, 0xFC) - try encodeImmediates(memory: memory) - } - mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws { - try encodeInstruction(0x0C, 0xFC) - try encodeImmediates(elemIndex: elemIndex, table: table) - } - mutating func visitElemDrop(elemIndex: UInt32) throws { - try encodeInstruction(0x0D, 0xFC) - try encodeImmediates(elemIndex: elemIndex) - } - mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws { - try encodeInstruction(0x0E, 0xFC) - try encodeImmediates(dstTable: dstTable, srcTable: srcTable) - } - mutating func visitTableFill(table: UInt32) throws { - try encodeInstruction(0x11, 0xFC) - try encodeImmediates(table: table) - } - mutating func visitTableGet(table: UInt32) throws { - try encodeInstruction(0x25, nil) - try encodeImmediates(table: table) - } - mutating func visitTableSet(table: UInt32) throws { - try encodeInstruction(0x26, nil) - try encodeImmediates(table: table) - } - mutating func visitTableGrow(table: UInt32) throws { - try encodeInstruction(0x0F, 0xFC) - try encodeImmediates(table: table) - } - mutating func visitTableSize(table: UInt32) throws { - try encodeInstruction(0x10, 0xFC) - try encodeImmediates(table: table) - } - mutating func visitI32TruncSatF32S() throws { try encodeInstruction(0x00, 0xFC) } - mutating func visitI32TruncSatF32U() throws { try encodeInstruction(0x01, 0xFC) } - mutating func visitI32TruncSatF64S() throws { try encodeInstruction(0x02, 0xFC) } - mutating func visitI32TruncSatF64U() throws { try encodeInstruction(0x03, 0xFC) } - mutating func visitI64TruncSatF32S() throws { try encodeInstruction(0x04, 0xFC) } - mutating func visitI64TruncSatF32U() throws { try encodeInstruction(0x05, 0xFC) } - mutating func visitI64TruncSatF64S() throws { try encodeInstruction(0x06, 0xFC) } - mutating func visitI64TruncSatF64U() throws { try encodeInstruction(0x07, 0xFC) } -} diff --git a/Sources/WAT/Parser/ExpressionParser.swift b/Sources/WAT/Parser/ExpressionParser.swift index e886738c..7d7952d6 100644 --- a/Sources/WAT/Parser/ExpressionParser.swift +++ b/Sources/WAT/Parser/ExpressionParser.swift @@ -115,7 +115,7 @@ struct ExpressionParser { var wat = Wat.empty(features: features) // WAST allows extra const value instruction if try parser.takeParenBlockStart("ref.extern") { - _ = try visitor.visitRefExtern(value: parser.expectUnsignedInt()) + try visitor.visitRefExtern(value: parser.expectUnsignedInt()) try parser.expect(.rightParen) return true } @@ -182,7 +182,7 @@ struct ExpressionParser { } private struct Suspense { - let visit: ((inout Visitor, inout ExpressionParser) throws -> Visitor.Output)? + let visit: ((inout Visitor, inout ExpressionParser) throws -> Void)? } private mutating func foldedInstruction(visitor: inout Visitor, wat: inout Wat) throws -> Bool { @@ -256,7 +256,7 @@ struct ExpressionParser { } /// Parse a single instruction without consuming the surrounding parentheses and instruction keyword. - private mutating func parseTextInstruction(keyword: String, wat: inout Wat) throws -> ((inout Visitor) throws -> Visitor.Output) { + private mutating func parseTextInstruction(keyword: String, wat: inout Wat) throws -> ((inout Visitor) throws -> Void) { switch keyword { case "select": // Special handling for "select", which have two variants 1. with type, 2. without type diff --git a/Sources/WAT/Parser/WastParser.swift b/Sources/WAT/Parser/WastParser.swift index 7cd6f39a..cfc69fb1 100644 --- a/Sources/WAT/Parser/WastParser.swift +++ b/Sources/WAT/Parser/WastParser.swift @@ -2,7 +2,7 @@ import WasmParser import WasmTypes protocol WastConstInstructionVisitor: InstructionVisitor { - mutating func visitRefExtern(value: UInt32) throws -> Output + mutating func visitRefExtern(value: UInt32) throws } /// A parser for WAST format. @@ -53,7 +53,7 @@ struct WastParser { return result } - struct ConstExpressionCollector: VoidInstructionVisitor, WastConstInstructionVisitor { + struct ConstExpressionCollector: WastConstInstructionVisitor { let addValue: (Value) -> Void mutating func visitI32Const(value: Int32) throws { addValue(.i32(UInt32(bitPattern: value))) } diff --git a/Sources/WasmKit/CMakeLists.txt b/Sources/WasmKit/CMakeLists.txt index f7594f06..256aed0c 100644 --- a/Sources/WasmKit/CMakeLists.txt +++ b/Sources/WasmKit/CMakeLists.txt @@ -4,6 +4,7 @@ add_wasmkit_library(WasmKit Module.swift ModuleParser.swift Translator.swift + Validator.swift ResourceLimiter.swift Component/CanonicalLifting.swift Component/CanonicalLowering.swift diff --git a/Sources/WasmKit/Execution/ConstEvaluation.swift b/Sources/WasmKit/Execution/ConstEvaluation.swift index 7b022fd1..396180b3 100644 --- a/Sources/WasmKit/Execution/ConstEvaluation.swift +++ b/Sources/WasmKit/Execution/ConstEvaluation.swift @@ -5,20 +5,33 @@ protocol ConstEvaluationContextProtocol { func globalValue(_ index: GlobalIndex) throws -> Value } -extension InternalInstance: ConstEvaluationContextProtocol { - func functionRef(_ index: FunctionIndex) throws -> Reference { - return try .function(from: self.functions[validating: Int(index)]) - } - func globalValue(_ index: GlobalIndex) throws -> Value { - return try self.globals[validating: Int(index)].value - } -} - struct ConstEvaluationContext: ConstEvaluationContextProtocol { let functions: ImmutableArray var globals: [Value] + let onFunctionReferenced: ((InternalFunction) -> Void)? + + init( + functions: ImmutableArray, + globals: [Value], + onFunctionReferenced: ((InternalFunction) -> Void)? = nil + ) { + self.functions = functions + self.globals = globals + self.onFunctionReferenced = onFunctionReferenced + } + + init(instance: InternalInstance, moduleImports: ModuleImports) { + // Constant expressions can only reference imported globals + let externalGlobals = instance.globals + .prefix(moduleImports.numberOfGlobals) + .map { $0.value } + self.init(functions: instance.functions, globals: Array(externalGlobals)) + } + func functionRef(_ index: FunctionIndex) throws -> Reference { - return try .function(from: self.functions[validating: Int(index)]) + let function = try self.functions[validating: Int(index)] + self.onFunctionReferenced?(function) + return .function(from: function) } func globalValue(_ index: GlobalIndex) throws -> Value { guard index < globals.count else { @@ -29,7 +42,13 @@ struct ConstEvaluationContext: ConstEvaluationContextProtocol { } extension ConstExpression { - func evaluate(context: C) throws -> Value { + func evaluate(context: C, expectedType: WasmTypes.ValueType) throws -> Value { + let result = try self._evaluate(context: context) + try result.checkType(expectedType) + return result + } + + private func _evaluate(context: C) throws -> Value { guard self.last == .end, self.count == 2 else { throw InstantiationError.unsupported("Expect `end` at the end of offset expression") } @@ -56,25 +75,58 @@ extension ConstExpression { extension WasmParser.ElementSegment { func evaluateInits(context: C) throws -> [Reference] { - try self.initializer.map { expression -> Reference in - switch expression[0] { - case let .refFunc(index): - return try context.functionRef(index) - case .refNull(.funcRef): - return .function(nil) - case .refNull(.externRef): - return .extern(nil) - case .globalGet(let index): - let value = try context.globalValue(index) - switch value { - case .ref(.function(let addr)): - return .function(addr) - default: - throw Trap._raw("Unexpected global value type for element initializer expression") - } + return try self.initializer.map { expression -> Reference in + let result = try Self._evaluateInits(context: context, expression: expression) + try result.checkType(self.type) + return result + } + } + static func _evaluateInits( + context: C, expression: ConstExpression + ) throws -> Reference { + switch expression[0] { + case let .refFunc(index): + return try context.functionRef(index) + case .refNull(.funcRef): + return .function(nil) + case .refNull(.externRef): + return .extern(nil) + case .globalGet(let index): + let value = try context.globalValue(index) + switch value { + case .ref(.function(let addr)): + return .function(addr) default: - throw Trap._raw("Unexpected element initializer expression: \(expression)") + throw Trap._raw("Unexpected global value type for element initializer expression") } + default: + throw Trap._raw("Unexpected element initializer expression: \(expression)") + } + } +} + +fileprivate extension WasmTypes.Reference { + func checkType(_ type: WasmTypes.ReferenceType) throws { + switch (self, type) { + case (.function, .funcRef): return + case (.extern, .externRef): return + default: + throw ValidationError("Expect \(type) but got \(self)") + } + } +} + +fileprivate extension Value { + func checkType(_ type: WasmTypes.ValueType) throws { + switch (self, type) { + case (.i32, .i32): return + case (.i64, .i64): return + case (.f32, .f32): return + case (.f64, .f64): return + case (.ref(let ref), .ref(let refType)): + try ref.checkType(refType) + default: + throw ValidationError("Expect \(type) but got \(self)") } } } diff --git a/Sources/WasmKit/Execution/Instances.swift b/Sources/WasmKit/Execution/Instances.swift index 2b078b38..2c3a56d6 100644 --- a/Sources/WasmKit/Execution/Instances.swift +++ b/Sources/WasmKit/Execution/Instances.swift @@ -76,6 +76,7 @@ struct InstanceEntity /* : ~Copyable */ { var elementSegments: ImmutableArray var dataSegments: ImmutableArray var exports: [String: InternalExternalValue] + var functionRefs: Set var features: WasmFeatureSet var hasDataCount: Bool @@ -89,6 +90,7 @@ struct InstanceEntity /* : ~Copyable */ { elementSegments: ImmutableArray(), dataSegments: ImmutableArray(), exports: [:], + functionRefs: [], features: [], hasDataCount: false ) @@ -262,6 +264,10 @@ struct TableEntity /* : ~Copyable */ { let tableType: TableType var limits: Limits { tableType.limits } + static func maxSize(isMemory64: Bool) -> UInt64 { + return UInt64(UInt32.max) + } + init(_ tableType: TableType, resourceLimiter: any ResourceLimiter) throws { let emptyElement: Reference switch tableType.elementType { @@ -418,6 +424,10 @@ public struct Table: Equatable { struct MemoryEntity /* : ~Copyable */ { static let pageSize = 64 * 1024 + static func maxPageCount(isMemory64: Bool) -> UInt64 { + isMemory64 ? UInt64.max : UInt64(1 << 32) / UInt64(pageSize) + } + var data: [UInt8] let maxPageCount: UInt64 let limit: Limits @@ -428,7 +438,7 @@ struct MemoryEntity /* : ~Copyable */ { throw Trap._raw("Initial memory size exceeds the resource limit: \(byteSize) bytes") } data = Array(repeating: 0, count: byteSize) - let defaultMaxPageCount = (memoryType.isMemory64 ? UInt64.max : UInt64(UInt32.max)) / UInt64(Self.pageSize) + let defaultMaxPageCount = Self.maxPageCount(isMemory64: memoryType.isMemory64) maxPageCount = memoryType.max ?? defaultMaxPageCount limit = memoryType } diff --git a/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift b/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift index 945ccc33..90f7957a 100644 --- a/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift +++ b/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift @@ -14,7 +14,7 @@ protocol ShiftedVReg { /// A larger (32-bit) version of `VReg` /// Used to utilize halfword loads instructions. -struct LVReg: Equatable, ShiftedVReg { +struct LVReg: Equatable, ShiftedVReg, CustomStringConvertible { let value: Int32 init(_ value: VReg) { @@ -26,11 +26,15 @@ struct LVReg: Equatable, ShiftedVReg { init(storage: Int32) { self.value = storage } + + var description: String { + "\(value / Int32(MemoryLayout.size))" + } } /// A larger (64-bit) version of `VReg` /// Used to utilize word loads instructions. -struct LLVReg: Equatable, ShiftedVReg { +struct LLVReg: Equatable, ShiftedVReg, CustomStringConvertible { let value: Int64 init(_ value: VReg) { @@ -42,6 +46,10 @@ struct LLVReg: Equatable, ShiftedVReg { init(storage: Int64) { self.value = storage } + + var description: String { + "\(value / Int64(MemoryLayout.size))" + } } // MARK: - Immediate load/emit support @@ -218,7 +226,11 @@ extension InstructionSequence { } target.write("0x\(hexOffset): ") let instruction = Instruction.load(from: &cursor) - context.print(instruction: instruction, to: &target) + context.print( + instruction: instruction, + instructionOffset: cursor - cursorStart, + to: &target + ) target.write("\n") } } @@ -238,8 +250,7 @@ struct InstructionPrintingContext { return "reg:\(reg)" } } - func reg(_ x: LVReg) -> String { reg(x.value) } - func reg(_ x: LLVReg) -> String { reg(x.value) } + func reg(_ x: R) -> String { reg(Int(x.value) / MemoryLayout.size) } func offset(_ offset: UInt64) -> String { "offset: \(offset)" @@ -264,6 +275,7 @@ struct InstructionPrintingContext { mutating func print( instruction: Instruction, + instructionOffset: Int, to target: inout Target ) where Target : TextOutputStream { switch instruction { @@ -310,7 +322,8 @@ struct InstructionPrintingContext { case .brIf(let op): target.write("br_if \(reg(op.condition)), +\(op.offset)") case .br(let offset): - target.write("br \(offset > 0 ? "+" : "")\(offset)") + let iseqOffset = instructionOffset + Int(offset) + target.write("br \(offset > 0 ? "+" : "")\(offset) ; 0x\(String(iseqOffset, radix: 16))") case .brTable(let table): target.write("br_table \(reg(table.index)), \(table.count) cases") for i in 0.. = [] // Step 5. - var constEvalContext = ConstEvaluationContext( + let constEvalContext = ConstEvaluationContext( functions: functions, - globals: importedGlobals.map(\.value) + globals: importedGlobals.map(\.value), + onFunctionReferenced: { function in + functionRefs.insert(function) + } ) + let globals = try allocateEntities( imports: importedGlobals, internals: module.globals, allocateHandle: { global, i in - let initialValue = try global.initializer.evaluate(context: constEvalContext) - constEvalContext.globals.append(initialValue) + let initialValue = try global.initializer.evaluate( + context: constEvalContext, expectedType: global.type.valueType + ) return allocate(globalType: global.type, initialValue: initialValue) } ) @@ -375,13 +384,13 @@ extension StoreAllocator { // Step 6. let elements = try ImmutableArray(allocator: arrayAllocator, count: module.elements.count) { buffer in for (index, element) in module.elements.enumerated() { - let references: [Reference] + // TODO: Avoid evaluating element expr twice in `Module.instantiate` and here. + var references = try element.evaluateInits(context: constEvalContext) switch element.mode { case .active, .declarative: // active & declarative segments are unavailable at runtime references = [] - case .passive: - references = try element.evaluateInits(context: constEvalContext) + case .passive: break } let handle = allocate(elementType: element.type, references: references) buffer.initializeElement(at: index, to: handle) @@ -429,6 +438,9 @@ extension StoreAllocator { } let exports: [String: InternalExternalValue] = try module.exports.reduce(into: [:]) { result, export in + guard result[export.name] == nil else { + throw ValidationError("Duplicate export name: \(export.name)") + } result[export.name] = try createExportValue(export) } @@ -442,6 +454,7 @@ extension StoreAllocator { elementSegments: elements, dataSegments: dataSegments, exports: exports, + functionRefs: functionRefs, features: module.features, hasDataCount: module.hasDataCount ) diff --git a/Sources/WasmKit/Module.swift b/Sources/WasmKit/Module.swift index 750a7bb6..52c3a58e 100644 --- a/Sources/WasmKit/Module.swift +++ b/Sources/WasmKit/Module.swift @@ -58,6 +58,7 @@ public struct Module { public let types: [FunctionType] let moduleImports: ModuleImports + let importedFunctionTypes: [TypeIndex] let memoryTypes: [MemoryType] let tableTypes: [TableType] let allocator: ISeqAllocator @@ -92,19 +93,20 @@ public struct Module { self.features = features self.hasDataCount = hasDataCount - var functionTypeIndices: [TypeIndex] = [] + var importedFunctionTypes: [TypeIndex] = [] var globalTypes: [GlobalType] = [] var memoryTypes: [MemoryType] = [] var tableTypes: [TableType] = [] self.moduleImports = ModuleImports.build( from: imports, - functionTypeIndices: &functionTypeIndices, + functionTypeIndices: &importedFunctionTypes, globalTypes: &globalTypes, memoryTypes: &memoryTypes, tableTypes: &tableTypes ) self.types = types + self.importedFunctionTypes = importedFunctionTypes self.memoryTypes = memoryTypes + memories self.tableTypes = tableTypes + tables } @@ -116,6 +118,19 @@ public struct Module { return typeSection[Int(index)] } + internal func resolveFunctionType(_ index: FunctionIndex) throws -> FunctionType { + guard Int(index) < functions.count + self.moduleImports.numberOfFunctions else { + throw TranslationError("Function index \(index) is out of range") + } + if Int(index) < self.moduleImports.numberOfFunctions { + return try Self.resolveType( + importedFunctionTypes[Int(index)], + typeSection: types + ) + } + return functions[Int(index) - self.moduleImports.numberOfFunctions].type + } + /// Instantiate this module in the given imports. /// /// - Parameters: @@ -129,6 +144,8 @@ public struct Module { /// > Note: /// private func instantiateHandle(store: Store, imports: Imports) throws -> InternalInstance { + try ModuleValidator(module: self).validate() + // Steps 5-8. // Step 9. @@ -147,21 +164,30 @@ public struct Module { try? store.nameRegistry.register(instance: instance, nameSection: nameSection) } + let constEvalContext = ConstEvaluationContext(instance: instance, moduleImports: moduleImports) // Step 12-13. // Steps 14-15. do { for element in elements { guard case let .active(tableIndex, offset) = element.mode else { continue } - let offsetValue = try offset.evaluate(context: instance) let table = try instance.tables[validating: Int(tableIndex)] + let offsetValue = try offset.evaluate( + context: constEvalContext, + expectedType: .addressType(isMemory64: table.limits.isMemory64) + ) try table.withValue { table in guard let offset = offsetValue.maybeAddressOffset(table.limits.isMemory64) else { throw InstantiationError.unsupported( "Expect \(ValueType.addressType(isMemory64: table.limits.isMemory64)) offset of active element segment but got \(offsetValue)" ) } - let references = try element.evaluateInits(context: instance) + guard table.tableType.elementType == element.type else { + throw ValidationError( + "Element segment type \(element.type) does not match table element type \(table.tableType.elementType)" + ) + } + let references = try element.evaluateInits(context: constEvalContext) try table.initialize( references, from: 0, to: Int(offset), count: references.count ) @@ -176,8 +202,11 @@ public struct Module { // Step 16. do { for case let .active(data) in data { - let offsetValue = try data.offset.evaluate(context: instance) let memory = try instance.memories[validating: Int(data.index)] + let offsetValue = try data.offset.evaluate( + context: constEvalContext, + expectedType: .addressType(isMemory64: memory.limit.isMemory64) + ) try memory.withValue { memory in guard let offset = offsetValue.maybeAddressOffset(memory.limit.isMemory64) else { throw InstantiationError.unsupported( diff --git a/Sources/WasmKit/Translator.swift b/Sources/WasmKit/Translator.swift index 0d8e0f61..e09cf547 100644 --- a/Sources/WasmKit/Translator.swift +++ b/Sources/WasmKit/Translator.swift @@ -40,12 +40,12 @@ protocol TranslatorContext { func globalType(_ index: GlobalIndex) throws -> ValueType func isMemory64(memoryIndex index: MemoryIndex) throws -> Bool func isMemory64(tableIndex index: TableIndex) throws -> Bool - func elementType(_ index: TableIndex) throws -> ReferenceType + func tableType(_ index: TableIndex) throws -> TableType + func elementType(_ index: ElementIndex) throws -> ReferenceType func resolveCallee(_ index: FunctionIndex) -> InternalFunction? func isSameInstance(_ instance: InternalInstance) -> Bool func resolveGlobal(_ index: GlobalIndex) -> InternalGlobal? func validateDataSegment(_ index: DataIndex) throws - func validateElementSegment(_ index: ElementIndex) throws func validateFunctionIndex(_ index: FunctionIndex) throws } @@ -56,6 +56,9 @@ extension TranslatorContext { func addressType(tableIndex: TableIndex) throws -> ValueType { return ValueType.addressType(isMemory64: try isMemory64(tableIndex: tableIndex)) } + func validateElementSegment(_ index: ElementIndex) throws { + _ = try elementType(index) + } } extension InternalInstance: TranslatorContext { @@ -92,11 +95,14 @@ extension InternalInstance: TranslatorContext { } return self.tables[Int(index)].limits.isMemory64 } - func elementType(_ index: TableIndex) throws -> ReferenceType { + func tableType(_ index: TableIndex) throws -> TableType { guard Int(index) < self.tables.count else { throw TranslationError("Table index \(index) is out of range") } - return self.tables[Int(index)].tableType.elementType + return self.tables[Int(index)].tableType + } + func elementType(_ index: ElementIndex) throws -> ReferenceType { + try self.elementSegments[validating: Int(index)].type } func resolveCallee(_ index: FunctionIndex) -> InternalFunction? { @@ -111,11 +117,11 @@ extension InternalInstance: TranslatorContext { func validateDataSegment(_ index: DataIndex) throws { _ = try self.dataSegments[validating: Int(index)] } - func validateElementSegment(_ index: ElementIndex) throws { - _ = try self.elementSegments[validating: Int(index)] - } func validateFunctionIndex(_ index: FunctionIndex) throws { - _ = try self.functions[validating: Int(index)] + let function = try self.functions[validating: Int(index)] + guard self.functionRefs.contains(function) else { + throw ValidationError("Function index \(index) is not declared but referenced as a function reference") + } } } @@ -166,7 +172,7 @@ fileprivate struct MetaProgramCounter { /// ``` /// | Offset | Description | /// |------------------------------------|----------------------| -/// | 0 ~ max(params, results)-1 | Frame header | +/// | SP-3 ~ SP-(max(params, results)+3) | Frame header | /// | SP-3 | * Saved Instance | /// | SP-2 | * Saved PC | /// | SP-1 | * Saved SP | @@ -187,19 +193,19 @@ fileprivate struct MetaProgramCounter { struct FrameHeaderLayout { let type: FunctionType - let paramResultBase: VReg + let size: VReg init(type: FunctionType) { self.type = type - self.paramResultBase = Self.size(of: type) + self.size = Self.size(of: type) } func paramReg(_ index: Int) -> VReg { - VReg(index) - paramResultBase + VReg(index) - size } func returnReg(_ index: Int) -> VReg { - return VReg(index) - paramResultBase + return VReg(index) - size } internal static func size(of: FunctionType) -> VReg { @@ -233,13 +239,17 @@ struct StackLayout { } func localReg(_ index: LocalIndex) -> VReg { - if index < frameHeader.type.parameters.count { + if isParameter(index) { return frameHeader.paramReg(Int(index)) } else { return VReg(index) - VReg(frameHeader.type.parameters.count) } } + func isParameter(_ index: LocalIndex) -> Bool { + index < frameHeader.type.parameters.count + } + func constReg(_ index: Int) -> VReg { return VReg(numberOfLocals + index) } @@ -298,7 +308,7 @@ struct InstructionTranslator: InstructionVisitor { enum Kind { case block(root: Bool) case loop - case `if`(elseLabel: LabelRef, endLabel: LabelRef) + case `if`(elseLabel: LabelRef, endLabel: LabelRef, isElse: Bool) static var block: Kind { .block(root: false) } } @@ -310,14 +320,17 @@ struct InstructionTranslator: InstructionVisitor { var kind: Kind var reachable: Bool = true - var copyCount: UInt16 { + var copyTypes: [ValueType] { switch self.kind { case .block, .if: - return UInt16(blockType.results.count) + return blockType.results case .loop: - return UInt16(blockType.parameters.count) + return blockType.parameters } } + var copyCount: UInt16 { + return UInt16(copyTypes.count) + } } private var frames: [ControlFrame] = [] @@ -341,14 +354,14 @@ struct InstructionTranslator: InstructionVisitor { private mutating func setReachability(_ value: Bool) throws { guard !self.frames.isEmpty else { - throw TranslationError("Control stack is empty. Instruction cannot be appeared after \"end\" of function") + throw ValidationError("Control stack is empty. Instruction cannot be appeared after \"end\" of function") } self.frames[self.frames.count - 1].reachable = value } func currentFrame() throws -> ControlFrame { guard let frame = self.frames.last else { - throw TranslationError("Control stack is empty. Instruction cannot be appeared after \"end\" of function") + throw ValidationError("Control stack is empty. Instruction cannot be appeared after \"end\" of function") } return frame } @@ -356,7 +369,7 @@ struct InstructionTranslator: InstructionVisitor { func branchTarget(relativeDepth: UInt32) throws -> ControlFrame { let index = frames.count - 1 - Int(relativeDepth) guard frames.indices.contains(index) else { - throw TranslationError("Relative depth \(relativeDepth) is out of range") + throw ValidationError("Relative depth \(relativeDepth) is out of range") } return frames[index] } @@ -457,6 +470,10 @@ struct InstructionTranslator: InstructionVisitor { return makeValueSource(self.values[height - 1 - depth]) } + func peekType(depth: Int) -> MetaValue { + return self.values[height - 1 - depth].type + } + private func makeValueSource(_ value: MetaValueOnStack) -> ValueSource { let source: ValueSource switch value { @@ -804,6 +821,7 @@ struct InstructionTranslator: InstructionVisitor { /// Whether a call to this function should be intercepted let intercepting: Bool var constantSlots: ConstSlots + let validator: InstructionValidator init( allocator: ISeqAllocator, @@ -832,6 +850,7 @@ struct InstructionTranslator: InstructionVisitor { self.functionIndex = functionIndex self.intercepting = intercepting self.constantSlots = ConstSlots(stackLayout: stackLayout) + self.validator = InstructionValidator(context: module) do { let endLabel = self.iseqBuilder.allocLabel() @@ -891,8 +910,7 @@ struct InstructionTranslator: InstructionVisitor { /// /// - Parameter typeHint: A type expected to be popped. Only used for diagnostic purpose. /// - Returns: `true` if check succeed. `false` if the pop operation is going to be performed in unreachable code path. - private func checkBeforePop(typeHint: ValueType?) throws -> Bool { - let controlFrame = try controlStack.currentFrame() + private func checkBeforePop(typeHint: ValueType?, controlFrame: ControlStack.ControlFrame) throws -> Bool { if _slowPath(valueStack.height <= controlFrame.stackHeight) { if controlFrame.reachable { let message: String @@ -908,6 +926,10 @@ struct InstructionTranslator: InstructionVisitor { } return true } + private func checkBeforePop(typeHint: ValueType?) throws -> Bool { + let controlFrame = try controlStack.currentFrame() + return try self.checkBeforePop(typeHint: typeHint, controlFrame: controlFrame) + } private mutating func ensureOnVReg(_ source: ValueSource) -> VReg { // TODO: Copy to stack if source is on preg // let copyTo = valueStack.stackRegBase + VReg(valueStack.height) @@ -957,11 +979,57 @@ struct InstructionTranslator: InstructionVisitor { return try valueStack.pop() } + @discardableResult + private mutating func popPushValues(_ valueTypes: [ValueType]) throws -> Int { + var values: [ValueSource?] = [] + for type in valueTypes.reversed() { + values.append(try popOperand(type)) + } + let stackHeight = self.valueStack.height + for (type, value) in zip(valueTypes, values.reversed()) { + switch value { + case .local(let localIndex): + // Re-push local variables to the stack + _ = try valueStack.pushLocal(localIndex, locals: &locals) + case .vreg, nil: + _ = valueStack.push(type) + case .const(let index, let type): + valueStack.pushConst(index, type: type) + } + } + return stackHeight + } + + private func checkStackTop(_ valueTypes: [ValueType]) throws { + for (stackDepth, type) in valueTypes.reversed().enumerated() { + guard try checkBeforePop(typeHint: type) else { return } + let actual = valueStack.peekType(depth: stackDepth) + switch actual { + case .some(let actualType): + guard actualType == type else { + throw ValidationError("Expected \(type) on the stack top but got \(actualType)") + } + case .unknown: break + } + } + } + private mutating func visitReturnLike() throws { - preserveOnStack(depth: self.type.results.count) + var copies: [(source: VReg, dest: VReg)] = [] for (index, resultType) in self.type.results.enumerated().reversed() { - let source = ensureOnVReg(try valueStack.pop(resultType)) + guard let operand = try popOperand(resultType) else { continue } + var source = ensureOnVReg(operand) + if case .local(let localIndex) = operand, stackLayout.isParameter(localIndex) { + // Parameter space is shared with return values, so we need to copy it to the stack + // before copying to the return slot to avoid overwriting the parameter value. + let copyTo = valueStack.stackRegBase + VReg(valueStack.height) + emitCopyStack(from: localReg(localIndex), to: copyTo) + source = copyTo + } let dest = returnReg(index) + copies.append((source, dest)) + } + for (source, dest) in copies { emitCopyStack(from: source, to: dest) } } @@ -1033,7 +1101,16 @@ struct InstructionTranslator: InstructionVisitor { // Emit `onEnter` instruction at the beginning of the function emit(.onEnter(functionIndex)) } - try code.parseExpression(visitor: &self) + var parser = ExpressionParser(code: code) + var offset = parser.offset + do { + while try parser.visit(visitor: &self) { + offset = parser.offset + } + } catch var error as ValidationError { + error.offset = offset + throw error + } return try finalize() } @@ -1048,22 +1125,7 @@ struct InstructionTranslator: InstructionVisitor { mutating func visitBlock(blockType: WasmParser.BlockType) throws -> Output { let blockType = try module.resolveBlockType(blockType) let endLabel = iseqBuilder.allocLabel() - var parameters: [ValueSource?] = [] - for param in blockType.parameters.reversed() { - parameters.append(try popOperand(param)) - } - let stackHeight = self.valueStack.height - for (param, value) in zip(blockType.parameters, parameters.reversed()) { - switch value { - case .local(let localIndex): - // Re-push local variables to the stack - _ = try valueStack.pushLocal(localIndex, locals: &locals) - case .vreg, nil: - _ = valueStack.push(param) - case .const(let index, let type): - valueStack.pushConst(index, type: type) - } - } + let stackHeight = try popPushValues(blockType.parameters) controlStack.pushFrame(ControlStack.ControlFrame(blockType: blockType, stackHeight: stackHeight, continuation: endLabel, kind: .block)) } @@ -1099,7 +1161,7 @@ struct InstructionTranslator: InstructionVisitor { controlStack.pushFrame( ControlStack.ControlFrame( blockType: blockType, stackHeight: stackHeight, continuation: endLabel, - kind: .if(elseLabel: elseLabel, endLabel: endLabel) + kind: .if(elseLabel: elseLabel, endLabel: endLabel, isElse: false) ) ) guard let condition = condition else { return } @@ -1116,8 +1178,8 @@ struct InstructionTranslator: InstructionVisitor { } mutating func visitElse() throws -> Output { - let frame = try controlStack.currentFrame() - guard case let .if(elseLabel, endLabel) = frame.kind else { + var frame = try controlStack.currentFrame() + guard case let .if(elseLabel, endLabel, _) = frame.kind else { throw TranslationError("Expected `if` control frame on top of the stack for `else` but got \(frame)") } preserveOnStack(depth: valueStack.height - frame.stackHeight) @@ -1127,7 +1189,18 @@ struct InstructionTranslator: InstructionVisitor { let offset = endPC.offsetFromHead - selfPC.offsetFromHead return Int32(offset) } - try valueStack.truncate(height: frame.stackHeight) + for result in frame.blockType.results.reversed() { + guard try checkBeforePop(typeHint: result, controlFrame: frame) else { continue } + _ = try valueStack.pop(result) + } + guard valueStack.height == frame.stackHeight else { + throw ValidationError("values remaining on stack at end of block") + } + _ = controlStack.popFrame() + frame.kind = .if(elseLabel: elseLabel, endLabel: endLabel, isElse: true) + frame.reachable = true + controlStack.pushFrame(frame) + // Re-push parameters for parameter in frame.blockType.parameters { _ = valueStack.push(parameter) @@ -1136,9 +1209,7 @@ struct InstructionTranslator: InstructionVisitor { } mutating func visitEnd() throws -> Output { - guard let poppedFrame = controlStack.popFrame() else { - throw TranslationError("Unexpected `end` instruction") - } + let toBePopped = try controlStack.currentFrame() // Reset the last emission to avoid relinking the result of the last instruction inside the block. // Relinking results across the block boundary is invalid because the producer instruction is not // statically known. Think about the following case: @@ -1153,28 +1224,45 @@ struct InstructionTranslator: InstructionVisitor { // ``` // iseqBuilder.resetLastEmission() - if case .block(root: true) = poppedFrame.kind { - if poppedFrame.reachable { - try translateReturn() + if case .block(root: true) = toBePopped.kind { + try translateReturn() + // TODO: Merge logic with regular block frame + guard valueStack.height == toBePopped.stackHeight else { + throw ValidationError("values remaining on stack at end of block") } - try iseqBuilder.pinLabelHere(poppedFrame.continuation) + try iseqBuilder.pinLabelHere(toBePopped.continuation) return } + if case .if(_, _, isElse: false) = toBePopped.kind { + // `if` inst without `else` must have the same parameter and result types + let blockType = toBePopped.blockType + guard blockType.parameters == blockType.results else { + throw TranslationError("Expected the same parameter and result types for `if` block but got \(blockType)") + } + } + // NOTE: `valueStack.height - poppedFrame.stackHeight` is usually the same as `poppedFrame.copyCount` // but it's not always the case when this block is already unreachable. - preserveOnStack(depth: Int(valueStack.height - poppedFrame.stackHeight)) - switch poppedFrame.kind { + preserveOnStack(depth: Int(valueStack.height - toBePopped.stackHeight)) + switch toBePopped.kind { case .block: - try iseqBuilder.pinLabelHere(poppedFrame.continuation) + try iseqBuilder.pinLabelHere(toBePopped.continuation) case .loop: break case .if: - try iseqBuilder.pinLabelHere(poppedFrame.continuation) + try iseqBuilder.pinLabelHere(toBePopped.continuation) } - try valueStack.truncate(height: poppedFrame.stackHeight) - for result in poppedFrame.blockType.results { + for result in toBePopped.blockType.results.reversed() { + guard try checkBeforePop(typeHint: result, controlFrame: toBePopped) else { continue } + _ = try valueStack.pop(result) + } + guard valueStack.height == toBePopped.stackHeight else { + throw ValidationError("values remaining on stack at end of block") + } + for result in toBePopped.blockType.results { _ = valueStack.push(result) } + _ = controlStack.popFrame() } private static func computePopCount( @@ -1229,14 +1317,18 @@ struct InstructionTranslator: InstructionVisitor { try emitBranch(Instruction.br, relativeDepth: relativeDepth) { offset, copyCount, popCount in return offset } + for type in frame.copyTypes.reversed() { + _ = try popOperand(type) + } try markUnreachable() } mutating func visitBrIf(relativeDepth: UInt32) throws -> Output { - guard let condition = try popVRegOperand(.i32) else { return } - let frame = try controlStack.branchTarget(relativeDepth: relativeDepth) + let condition = try popVRegOperand(.i32) + if frame.copyCount == 0 { + guard let condition else { return } // Optimization where we don't need copying values when the branch taken iseqBuilder.emitWithLabel(Instruction.brIf, frame.continuation) { _, selfPC, continuation in let relativeOffset = continuation.offsetFromHead - selfPC.offsetFromHead @@ -1248,45 +1340,53 @@ struct InstructionTranslator: InstructionVisitor { } preserveOnStack(depth: valueStack.height - frame.stackHeight) - // If branch taken, fallthrough to landing pad, copy stack values - // then branch to the actual place - // If branch not taken, branch to the next of the landing pad - // - // (block (result i32) - // (i32.const 42) - // (i32.const 24) - // (local.get 0) - // (br_if 0) ------+ - // (local.get 1) | - // ) <-------+ - // - // [0x00] (i32.const 42 reg:0) - // [0x01] (i32.const 24 reg:1) - // [0x02] (local.get 0 result=reg:2) - // [0x03] (br_if_z offset=+0x3 cond=reg:2) --+ - // [0x04] (stack.copy reg:1 -> reg:0) | - // [0x05] (br offset=+0x2) --------+ | - // [0x06] (local.get 1 reg:2) <----|---------+ - // [0x07] ... <-------+ - let onBranchNotTaken = iseqBuilder.allocLabel() - iseqBuilder.emitWithLabel(Instruction.brIfNot, onBranchNotTaken) { _, conditionCheckAt, continuation in - let relativeOffset = continuation.offsetFromHead - conditionCheckAt.offsetFromHead - return Instruction.BrIfOperand(condition: LVReg(condition), offset: Int32(relativeOffset)) - } - try copyOnBranch(targetFrame: frame) - try emitBranch(Instruction.br, relativeDepth: relativeDepth) { offset, copyCount, popCount in - return offset + if let condition { + // If branch taken, fallthrough to landing pad, copy stack values + // then branch to the actual place + // If branch not taken, branch to the next of the landing pad + // + // (block (result i32) + // (i32.const 42) + // (i32.const 24) + // (local.get 0) + // (br_if 0) ------+ + // (local.get 1) | + // ) <-------+ + // + // [0x00] (i32.const 42 reg:0) + // [0x01] (i32.const 24 reg:1) + // [0x02] (local.get 0 result=reg:2) + // [0x03] (br_if_z offset=+0x3 cond=reg:2) --+ + // [0x04] (stack.copy reg:1 -> reg:0) | + // [0x05] (br offset=+0x2) --------+ | + // [0x06] (local.get 1 reg:2) <----|---------+ + // [0x07] ... <-------+ + let onBranchNotTaken = iseqBuilder.allocLabel() + iseqBuilder.emitWithLabel(Instruction.brIfNot, onBranchNotTaken) { _, conditionCheckAt, continuation in + let relativeOffset = continuation.offsetFromHead - conditionCheckAt.offsetFromHead + return Instruction.BrIfOperand(condition: LVReg(condition), offset: Int32(relativeOffset)) + } + try copyOnBranch(targetFrame: frame) + try emitBranch(Instruction.br, relativeDepth: relativeDepth) { offset, copyCount, popCount in + return offset + } + try iseqBuilder.pinLabelHere(onBranchNotTaken) } - try iseqBuilder.pinLabelHere(onBranchNotTaken) + try popPushValues(frame.copyTypes) } mutating func visitBrTable(targets: WasmParser.BrTable) throws -> Output { guard let index = try popVRegOperand(.i32) else { return } - guard try controlStack.currentFrame().reachable else { return } let defaultFrame = try controlStack.branchTarget(relativeDepth: targets.defaultIndex) - preserveOnStack(depth: Int(defaultFrame.copyCount)) + // If this instruction is unreachable, copyCount might be greater than the actual stack height + try preserveOnStack( + depth: min( + Int(defaultFrame.copyCount), + valueStack.height - controlStack.currentFrame().stackHeight + ) + ) let allLabelIndices = targets.labelIndices + [targets.defaultIndex] let tableBuffer = allocator.allocateBrTable(capacity: allLabelIndices.count) let operand = Instruction.BrTableOperand( @@ -1327,6 +1427,13 @@ struct InstructionTranslator: InstructionVisitor { // +---> [0x0b] ... for (entryIndex, labelIndex) in allLabelIndices.enumerated() { let frame = try controlStack.branchTarget(relativeDepth: labelIndex) + + // Check copyTypes consistency + guard frame.copyTypes.count == defaultFrame.copyTypes.count else { + throw ValidationError("Expected the same copy types for all branches in `br_table` but got \(frame.copyTypes) and \(defaultFrame.copyTypes)") + } + try checkStackTop(frame.copyTypes) + do { let relativeOffset = iseqBuilder.insertingPC.offsetFromHead - brTableAt.offsetFromHead tableBuffer[entryIndex] = Instruction.BrTableOperand.Entry( @@ -1346,11 +1453,14 @@ struct InstructionTranslator: InstructionVisitor { } } } + // Pop branch copy values for type checking + for type in defaultFrame.copyTypes.reversed() { + _ = try popOperand(type) + } try markUnreachable() } mutating func visitReturn() throws -> Output { - guard try controlStack.currentFrame().reachable else { return } try translateReturn() try markUnreachable() } @@ -1409,6 +1519,8 @@ struct InstructionTranslator: InstructionVisitor { let (value1Type, value1) = try popAnyOperand() let (value2Type, value2) = try popAnyOperand() switch (value1Type, value2Type) { + case (.some(.ref(_)), _), (_, .some(.ref(_))): + throw TranslationError("Cannot `select` on reference types") case let (.some(type1), .some(type2)): guard type1 == type2 else { throw TranslationError("Type mismatch on `select`. Expected \(value1Type) and \(value2Type) to be same") @@ -1484,7 +1596,6 @@ struct InstructionTranslator: InstructionVisitor { try visitLocalSetOrTee(localIndex: localIndex, isTee: false) } mutating func visitLocalTee(localIndex: UInt32) throws -> Output { - guard try controlStack.currentFrame().reachable else { return } try visitLocalSetOrTee(localIndex: localIndex, isTee: true) _ = try valueStack.pushLocal(localIndex, locals: &locals) } @@ -1504,6 +1615,7 @@ struct InstructionTranslator: InstructionVisitor { // Skip actual code emission if validation-only mode return } + try validator.validateGlobalSet(global.globalType) emit(.globalSet(Instruction.GlobalAndVRegOperand(reg: LLVReg(value), global: global))) } @@ -1574,13 +1686,11 @@ struct InstructionTranslator: InstructionVisitor { private mutating func visitLoad( _ memarg: MemArg, _ type: ValueType, + _ naturalAlignment: Int, _ instruction: @escaping (Instruction.LoadOperand) -> Instruction ) throws { let isMemory64 = try module.isMemory64(memoryIndex: 0) - let alignLog2Limit = isMemory64 ? 64 : 32 - if memarg.align >= alignLog2Limit { - throw TranslationError("Alignment 2**\(memarg.align) is out of limit \(alignLog2Limit)") - } + try validator.validateMemArg(memarg, naturalAlignment: naturalAlignment) try popPushEmit(.address(isMemory64: isMemory64), type) { value, result, stack in let loadOperand = Instruction.LoadOperand( offset: memarg.offset, @@ -1593,9 +1703,11 @@ struct InstructionTranslator: InstructionVisitor { private mutating func visitStore( _ memarg: MemArg, _ type: ValueType, + _ naturalAlignment: Int, _ instruction: (Instruction.StoreOperand) -> Instruction ) throws { let isMemory64 = try module.isMemory64(memoryIndex: 0) + try validator.validateMemArg(memarg, naturalAlignment: naturalAlignment) let value = try popVRegOperand(type) let pointer = try popVRegOperand(.address(isMemory64: isMemory64)) if let value = value, let pointer = pointer { @@ -1607,29 +1719,29 @@ struct InstructionTranslator: InstructionVisitor { emit(instruction(storeOperand)) } } - mutating func visitI32Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, Instruction.i32Load) } - mutating func visitI64Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, Instruction.i64Load) } - mutating func visitF32Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .f32, Instruction.f32Load) } - mutating func visitF64Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .f64, Instruction.f64Load) } - mutating func visitI32Load8S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, Instruction.i32Load8S) } - mutating func visitI32Load8U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, Instruction.i32Load8U) } - mutating func visitI32Load16S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, Instruction.i32Load16S) } - mutating func visitI32Load16U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, Instruction.i32Load16U) } - mutating func visitI64Load8S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, Instruction.i64Load8S) } - mutating func visitI64Load8U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, Instruction.i64Load8U) } - mutating func visitI64Load16S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, Instruction.i64Load16S) } - mutating func visitI64Load16U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, Instruction.i64Load16U) } - mutating func visitI64Load32S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, Instruction.i64Load32S) } - mutating func visitI64Load32U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, Instruction.i64Load32U) } - mutating func visitI32Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .i32, Instruction.i32Store) } - mutating func visitI64Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, Instruction.i64Store) } - mutating func visitF32Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .f32, Instruction.f32Store) } - mutating func visitF64Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .f64, Instruction.f64Store) } - mutating func visitI32Store8(memarg: MemArg) throws -> Output { try visitStore(memarg, .i32, Instruction.i32Store8) } - mutating func visitI32Store16(memarg: MemArg) throws -> Output { try visitStore(memarg, .i32, Instruction.i32Store16) } - mutating func visitI64Store8(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, Instruction.i64Store8) } - mutating func visitI64Store16(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, Instruction.i64Store16) } - mutating func visitI64Store32(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, Instruction.i64Store32) } + mutating func visitI32Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, 2, Instruction.i32Load) } + mutating func visitI64Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, 3, Instruction.i64Load) } + mutating func visitF32Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .f32, 2, Instruction.f32Load) } + mutating func visitF64Load(memarg: MemArg) throws -> Output { try visitLoad(memarg, .f64, 3, Instruction.f64Load) } + mutating func visitI32Load8S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, 0, Instruction.i32Load8S) } + mutating func visitI32Load8U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, 0, Instruction.i32Load8U) } + mutating func visitI32Load16S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, 1, Instruction.i32Load16S) } + mutating func visitI32Load16U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i32, 1, Instruction.i32Load16U) } + mutating func visitI64Load8S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, 0, Instruction.i64Load8S) } + mutating func visitI64Load8U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, 0, Instruction.i64Load8U) } + mutating func visitI64Load16S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, 1, Instruction.i64Load16S) } + mutating func visitI64Load16U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, 1, Instruction.i64Load16U) } + mutating func visitI64Load32S(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, 2, Instruction.i64Load32S) } + mutating func visitI64Load32U(memarg: MemArg) throws -> Output { try visitLoad(memarg, .i64, 2, Instruction.i64Load32U) } + mutating func visitI32Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .i32, 2, Instruction.i32Store) } + mutating func visitI64Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, 3, Instruction.i64Store) } + mutating func visitF32Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .f32, 2, Instruction.f32Store) } + mutating func visitF64Store(memarg: MemArg) throws -> Output { try visitStore(memarg, .f64, 3, Instruction.f64Store) } + mutating func visitI32Store8(memarg: MemArg) throws -> Output { try visitStore(memarg, .i32, 0, Instruction.i32Store8) } + mutating func visitI32Store16(memarg: MemArg) throws -> Output { try visitStore(memarg, .i32, 1, Instruction.i32Store16) } + mutating func visitI64Store8(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, 0, Instruction.i64Store8) } + mutating func visitI64Store16(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, 1, Instruction.i64Store16) } + mutating func visitI64Store32(memarg: MemArg) throws -> Output { try visitStore(memarg, .i64, 2, Instruction.i64Store32) } mutating func visitMemorySize(memory: UInt32) throws -> Output { let sizeType: ValueType = try module.isMemory64(memoryIndex: memory) ? .i64 : .i32 pushEmit(sizeType, { .memorySize(Instruction.MemorySizeOperand(memoryIndex: memory, result: LVReg($0))) }) @@ -1674,7 +1786,7 @@ struct InstructionTranslator: InstructionVisitor { emit(.refIsNull(Instruction.RefIsNullOperand(value: LVReg(ensureOnVReg(value)), result: LVReg(result)))) } mutating func visitRefFunc(functionIndex: UInt32) throws -> Output { - try self.module.validateFunctionIndex(functionIndex) + try validator.validateRefFunc(functionIndex: functionIndex) pushEmit(.ref(.funcRef), { .refFunc(Instruction.RefFuncOperand(index: functionIndex, result: LVReg($0))) }) } @@ -1897,7 +2009,8 @@ struct InstructionTranslator: InstructionVisitor { } } mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws -> Output { - try self.module.validateElementSegment(elemIndex) + try validator.validateTableInit(elemIndex: elemIndex, table: table) + try pop3Emit((.i32, .i32, module.addressType(tableIndex: table))) { values, stack in let (size, sourceOffset, destOffset) = values return .tableInit( @@ -1920,9 +2033,10 @@ struct InstructionTranslator: InstructionVisitor { // ----------------------------------------------------------------------------- // C ⊦ table.copy d s : [iN iM iK] → [] // https://github.com/WebAssembly/memory64/blob/main/proposals/memory64/Overview.md + try validator.validateTableCopy(dest: dstTable, source: srcTable) let destIsMemory64 = try module.isMemory64(tableIndex: dstTable) let sourceIsMemory64 = try module.isMemory64(tableIndex: srcTable) - let lengthIsMemory64 = destIsMemory64 || sourceIsMemory64 + let lengthIsMemory64 = destIsMemory64 && sourceIsMemory64 try pop3Emit( ( .address(isMemory64: lengthIsMemory64), @@ -1944,7 +2058,8 @@ struct InstructionTranslator: InstructionVisitor { } mutating func visitTableFill(table: UInt32) throws -> Output { let address = try module.addressType(tableIndex: table) - try pop3Emit((address, .ref(module.elementType(table)), address)) { values, stack in + let type = try module.tableType(table) + try pop3Emit((address, .ref(type.elementType), address)) { values, stack in let (size, value, destOffset) = values return .tableFill( Instruction.TableFillOperand( @@ -1957,9 +2072,10 @@ struct InstructionTranslator: InstructionVisitor { } } mutating func visitTableGet(table: UInt32) throws -> Output { + let type = try module.tableType(table) try popPushEmit( module.addressType(tableIndex: table), - .ref(module.elementType(table)) + .ref(type.elementType) ) { index, result, stack in return .tableGet( Instruction.TableGetOperand( @@ -1971,7 +2087,8 @@ struct InstructionTranslator: InstructionVisitor { } } mutating func visitTableSet(table: UInt32) throws -> Output { - try pop2Emit((.ref(module.elementType(table)), module.addressType(tableIndex: table))) { values, stack in + let type = try module.tableType(table) + try pop2Emit((.ref(type.elementType), module.addressType(tableIndex: table))) { values, stack in let (value, index) = values return .tableSet( Instruction.TableSetOperand( @@ -1984,7 +2101,8 @@ struct InstructionTranslator: InstructionVisitor { } mutating func visitTableGrow(table: UInt32) throws -> Output { let address = try module.addressType(tableIndex: table) - try pop2PushEmit((address, .ref(module.elementType(table))), address) { values, result in + let type = try module.tableType(table) + try pop2PushEmit((address, .ref(type.elementType)), address) { values, result in let (delta, value) = values return .tableGrow( Instruction.TableGrowOperand( diff --git a/Sources/WasmKit/Validator.swift b/Sources/WasmKit/Validator.swift new file mode 100644 index 00000000..ee3fec4c --- /dev/null +++ b/Sources/WasmKit/Validator.swift @@ -0,0 +1,142 @@ +import WasmParser + +struct ValidationError: Error, CustomStringConvertible { + let message: String + var offset: Int? + + var description: String { + if let offset = offset { + return "\(message) at offset 0x\(String(offset, radix: 16))" + } else { + return message + } + } + + init(_ message: String) { + self.message = message + } +} + +struct InstructionValidator { + let context: Context + + func validateMemArg(_ memarg: MemArg, naturalAlignment: Int) throws { + if memarg.align > naturalAlignment { + throw ValidationError("Alignment 2**\(memarg.align) is out of limit \(naturalAlignment)") + } + } + + func validateGlobalSet(_ type: GlobalType) throws { + switch type.mutability { + case .constant: + throw ValidationError("Cannot set a constant global") + case .variable: + break + } + } + + func validateTableInit(elemIndex: UInt32, table: UInt32) throws { + let tableType = try context.tableType(table) + let elementType = try context.elementType(elemIndex) + guard tableType.elementType == elementType else { + throw ValidationError("Table element type mismatch in table.init: \(tableType.elementType) != \(elementType)") + } + } + + func validateTableCopy(dest: UInt32, source: UInt32) throws { + let tableType1 = try context.tableType(source) + let tableType2 = try context.tableType(dest) + guard tableType1.elementType == tableType2.elementType else { + throw ValidationError("Table element type mismatch in table.copy: \(tableType1.elementType) != \(tableType2.elementType)") + } + } + + func validateRefFunc(functionIndex: UInt32) throws { + try context.validateFunctionIndex(functionIndex) + } +} + +struct ModuleValidator { + let module: Module + init(module: Module) { + self.module = module + } + + func validate() throws { + if module.memoryTypes.count > 1 { + throw ValidationError("Multiple memories are not permitted") + } + for memoryType in module.memoryTypes { + try Self.checkMemoryType(memoryType, features: module.features) + } + for tableType in module.tableTypes { + try Self.checkTableType(tableType, features: module.features) + } + try checkStartFunction() + } + + func checkStartFunction() throws { + if let startFunction = module.start { + let type = try module.resolveFunctionType(startFunction) + guard type.parameters.isEmpty, type.results.isEmpty else { + throw ValidationError("Start function must have no parameters and no results") + } + } + } + + static func checkMemoryType(_ type: MemoryType, features: WasmFeatureSet) throws { + try checkLimit(type) + + if type.isMemory64 { + guard features.contains(.memory64) else { + throw ValidationError("memory64 feature is required for 64-bit memories") + } + } + + let hardMax = MemoryEntity.maxPageCount(isMemory64: type.isMemory64) + + if type.min > hardMax { + throw ValidationError("size minimum must not be greater than \(hardMax)") + } + + if let max = type.max, max > hardMax { + throw ValidationError("size maximum must not be greater than \(hardMax)") + } + + if type.shared { + guard features.contains(.threads) else { + throw ValidationError("reference-types feature is required for shared memories") + } + } + } + + static func checkTableType(_ type: TableType, features: WasmFeatureSet) throws { + if type.elementType != .funcRef, !features.contains(.referenceTypes) { + throw ValidationError("reference-types feature is required for non-funcref tables") + } + try checkLimit(type.limits) + + if type.limits.isMemory64 { + guard features.contains(.memory64) else { + throw ValidationError("memory64 feature is required for 64-bit tables") + } + } + + let hardMax = TableEntity.maxSize(isMemory64: type.limits.isMemory64) + + if type.limits.min > hardMax { + throw ValidationError("size minimum must not be greater than \(hardMax)") + } + + if let max = type.limits.max, max > hardMax { + throw ValidationError("size maximum must not be greater than \(hardMax)") + } + } + + private static func checkLimit(_ limit: Limits) throws { + guard let max = limit.max else { return } + if limit.min > max { + throw ValidationError("size minimum must not be greater than maximum") + } + } +} diff --git a/Sources/WasmParser/Docs.docc/Docs.md b/Sources/WasmParser/Docs.docc/Docs.md index e38c4c7f..3019648b 100644 --- a/Sources/WasmParser/Docs.docc/Docs.md +++ b/Sources/WasmParser/Docs.docc/Docs.md @@ -53,7 +53,6 @@ while let payload = try parser.parseNext() { ### Visitor - ``InstructionVisitor`` -- ``VoidInstructionVisitor`` - ``AnyInstructionVisitor`` - ``InstructionTracingVisitor`` diff --git a/Sources/WasmParser/InstructionVisitor.swift b/Sources/WasmParser/InstructionVisitor.swift index eaaebc36..904a2704 100644 --- a/Sources/WasmParser/InstructionVisitor.swift +++ b/Sources/WasmParser/InstructionVisitor.swift @@ -211,211 +211,211 @@ public enum Instruction: Equatable { /// A visitor that visits all instructions by a single visit method. public protocol AnyInstructionVisitor: InstructionVisitor { /// Visiting any instruction. - mutating func visit(_ instruction: Instruction) throws -> Output + mutating func visit(_ instruction: Instruction) throws } extension AnyInstructionVisitor { - public mutating func visitUnreachable() throws -> Output { return try self.visit(.unreachable) } - public mutating func visitNop() throws -> Output { return try self.visit(.nop) } - public mutating func visitBlock(blockType: BlockType) throws -> Output { return try self.visit(.block(blockType: blockType)) } - public mutating func visitLoop(blockType: BlockType) throws -> Output { return try self.visit(.loop(blockType: blockType)) } - public mutating func visitIf(blockType: BlockType) throws -> Output { return try self.visit(.if(blockType: blockType)) } - public mutating func visitElse() throws -> Output { return try self.visit(.else) } - public mutating func visitEnd() throws -> Output { return try self.visit(.end) } - public mutating func visitBr(relativeDepth: UInt32) throws -> Output { return try self.visit(.br(relativeDepth: relativeDepth)) } - public mutating func visitBrIf(relativeDepth: UInt32) throws -> Output { return try self.visit(.brIf(relativeDepth: relativeDepth)) } - public mutating func visitBrTable(targets: BrTable) throws -> Output { return try self.visit(.brTable(targets: targets)) } - public mutating func visitReturn() throws -> Output { return try self.visit(.return) } - public mutating func visitCall(functionIndex: UInt32) throws -> Output { return try self.visit(.call(functionIndex: functionIndex)) } - public mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws -> Output { return try self.visit(.callIndirect(typeIndex: typeIndex, tableIndex: tableIndex)) } - public mutating func visitDrop() throws -> Output { return try self.visit(.drop) } - public mutating func visitSelect() throws -> Output { return try self.visit(.select) } - public mutating func visitTypedSelect(type: ValueType) throws -> Output { return try self.visit(.typedSelect(type: type)) } - public mutating func visitLocalGet(localIndex: UInt32) throws -> Output { return try self.visit(.localGet(localIndex: localIndex)) } - public mutating func visitLocalSet(localIndex: UInt32) throws -> Output { return try self.visit(.localSet(localIndex: localIndex)) } - public mutating func visitLocalTee(localIndex: UInt32) throws -> Output { return try self.visit(.localTee(localIndex: localIndex)) } - public mutating func visitGlobalGet(globalIndex: UInt32) throws -> Output { return try self.visit(.globalGet(globalIndex: globalIndex)) } - public mutating func visitGlobalSet(globalIndex: UInt32) throws -> Output { return try self.visit(.globalSet(globalIndex: globalIndex)) } - public mutating func visitI32Load(memarg: MemArg) throws -> Output { return try self.visit(.i32Load(memarg: memarg)) } - public mutating func visitI64Load(memarg: MemArg) throws -> Output { return try self.visit(.i64Load(memarg: memarg)) } - public mutating func visitF32Load(memarg: MemArg) throws -> Output { return try self.visit(.f32Load(memarg: memarg)) } - public mutating func visitF64Load(memarg: MemArg) throws -> Output { return try self.visit(.f64Load(memarg: memarg)) } - public mutating func visitI32Load8S(memarg: MemArg) throws -> Output { return try self.visit(.i32Load8S(memarg: memarg)) } - public mutating func visitI32Load8U(memarg: MemArg) throws -> Output { return try self.visit(.i32Load8U(memarg: memarg)) } - public mutating func visitI32Load16S(memarg: MemArg) throws -> Output { return try self.visit(.i32Load16S(memarg: memarg)) } - public mutating func visitI32Load16U(memarg: MemArg) throws -> Output { return try self.visit(.i32Load16U(memarg: memarg)) } - public mutating func visitI64Load8S(memarg: MemArg) throws -> Output { return try self.visit(.i64Load8S(memarg: memarg)) } - public mutating func visitI64Load8U(memarg: MemArg) throws -> Output { return try self.visit(.i64Load8U(memarg: memarg)) } - public mutating func visitI64Load16S(memarg: MemArg) throws -> Output { return try self.visit(.i64Load16S(memarg: memarg)) } - public mutating func visitI64Load16U(memarg: MemArg) throws -> Output { return try self.visit(.i64Load16U(memarg: memarg)) } - public mutating func visitI64Load32S(memarg: MemArg) throws -> Output { return try self.visit(.i64Load32S(memarg: memarg)) } - public mutating func visitI64Load32U(memarg: MemArg) throws -> Output { return try self.visit(.i64Load32U(memarg: memarg)) } - public mutating func visitI32Store(memarg: MemArg) throws -> Output { return try self.visit(.i32Store(memarg: memarg)) } - public mutating func visitI64Store(memarg: MemArg) throws -> Output { return try self.visit(.i64Store(memarg: memarg)) } - public mutating func visitF32Store(memarg: MemArg) throws -> Output { return try self.visit(.f32Store(memarg: memarg)) } - public mutating func visitF64Store(memarg: MemArg) throws -> Output { return try self.visit(.f64Store(memarg: memarg)) } - public mutating func visitI32Store8(memarg: MemArg) throws -> Output { return try self.visit(.i32Store8(memarg: memarg)) } - public mutating func visitI32Store16(memarg: MemArg) throws -> Output { return try self.visit(.i32Store16(memarg: memarg)) } - public mutating func visitI64Store8(memarg: MemArg) throws -> Output { return try self.visit(.i64Store8(memarg: memarg)) } - public mutating func visitI64Store16(memarg: MemArg) throws -> Output { return try self.visit(.i64Store16(memarg: memarg)) } - public mutating func visitI64Store32(memarg: MemArg) throws -> Output { return try self.visit(.i64Store32(memarg: memarg)) } - public mutating func visitMemorySize(memory: UInt32) throws -> Output { return try self.visit(.memorySize(memory: memory)) } - public mutating func visitMemoryGrow(memory: UInt32) throws -> Output { return try self.visit(.memoryGrow(memory: memory)) } - public mutating func visitI32Const(value: Int32) throws -> Output { return try self.visit(.i32Const(value: value)) } - public mutating func visitI64Const(value: Int64) throws -> Output { return try self.visit(.i64Const(value: value)) } - public mutating func visitF32Const(value: IEEE754.Float32) throws -> Output { return try self.visit(.f32Const(value: value)) } - public mutating func visitF64Const(value: IEEE754.Float64) throws -> Output { return try self.visit(.f64Const(value: value)) } - public mutating func visitRefNull(type: ReferenceType) throws -> Output { return try self.visit(.refNull(type: type)) } - public mutating func visitRefIsNull() throws -> Output { return try self.visit(.refIsNull) } - public mutating func visitRefFunc(functionIndex: UInt32) throws -> Output { return try self.visit(.refFunc(functionIndex: functionIndex)) } - public mutating func visitI32Eqz() throws -> Output { return try self.visit(.i32Eqz) } - public mutating func visitI32Eq() throws -> Output { return try self.visit(.i32Eq) } - public mutating func visitI32Ne() throws -> Output { return try self.visit(.i32Ne) } - public mutating func visitI32LtS() throws -> Output { return try self.visit(.i32LtS) } - public mutating func visitI32LtU() throws -> Output { return try self.visit(.i32LtU) } - public mutating func visitI32GtS() throws -> Output { return try self.visit(.i32GtS) } - public mutating func visitI32GtU() throws -> Output { return try self.visit(.i32GtU) } - public mutating func visitI32LeS() throws -> Output { return try self.visit(.i32LeS) } - public mutating func visitI32LeU() throws -> Output { return try self.visit(.i32LeU) } - public mutating func visitI32GeS() throws -> Output { return try self.visit(.i32GeS) } - public mutating func visitI32GeU() throws -> Output { return try self.visit(.i32GeU) } - public mutating func visitI64Eqz() throws -> Output { return try self.visit(.i64Eqz) } - public mutating func visitI64Eq() throws -> Output { return try self.visit(.i64Eq) } - public mutating func visitI64Ne() throws -> Output { return try self.visit(.i64Ne) } - public mutating func visitI64LtS() throws -> Output { return try self.visit(.i64LtS) } - public mutating func visitI64LtU() throws -> Output { return try self.visit(.i64LtU) } - public mutating func visitI64GtS() throws -> Output { return try self.visit(.i64GtS) } - public mutating func visitI64GtU() throws -> Output { return try self.visit(.i64GtU) } - public mutating func visitI64LeS() throws -> Output { return try self.visit(.i64LeS) } - public mutating func visitI64LeU() throws -> Output { return try self.visit(.i64LeU) } - public mutating func visitI64GeS() throws -> Output { return try self.visit(.i64GeS) } - public mutating func visitI64GeU() throws -> Output { return try self.visit(.i64GeU) } - public mutating func visitF32Eq() throws -> Output { return try self.visit(.f32Eq) } - public mutating func visitF32Ne() throws -> Output { return try self.visit(.f32Ne) } - public mutating func visitF32Lt() throws -> Output { return try self.visit(.f32Lt) } - public mutating func visitF32Gt() throws -> Output { return try self.visit(.f32Gt) } - public mutating func visitF32Le() throws -> Output { return try self.visit(.f32Le) } - public mutating func visitF32Ge() throws -> Output { return try self.visit(.f32Ge) } - public mutating func visitF64Eq() throws -> Output { return try self.visit(.f64Eq) } - public mutating func visitF64Ne() throws -> Output { return try self.visit(.f64Ne) } - public mutating func visitF64Lt() throws -> Output { return try self.visit(.f64Lt) } - public mutating func visitF64Gt() throws -> Output { return try self.visit(.f64Gt) } - public mutating func visitF64Le() throws -> Output { return try self.visit(.f64Le) } - public mutating func visitF64Ge() throws -> Output { return try self.visit(.f64Ge) } - public mutating func visitI32Clz() throws -> Output { return try self.visit(.i32Clz) } - public mutating func visitI32Ctz() throws -> Output { return try self.visit(.i32Ctz) } - public mutating func visitI32Popcnt() throws -> Output { return try self.visit(.i32Popcnt) } - public mutating func visitI32Add() throws -> Output { return try self.visit(.i32Add) } - public mutating func visitI32Sub() throws -> Output { return try self.visit(.i32Sub) } - public mutating func visitI32Mul() throws -> Output { return try self.visit(.i32Mul) } - public mutating func visitI32DivS() throws -> Output { return try self.visit(.i32DivS) } - public mutating func visitI32DivU() throws -> Output { return try self.visit(.i32DivU) } - public mutating func visitI32RemS() throws -> Output { return try self.visit(.i32RemS) } - public mutating func visitI32RemU() throws -> Output { return try self.visit(.i32RemU) } - public mutating func visitI32And() throws -> Output { return try self.visit(.i32And) } - public mutating func visitI32Or() throws -> Output { return try self.visit(.i32Or) } - public mutating func visitI32Xor() throws -> Output { return try self.visit(.i32Xor) } - public mutating func visitI32Shl() throws -> Output { return try self.visit(.i32Shl) } - public mutating func visitI32ShrS() throws -> Output { return try self.visit(.i32ShrS) } - public mutating func visitI32ShrU() throws -> Output { return try self.visit(.i32ShrU) } - public mutating func visitI32Rotl() throws -> Output { return try self.visit(.i32Rotl) } - public mutating func visitI32Rotr() throws -> Output { return try self.visit(.i32Rotr) } - public mutating func visitI64Clz() throws -> Output { return try self.visit(.i64Clz) } - public mutating func visitI64Ctz() throws -> Output { return try self.visit(.i64Ctz) } - public mutating func visitI64Popcnt() throws -> Output { return try self.visit(.i64Popcnt) } - public mutating func visitI64Add() throws -> Output { return try self.visit(.i64Add) } - public mutating func visitI64Sub() throws -> Output { return try self.visit(.i64Sub) } - public mutating func visitI64Mul() throws -> Output { return try self.visit(.i64Mul) } - public mutating func visitI64DivS() throws -> Output { return try self.visit(.i64DivS) } - public mutating func visitI64DivU() throws -> Output { return try self.visit(.i64DivU) } - public mutating func visitI64RemS() throws -> Output { return try self.visit(.i64RemS) } - public mutating func visitI64RemU() throws -> Output { return try self.visit(.i64RemU) } - public mutating func visitI64And() throws -> Output { return try self.visit(.i64And) } - public mutating func visitI64Or() throws -> Output { return try self.visit(.i64Or) } - public mutating func visitI64Xor() throws -> Output { return try self.visit(.i64Xor) } - public mutating func visitI64Shl() throws -> Output { return try self.visit(.i64Shl) } - public mutating func visitI64ShrS() throws -> Output { return try self.visit(.i64ShrS) } - public mutating func visitI64ShrU() throws -> Output { return try self.visit(.i64ShrU) } - public mutating func visitI64Rotl() throws -> Output { return try self.visit(.i64Rotl) } - public mutating func visitI64Rotr() throws -> Output { return try self.visit(.i64Rotr) } - public mutating func visitF32Abs() throws -> Output { return try self.visit(.f32Abs) } - public mutating func visitF32Neg() throws -> Output { return try self.visit(.f32Neg) } - public mutating func visitF32Ceil() throws -> Output { return try self.visit(.f32Ceil) } - public mutating func visitF32Floor() throws -> Output { return try self.visit(.f32Floor) } - public mutating func visitF32Trunc() throws -> Output { return try self.visit(.f32Trunc) } - public mutating func visitF32Nearest() throws -> Output { return try self.visit(.f32Nearest) } - public mutating func visitF32Sqrt() throws -> Output { return try self.visit(.f32Sqrt) } - public mutating func visitF32Add() throws -> Output { return try self.visit(.f32Add) } - public mutating func visitF32Sub() throws -> Output { return try self.visit(.f32Sub) } - public mutating func visitF32Mul() throws -> Output { return try self.visit(.f32Mul) } - public mutating func visitF32Div() throws -> Output { return try self.visit(.f32Div) } - public mutating func visitF32Min() throws -> Output { return try self.visit(.f32Min) } - public mutating func visitF32Max() throws -> Output { return try self.visit(.f32Max) } - public mutating func visitF32Copysign() throws -> Output { return try self.visit(.f32Copysign) } - public mutating func visitF64Abs() throws -> Output { return try self.visit(.f64Abs) } - public mutating func visitF64Neg() throws -> Output { return try self.visit(.f64Neg) } - public mutating func visitF64Ceil() throws -> Output { return try self.visit(.f64Ceil) } - public mutating func visitF64Floor() throws -> Output { return try self.visit(.f64Floor) } - public mutating func visitF64Trunc() throws -> Output { return try self.visit(.f64Trunc) } - public mutating func visitF64Nearest() throws -> Output { return try self.visit(.f64Nearest) } - public mutating func visitF64Sqrt() throws -> Output { return try self.visit(.f64Sqrt) } - public mutating func visitF64Add() throws -> Output { return try self.visit(.f64Add) } - public mutating func visitF64Sub() throws -> Output { return try self.visit(.f64Sub) } - public mutating func visitF64Mul() throws -> Output { return try self.visit(.f64Mul) } - public mutating func visitF64Div() throws -> Output { return try self.visit(.f64Div) } - public mutating func visitF64Min() throws -> Output { return try self.visit(.f64Min) } - public mutating func visitF64Max() throws -> Output { return try self.visit(.f64Max) } - public mutating func visitF64Copysign() throws -> Output { return try self.visit(.f64Copysign) } - public mutating func visitI32WrapI64() throws -> Output { return try self.visit(.i32WrapI64) } - public mutating func visitI32TruncF32S() throws -> Output { return try self.visit(.i32TruncF32S) } - public mutating func visitI32TruncF32U() throws -> Output { return try self.visit(.i32TruncF32U) } - public mutating func visitI32TruncF64S() throws -> Output { return try self.visit(.i32TruncF64S) } - public mutating func visitI32TruncF64U() throws -> Output { return try self.visit(.i32TruncF64U) } - public mutating func visitI64ExtendI32S() throws -> Output { return try self.visit(.i64ExtendI32S) } - public mutating func visitI64ExtendI32U() throws -> Output { return try self.visit(.i64ExtendI32U) } - public mutating func visitI64TruncF32S() throws -> Output { return try self.visit(.i64TruncF32S) } - public mutating func visitI64TruncF32U() throws -> Output { return try self.visit(.i64TruncF32U) } - public mutating func visitI64TruncF64S() throws -> Output { return try self.visit(.i64TruncF64S) } - public mutating func visitI64TruncF64U() throws -> Output { return try self.visit(.i64TruncF64U) } - public mutating func visitF32ConvertI32S() throws -> Output { return try self.visit(.f32ConvertI32S) } - public mutating func visitF32ConvertI32U() throws -> Output { return try self.visit(.f32ConvertI32U) } - public mutating func visitF32ConvertI64S() throws -> Output { return try self.visit(.f32ConvertI64S) } - public mutating func visitF32ConvertI64U() throws -> Output { return try self.visit(.f32ConvertI64U) } - public mutating func visitF32DemoteF64() throws -> Output { return try self.visit(.f32DemoteF64) } - public mutating func visitF64ConvertI32S() throws -> Output { return try self.visit(.f64ConvertI32S) } - public mutating func visitF64ConvertI32U() throws -> Output { return try self.visit(.f64ConvertI32U) } - public mutating func visitF64ConvertI64S() throws -> Output { return try self.visit(.f64ConvertI64S) } - public mutating func visitF64ConvertI64U() throws -> Output { return try self.visit(.f64ConvertI64U) } - public mutating func visitF64PromoteF32() throws -> Output { return try self.visit(.f64PromoteF32) } - public mutating func visitI32ReinterpretF32() throws -> Output { return try self.visit(.i32ReinterpretF32) } - public mutating func visitI64ReinterpretF64() throws -> Output { return try self.visit(.i64ReinterpretF64) } - public mutating func visitF32ReinterpretI32() throws -> Output { return try self.visit(.f32ReinterpretI32) } - public mutating func visitF64ReinterpretI64() throws -> Output { return try self.visit(.f64ReinterpretI64) } - public mutating func visitI32Extend8S() throws -> Output { return try self.visit(.i32Extend8S) } - public mutating func visitI32Extend16S() throws -> Output { return try self.visit(.i32Extend16S) } - public mutating func visitI64Extend8S() throws -> Output { return try self.visit(.i64Extend8S) } - public mutating func visitI64Extend16S() throws -> Output { return try self.visit(.i64Extend16S) } - public mutating func visitI64Extend32S() throws -> Output { return try self.visit(.i64Extend32S) } - public mutating func visitMemoryInit(dataIndex: UInt32) throws -> Output { return try self.visit(.memoryInit(dataIndex: dataIndex)) } - public mutating func visitDataDrop(dataIndex: UInt32) throws -> Output { return try self.visit(.dataDrop(dataIndex: dataIndex)) } - public mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws -> Output { return try self.visit(.memoryCopy(dstMem: dstMem, srcMem: srcMem)) } - public mutating func visitMemoryFill(memory: UInt32) throws -> Output { return try self.visit(.memoryFill(memory: memory)) } - public mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws -> Output { return try self.visit(.tableInit(elemIndex: elemIndex, table: table)) } - public mutating func visitElemDrop(elemIndex: UInt32) throws -> Output { return try self.visit(.elemDrop(elemIndex: elemIndex)) } - public mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws -> Output { return try self.visit(.tableCopy(dstTable: dstTable, srcTable: srcTable)) } - public mutating func visitTableFill(table: UInt32) throws -> Output { return try self.visit(.tableFill(table: table)) } - public mutating func visitTableGet(table: UInt32) throws -> Output { return try self.visit(.tableGet(table: table)) } - public mutating func visitTableSet(table: UInt32) throws -> Output { return try self.visit(.tableSet(table: table)) } - public mutating func visitTableGrow(table: UInt32) throws -> Output { return try self.visit(.tableGrow(table: table)) } - public mutating func visitTableSize(table: UInt32) throws -> Output { return try self.visit(.tableSize(table: table)) } - public mutating func visitI32TruncSatF32S() throws -> Output { return try self.visit(.i32TruncSatF32S) } - public mutating func visitI32TruncSatF32U() throws -> Output { return try self.visit(.i32TruncSatF32U) } - public mutating func visitI32TruncSatF64S() throws -> Output { return try self.visit(.i32TruncSatF64S) } - public mutating func visitI32TruncSatF64U() throws -> Output { return try self.visit(.i32TruncSatF64U) } - public mutating func visitI64TruncSatF32S() throws -> Output { return try self.visit(.i64TruncSatF32S) } - public mutating func visitI64TruncSatF32U() throws -> Output { return try self.visit(.i64TruncSatF32U) } - public mutating func visitI64TruncSatF64S() throws -> Output { return try self.visit(.i64TruncSatF64S) } - public mutating func visitI64TruncSatF64U() throws -> Output { return try self.visit(.i64TruncSatF64U) } + public mutating func visitUnreachable() throws { return try self.visit(.unreachable) } + public mutating func visitNop() throws { return try self.visit(.nop) } + public mutating func visitBlock(blockType: BlockType) throws { return try self.visit(.block(blockType: blockType)) } + public mutating func visitLoop(blockType: BlockType) throws { return try self.visit(.loop(blockType: blockType)) } + public mutating func visitIf(blockType: BlockType) throws { return try self.visit(.if(blockType: blockType)) } + public mutating func visitElse() throws { return try self.visit(.else) } + public mutating func visitEnd() throws { return try self.visit(.end) } + public mutating func visitBr(relativeDepth: UInt32) throws { return try self.visit(.br(relativeDepth: relativeDepth)) } + public mutating func visitBrIf(relativeDepth: UInt32) throws { return try self.visit(.brIf(relativeDepth: relativeDepth)) } + public mutating func visitBrTable(targets: BrTable) throws { return try self.visit(.brTable(targets: targets)) } + public mutating func visitReturn() throws { return try self.visit(.return) } + public mutating func visitCall(functionIndex: UInt32) throws { return try self.visit(.call(functionIndex: functionIndex)) } + public mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws { return try self.visit(.callIndirect(typeIndex: typeIndex, tableIndex: tableIndex)) } + public mutating func visitDrop() throws { return try self.visit(.drop) } + public mutating func visitSelect() throws { return try self.visit(.select) } + public mutating func visitTypedSelect(type: ValueType) throws { return try self.visit(.typedSelect(type: type)) } + public mutating func visitLocalGet(localIndex: UInt32) throws { return try self.visit(.localGet(localIndex: localIndex)) } + public mutating func visitLocalSet(localIndex: UInt32) throws { return try self.visit(.localSet(localIndex: localIndex)) } + public mutating func visitLocalTee(localIndex: UInt32) throws { return try self.visit(.localTee(localIndex: localIndex)) } + public mutating func visitGlobalGet(globalIndex: UInt32) throws { return try self.visit(.globalGet(globalIndex: globalIndex)) } + public mutating func visitGlobalSet(globalIndex: UInt32) throws { return try self.visit(.globalSet(globalIndex: globalIndex)) } + public mutating func visitI32Load(memarg: MemArg) throws { return try self.visit(.i32Load(memarg: memarg)) } + public mutating func visitI64Load(memarg: MemArg) throws { return try self.visit(.i64Load(memarg: memarg)) } + public mutating func visitF32Load(memarg: MemArg) throws { return try self.visit(.f32Load(memarg: memarg)) } + public mutating func visitF64Load(memarg: MemArg) throws { return try self.visit(.f64Load(memarg: memarg)) } + public mutating func visitI32Load8S(memarg: MemArg) throws { return try self.visit(.i32Load8S(memarg: memarg)) } + public mutating func visitI32Load8U(memarg: MemArg) throws { return try self.visit(.i32Load8U(memarg: memarg)) } + public mutating func visitI32Load16S(memarg: MemArg) throws { return try self.visit(.i32Load16S(memarg: memarg)) } + public mutating func visitI32Load16U(memarg: MemArg) throws { return try self.visit(.i32Load16U(memarg: memarg)) } + public mutating func visitI64Load8S(memarg: MemArg) throws { return try self.visit(.i64Load8S(memarg: memarg)) } + public mutating func visitI64Load8U(memarg: MemArg) throws { return try self.visit(.i64Load8U(memarg: memarg)) } + public mutating func visitI64Load16S(memarg: MemArg) throws { return try self.visit(.i64Load16S(memarg: memarg)) } + public mutating func visitI64Load16U(memarg: MemArg) throws { return try self.visit(.i64Load16U(memarg: memarg)) } + public mutating func visitI64Load32S(memarg: MemArg) throws { return try self.visit(.i64Load32S(memarg: memarg)) } + public mutating func visitI64Load32U(memarg: MemArg) throws { return try self.visit(.i64Load32U(memarg: memarg)) } + public mutating func visitI32Store(memarg: MemArg) throws { return try self.visit(.i32Store(memarg: memarg)) } + public mutating func visitI64Store(memarg: MemArg) throws { return try self.visit(.i64Store(memarg: memarg)) } + public mutating func visitF32Store(memarg: MemArg) throws { return try self.visit(.f32Store(memarg: memarg)) } + public mutating func visitF64Store(memarg: MemArg) throws { return try self.visit(.f64Store(memarg: memarg)) } + public mutating func visitI32Store8(memarg: MemArg) throws { return try self.visit(.i32Store8(memarg: memarg)) } + public mutating func visitI32Store16(memarg: MemArg) throws { return try self.visit(.i32Store16(memarg: memarg)) } + public mutating func visitI64Store8(memarg: MemArg) throws { return try self.visit(.i64Store8(memarg: memarg)) } + public mutating func visitI64Store16(memarg: MemArg) throws { return try self.visit(.i64Store16(memarg: memarg)) } + public mutating func visitI64Store32(memarg: MemArg) throws { return try self.visit(.i64Store32(memarg: memarg)) } + public mutating func visitMemorySize(memory: UInt32) throws { return try self.visit(.memorySize(memory: memory)) } + public mutating func visitMemoryGrow(memory: UInt32) throws { return try self.visit(.memoryGrow(memory: memory)) } + public mutating func visitI32Const(value: Int32) throws { return try self.visit(.i32Const(value: value)) } + public mutating func visitI64Const(value: Int64) throws { return try self.visit(.i64Const(value: value)) } + public mutating func visitF32Const(value: IEEE754.Float32) throws { return try self.visit(.f32Const(value: value)) } + public mutating func visitF64Const(value: IEEE754.Float64) throws { return try self.visit(.f64Const(value: value)) } + public mutating func visitRefNull(type: ReferenceType) throws { return try self.visit(.refNull(type: type)) } + public mutating func visitRefIsNull() throws { return try self.visit(.refIsNull) } + public mutating func visitRefFunc(functionIndex: UInt32) throws { return try self.visit(.refFunc(functionIndex: functionIndex)) } + public mutating func visitI32Eqz() throws { return try self.visit(.i32Eqz) } + public mutating func visitI32Eq() throws { return try self.visit(.i32Eq) } + public mutating func visitI32Ne() throws { return try self.visit(.i32Ne) } + public mutating func visitI32LtS() throws { return try self.visit(.i32LtS) } + public mutating func visitI32LtU() throws { return try self.visit(.i32LtU) } + public mutating func visitI32GtS() throws { return try self.visit(.i32GtS) } + public mutating func visitI32GtU() throws { return try self.visit(.i32GtU) } + public mutating func visitI32LeS() throws { return try self.visit(.i32LeS) } + public mutating func visitI32LeU() throws { return try self.visit(.i32LeU) } + public mutating func visitI32GeS() throws { return try self.visit(.i32GeS) } + public mutating func visitI32GeU() throws { return try self.visit(.i32GeU) } + public mutating func visitI64Eqz() throws { return try self.visit(.i64Eqz) } + public mutating func visitI64Eq() throws { return try self.visit(.i64Eq) } + public mutating func visitI64Ne() throws { return try self.visit(.i64Ne) } + public mutating func visitI64LtS() throws { return try self.visit(.i64LtS) } + public mutating func visitI64LtU() throws { return try self.visit(.i64LtU) } + public mutating func visitI64GtS() throws { return try self.visit(.i64GtS) } + public mutating func visitI64GtU() throws { return try self.visit(.i64GtU) } + public mutating func visitI64LeS() throws { return try self.visit(.i64LeS) } + public mutating func visitI64LeU() throws { return try self.visit(.i64LeU) } + public mutating func visitI64GeS() throws { return try self.visit(.i64GeS) } + public mutating func visitI64GeU() throws { return try self.visit(.i64GeU) } + public mutating func visitF32Eq() throws { return try self.visit(.f32Eq) } + public mutating func visitF32Ne() throws { return try self.visit(.f32Ne) } + public mutating func visitF32Lt() throws { return try self.visit(.f32Lt) } + public mutating func visitF32Gt() throws { return try self.visit(.f32Gt) } + public mutating func visitF32Le() throws { return try self.visit(.f32Le) } + public mutating func visitF32Ge() throws { return try self.visit(.f32Ge) } + public mutating func visitF64Eq() throws { return try self.visit(.f64Eq) } + public mutating func visitF64Ne() throws { return try self.visit(.f64Ne) } + public mutating func visitF64Lt() throws { return try self.visit(.f64Lt) } + public mutating func visitF64Gt() throws { return try self.visit(.f64Gt) } + public mutating func visitF64Le() throws { return try self.visit(.f64Le) } + public mutating func visitF64Ge() throws { return try self.visit(.f64Ge) } + public mutating func visitI32Clz() throws { return try self.visit(.i32Clz) } + public mutating func visitI32Ctz() throws { return try self.visit(.i32Ctz) } + public mutating func visitI32Popcnt() throws { return try self.visit(.i32Popcnt) } + public mutating func visitI32Add() throws { return try self.visit(.i32Add) } + public mutating func visitI32Sub() throws { return try self.visit(.i32Sub) } + public mutating func visitI32Mul() throws { return try self.visit(.i32Mul) } + public mutating func visitI32DivS() throws { return try self.visit(.i32DivS) } + public mutating func visitI32DivU() throws { return try self.visit(.i32DivU) } + public mutating func visitI32RemS() throws { return try self.visit(.i32RemS) } + public mutating func visitI32RemU() throws { return try self.visit(.i32RemU) } + public mutating func visitI32And() throws { return try self.visit(.i32And) } + public mutating func visitI32Or() throws { return try self.visit(.i32Or) } + public mutating func visitI32Xor() throws { return try self.visit(.i32Xor) } + public mutating func visitI32Shl() throws { return try self.visit(.i32Shl) } + public mutating func visitI32ShrS() throws { return try self.visit(.i32ShrS) } + public mutating func visitI32ShrU() throws { return try self.visit(.i32ShrU) } + public mutating func visitI32Rotl() throws { return try self.visit(.i32Rotl) } + public mutating func visitI32Rotr() throws { return try self.visit(.i32Rotr) } + public mutating func visitI64Clz() throws { return try self.visit(.i64Clz) } + public mutating func visitI64Ctz() throws { return try self.visit(.i64Ctz) } + public mutating func visitI64Popcnt() throws { return try self.visit(.i64Popcnt) } + public mutating func visitI64Add() throws { return try self.visit(.i64Add) } + public mutating func visitI64Sub() throws { return try self.visit(.i64Sub) } + public mutating func visitI64Mul() throws { return try self.visit(.i64Mul) } + public mutating func visitI64DivS() throws { return try self.visit(.i64DivS) } + public mutating func visitI64DivU() throws { return try self.visit(.i64DivU) } + public mutating func visitI64RemS() throws { return try self.visit(.i64RemS) } + public mutating func visitI64RemU() throws { return try self.visit(.i64RemU) } + public mutating func visitI64And() throws { return try self.visit(.i64And) } + public mutating func visitI64Or() throws { return try self.visit(.i64Or) } + public mutating func visitI64Xor() throws { return try self.visit(.i64Xor) } + public mutating func visitI64Shl() throws { return try self.visit(.i64Shl) } + public mutating func visitI64ShrS() throws { return try self.visit(.i64ShrS) } + public mutating func visitI64ShrU() throws { return try self.visit(.i64ShrU) } + public mutating func visitI64Rotl() throws { return try self.visit(.i64Rotl) } + public mutating func visitI64Rotr() throws { return try self.visit(.i64Rotr) } + public mutating func visitF32Abs() throws { return try self.visit(.f32Abs) } + public mutating func visitF32Neg() throws { return try self.visit(.f32Neg) } + public mutating func visitF32Ceil() throws { return try self.visit(.f32Ceil) } + public mutating func visitF32Floor() throws { return try self.visit(.f32Floor) } + public mutating func visitF32Trunc() throws { return try self.visit(.f32Trunc) } + public mutating func visitF32Nearest() throws { return try self.visit(.f32Nearest) } + public mutating func visitF32Sqrt() throws { return try self.visit(.f32Sqrt) } + public mutating func visitF32Add() throws { return try self.visit(.f32Add) } + public mutating func visitF32Sub() throws { return try self.visit(.f32Sub) } + public mutating func visitF32Mul() throws { return try self.visit(.f32Mul) } + public mutating func visitF32Div() throws { return try self.visit(.f32Div) } + public mutating func visitF32Min() throws { return try self.visit(.f32Min) } + public mutating func visitF32Max() throws { return try self.visit(.f32Max) } + public mutating func visitF32Copysign() throws { return try self.visit(.f32Copysign) } + public mutating func visitF64Abs() throws { return try self.visit(.f64Abs) } + public mutating func visitF64Neg() throws { return try self.visit(.f64Neg) } + public mutating func visitF64Ceil() throws { return try self.visit(.f64Ceil) } + public mutating func visitF64Floor() throws { return try self.visit(.f64Floor) } + public mutating func visitF64Trunc() throws { return try self.visit(.f64Trunc) } + public mutating func visitF64Nearest() throws { return try self.visit(.f64Nearest) } + public mutating func visitF64Sqrt() throws { return try self.visit(.f64Sqrt) } + public mutating func visitF64Add() throws { return try self.visit(.f64Add) } + public mutating func visitF64Sub() throws { return try self.visit(.f64Sub) } + public mutating func visitF64Mul() throws { return try self.visit(.f64Mul) } + public mutating func visitF64Div() throws { return try self.visit(.f64Div) } + public mutating func visitF64Min() throws { return try self.visit(.f64Min) } + public mutating func visitF64Max() throws { return try self.visit(.f64Max) } + public mutating func visitF64Copysign() throws { return try self.visit(.f64Copysign) } + public mutating func visitI32WrapI64() throws { return try self.visit(.i32WrapI64) } + public mutating func visitI32TruncF32S() throws { return try self.visit(.i32TruncF32S) } + public mutating func visitI32TruncF32U() throws { return try self.visit(.i32TruncF32U) } + public mutating func visitI32TruncF64S() throws { return try self.visit(.i32TruncF64S) } + public mutating func visitI32TruncF64U() throws { return try self.visit(.i32TruncF64U) } + public mutating func visitI64ExtendI32S() throws { return try self.visit(.i64ExtendI32S) } + public mutating func visitI64ExtendI32U() throws { return try self.visit(.i64ExtendI32U) } + public mutating func visitI64TruncF32S() throws { return try self.visit(.i64TruncF32S) } + public mutating func visitI64TruncF32U() throws { return try self.visit(.i64TruncF32U) } + public mutating func visitI64TruncF64S() throws { return try self.visit(.i64TruncF64S) } + public mutating func visitI64TruncF64U() throws { return try self.visit(.i64TruncF64U) } + public mutating func visitF32ConvertI32S() throws { return try self.visit(.f32ConvertI32S) } + public mutating func visitF32ConvertI32U() throws { return try self.visit(.f32ConvertI32U) } + public mutating func visitF32ConvertI64S() throws { return try self.visit(.f32ConvertI64S) } + public mutating func visitF32ConvertI64U() throws { return try self.visit(.f32ConvertI64U) } + public mutating func visitF32DemoteF64() throws { return try self.visit(.f32DemoteF64) } + public mutating func visitF64ConvertI32S() throws { return try self.visit(.f64ConvertI32S) } + public mutating func visitF64ConvertI32U() throws { return try self.visit(.f64ConvertI32U) } + public mutating func visitF64ConvertI64S() throws { return try self.visit(.f64ConvertI64S) } + public mutating func visitF64ConvertI64U() throws { return try self.visit(.f64ConvertI64U) } + public mutating func visitF64PromoteF32() throws { return try self.visit(.f64PromoteF32) } + public mutating func visitI32ReinterpretF32() throws { return try self.visit(.i32ReinterpretF32) } + public mutating func visitI64ReinterpretF64() throws { return try self.visit(.i64ReinterpretF64) } + public mutating func visitF32ReinterpretI32() throws { return try self.visit(.f32ReinterpretI32) } + public mutating func visitF64ReinterpretI64() throws { return try self.visit(.f64ReinterpretI64) } + public mutating func visitI32Extend8S() throws { return try self.visit(.i32Extend8S) } + public mutating func visitI32Extend16S() throws { return try self.visit(.i32Extend16S) } + public mutating func visitI64Extend8S() throws { return try self.visit(.i64Extend8S) } + public mutating func visitI64Extend16S() throws { return try self.visit(.i64Extend16S) } + public mutating func visitI64Extend32S() throws { return try self.visit(.i64Extend32S) } + public mutating func visitMemoryInit(dataIndex: UInt32) throws { return try self.visit(.memoryInit(dataIndex: dataIndex)) } + public mutating func visitDataDrop(dataIndex: UInt32) throws { return try self.visit(.dataDrop(dataIndex: dataIndex)) } + public mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws { return try self.visit(.memoryCopy(dstMem: dstMem, srcMem: srcMem)) } + public mutating func visitMemoryFill(memory: UInt32) throws { return try self.visit(.memoryFill(memory: memory)) } + public mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws { return try self.visit(.tableInit(elemIndex: elemIndex, table: table)) } + public mutating func visitElemDrop(elemIndex: UInt32) throws { return try self.visit(.elemDrop(elemIndex: elemIndex)) } + public mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws { return try self.visit(.tableCopy(dstTable: dstTable, srcTable: srcTable)) } + public mutating func visitTableFill(table: UInt32) throws { return try self.visit(.tableFill(table: table)) } + public mutating func visitTableGet(table: UInt32) throws { return try self.visit(.tableGet(table: table)) } + public mutating func visitTableSet(table: UInt32) throws { return try self.visit(.tableSet(table: table)) } + public mutating func visitTableGrow(table: UInt32) throws { return try self.visit(.tableGrow(table: table)) } + public mutating func visitTableSize(table: UInt32) throws { return try self.visit(.tableSize(table: table)) } + public mutating func visitI32TruncSatF32S() throws { return try self.visit(.i32TruncSatF32S) } + public mutating func visitI32TruncSatF32U() throws { return try self.visit(.i32TruncSatF32U) } + public mutating func visitI32TruncSatF64S() throws { return try self.visit(.i32TruncSatF64S) } + public mutating func visitI32TruncSatF64U() throws { return try self.visit(.i32TruncSatF64U) } + public mutating func visitI64TruncSatF32S() throws { return try self.visit(.i64TruncSatF32S) } + public mutating func visitI64TruncSatF32U() throws { return try self.visit(.i64TruncSatF32U) } + public mutating func visitI64TruncSatF64S() throws { return try self.visit(.i64TruncSatF64S) } + public mutating func visitI64TruncSatF64U() throws { return try self.visit(.i64TruncSatF64U) } } /// A visitor that traces the instructions visited. @@ -434,807 +434,807 @@ public struct InstructionTracingVisitor: InstructionVisit self.trace = trace self.visitor = visitor } - public mutating func visitUnreachable() throws -> V.Output { + public mutating func visitUnreachable() throws { trace(.unreachable) return try visitor.visitUnreachable() } - public mutating func visitNop() throws -> V.Output { + public mutating func visitNop() throws { trace(.nop) return try visitor.visitNop() } - public mutating func visitBlock(blockType: BlockType) throws -> V.Output { + public mutating func visitBlock(blockType: BlockType) throws { trace(.block(blockType: blockType)) return try visitor.visitBlock(blockType: blockType) } - public mutating func visitLoop(blockType: BlockType) throws -> V.Output { + public mutating func visitLoop(blockType: BlockType) throws { trace(.loop(blockType: blockType)) return try visitor.visitLoop(blockType: blockType) } - public mutating func visitIf(blockType: BlockType) throws -> V.Output { + public mutating func visitIf(blockType: BlockType) throws { trace(.if(blockType: blockType)) return try visitor.visitIf(blockType: blockType) } - public mutating func visitElse() throws -> V.Output { + public mutating func visitElse() throws { trace(.else) return try visitor.visitElse() } - public mutating func visitEnd() throws -> V.Output { + public mutating func visitEnd() throws { trace(.end) return try visitor.visitEnd() } - public mutating func visitBr(relativeDepth: UInt32) throws -> V.Output { + public mutating func visitBr(relativeDepth: UInt32) throws { trace(.br(relativeDepth: relativeDepth)) return try visitor.visitBr(relativeDepth: relativeDepth) } - public mutating func visitBrIf(relativeDepth: UInt32) throws -> V.Output { + public mutating func visitBrIf(relativeDepth: UInt32) throws { trace(.brIf(relativeDepth: relativeDepth)) return try visitor.visitBrIf(relativeDepth: relativeDepth) } - public mutating func visitBrTable(targets: BrTable) throws -> V.Output { + public mutating func visitBrTable(targets: BrTable) throws { trace(.brTable(targets: targets)) return try visitor.visitBrTable(targets: targets) } - public mutating func visitReturn() throws -> V.Output { + public mutating func visitReturn() throws { trace(.return) return try visitor.visitReturn() } - public mutating func visitCall(functionIndex: UInt32) throws -> V.Output { + public mutating func visitCall(functionIndex: UInt32) throws { trace(.call(functionIndex: functionIndex)) return try visitor.visitCall(functionIndex: functionIndex) } - public mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws -> V.Output { + public mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws { trace(.callIndirect(typeIndex: typeIndex, tableIndex: tableIndex)) return try visitor.visitCallIndirect(typeIndex: typeIndex, tableIndex: tableIndex) } - public mutating func visitDrop() throws -> V.Output { + public mutating func visitDrop() throws { trace(.drop) return try visitor.visitDrop() } - public mutating func visitSelect() throws -> V.Output { + public mutating func visitSelect() throws { trace(.select) return try visitor.visitSelect() } - public mutating func visitTypedSelect(type: ValueType) throws -> V.Output { + public mutating func visitTypedSelect(type: ValueType) throws { trace(.typedSelect(type: type)) return try visitor.visitTypedSelect(type: type) } - public mutating func visitLocalGet(localIndex: UInt32) throws -> V.Output { + public mutating func visitLocalGet(localIndex: UInt32) throws { trace(.localGet(localIndex: localIndex)) return try visitor.visitLocalGet(localIndex: localIndex) } - public mutating func visitLocalSet(localIndex: UInt32) throws -> V.Output { + public mutating func visitLocalSet(localIndex: UInt32) throws { trace(.localSet(localIndex: localIndex)) return try visitor.visitLocalSet(localIndex: localIndex) } - public mutating func visitLocalTee(localIndex: UInt32) throws -> V.Output { + public mutating func visitLocalTee(localIndex: UInt32) throws { trace(.localTee(localIndex: localIndex)) return try visitor.visitLocalTee(localIndex: localIndex) } - public mutating func visitGlobalGet(globalIndex: UInt32) throws -> V.Output { + public mutating func visitGlobalGet(globalIndex: UInt32) throws { trace(.globalGet(globalIndex: globalIndex)) return try visitor.visitGlobalGet(globalIndex: globalIndex) } - public mutating func visitGlobalSet(globalIndex: UInt32) throws -> V.Output { + public mutating func visitGlobalSet(globalIndex: UInt32) throws { trace(.globalSet(globalIndex: globalIndex)) return try visitor.visitGlobalSet(globalIndex: globalIndex) } - public mutating func visitI32Load(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Load(memarg: MemArg) throws { trace(.i32Load(memarg: memarg)) return try visitor.visitI32Load(memarg: memarg) } - public mutating func visitI64Load(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Load(memarg: MemArg) throws { trace(.i64Load(memarg: memarg)) return try visitor.visitI64Load(memarg: memarg) } - public mutating func visitF32Load(memarg: MemArg) throws -> V.Output { + public mutating func visitF32Load(memarg: MemArg) throws { trace(.f32Load(memarg: memarg)) return try visitor.visitF32Load(memarg: memarg) } - public mutating func visitF64Load(memarg: MemArg) throws -> V.Output { + public mutating func visitF64Load(memarg: MemArg) throws { trace(.f64Load(memarg: memarg)) return try visitor.visitF64Load(memarg: memarg) } - public mutating func visitI32Load8S(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Load8S(memarg: MemArg) throws { trace(.i32Load8S(memarg: memarg)) return try visitor.visitI32Load8S(memarg: memarg) } - public mutating func visitI32Load8U(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Load8U(memarg: MemArg) throws { trace(.i32Load8U(memarg: memarg)) return try visitor.visitI32Load8U(memarg: memarg) } - public mutating func visitI32Load16S(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Load16S(memarg: MemArg) throws { trace(.i32Load16S(memarg: memarg)) return try visitor.visitI32Load16S(memarg: memarg) } - public mutating func visitI32Load16U(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Load16U(memarg: MemArg) throws { trace(.i32Load16U(memarg: memarg)) return try visitor.visitI32Load16U(memarg: memarg) } - public mutating func visitI64Load8S(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Load8S(memarg: MemArg) throws { trace(.i64Load8S(memarg: memarg)) return try visitor.visitI64Load8S(memarg: memarg) } - public mutating func visitI64Load8U(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Load8U(memarg: MemArg) throws { trace(.i64Load8U(memarg: memarg)) return try visitor.visitI64Load8U(memarg: memarg) } - public mutating func visitI64Load16S(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Load16S(memarg: MemArg) throws { trace(.i64Load16S(memarg: memarg)) return try visitor.visitI64Load16S(memarg: memarg) } - public mutating func visitI64Load16U(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Load16U(memarg: MemArg) throws { trace(.i64Load16U(memarg: memarg)) return try visitor.visitI64Load16U(memarg: memarg) } - public mutating func visitI64Load32S(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Load32S(memarg: MemArg) throws { trace(.i64Load32S(memarg: memarg)) return try visitor.visitI64Load32S(memarg: memarg) } - public mutating func visitI64Load32U(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Load32U(memarg: MemArg) throws { trace(.i64Load32U(memarg: memarg)) return try visitor.visitI64Load32U(memarg: memarg) } - public mutating func visitI32Store(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Store(memarg: MemArg) throws { trace(.i32Store(memarg: memarg)) return try visitor.visitI32Store(memarg: memarg) } - public mutating func visitI64Store(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Store(memarg: MemArg) throws { trace(.i64Store(memarg: memarg)) return try visitor.visitI64Store(memarg: memarg) } - public mutating func visitF32Store(memarg: MemArg) throws -> V.Output { + public mutating func visitF32Store(memarg: MemArg) throws { trace(.f32Store(memarg: memarg)) return try visitor.visitF32Store(memarg: memarg) } - public mutating func visitF64Store(memarg: MemArg) throws -> V.Output { + public mutating func visitF64Store(memarg: MemArg) throws { trace(.f64Store(memarg: memarg)) return try visitor.visitF64Store(memarg: memarg) } - public mutating func visitI32Store8(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Store8(memarg: MemArg) throws { trace(.i32Store8(memarg: memarg)) return try visitor.visitI32Store8(memarg: memarg) } - public mutating func visitI32Store16(memarg: MemArg) throws -> V.Output { + public mutating func visitI32Store16(memarg: MemArg) throws { trace(.i32Store16(memarg: memarg)) return try visitor.visitI32Store16(memarg: memarg) } - public mutating func visitI64Store8(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Store8(memarg: MemArg) throws { trace(.i64Store8(memarg: memarg)) return try visitor.visitI64Store8(memarg: memarg) } - public mutating func visitI64Store16(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Store16(memarg: MemArg) throws { trace(.i64Store16(memarg: memarg)) return try visitor.visitI64Store16(memarg: memarg) } - public mutating func visitI64Store32(memarg: MemArg) throws -> V.Output { + public mutating func visitI64Store32(memarg: MemArg) throws { trace(.i64Store32(memarg: memarg)) return try visitor.visitI64Store32(memarg: memarg) } - public mutating func visitMemorySize(memory: UInt32) throws -> V.Output { + public mutating func visitMemorySize(memory: UInt32) throws { trace(.memorySize(memory: memory)) return try visitor.visitMemorySize(memory: memory) } - public mutating func visitMemoryGrow(memory: UInt32) throws -> V.Output { + public mutating func visitMemoryGrow(memory: UInt32) throws { trace(.memoryGrow(memory: memory)) return try visitor.visitMemoryGrow(memory: memory) } - public mutating func visitI32Const(value: Int32) throws -> V.Output { + public mutating func visitI32Const(value: Int32) throws { trace(.i32Const(value: value)) return try visitor.visitI32Const(value: value) } - public mutating func visitI64Const(value: Int64) throws -> V.Output { + public mutating func visitI64Const(value: Int64) throws { trace(.i64Const(value: value)) return try visitor.visitI64Const(value: value) } - public mutating func visitF32Const(value: IEEE754.Float32) throws -> V.Output { + public mutating func visitF32Const(value: IEEE754.Float32) throws { trace(.f32Const(value: value)) return try visitor.visitF32Const(value: value) } - public mutating func visitF64Const(value: IEEE754.Float64) throws -> V.Output { + public mutating func visitF64Const(value: IEEE754.Float64) throws { trace(.f64Const(value: value)) return try visitor.visitF64Const(value: value) } - public mutating func visitRefNull(type: ReferenceType) throws -> V.Output { + public mutating func visitRefNull(type: ReferenceType) throws { trace(.refNull(type: type)) return try visitor.visitRefNull(type: type) } - public mutating func visitRefIsNull() throws -> V.Output { + public mutating func visitRefIsNull() throws { trace(.refIsNull) return try visitor.visitRefIsNull() } - public mutating func visitRefFunc(functionIndex: UInt32) throws -> V.Output { + public mutating func visitRefFunc(functionIndex: UInt32) throws { trace(.refFunc(functionIndex: functionIndex)) return try visitor.visitRefFunc(functionIndex: functionIndex) } - public mutating func visitI32Eqz() throws -> V.Output { + public mutating func visitI32Eqz() throws { trace(.i32Eqz) return try visitor.visitI32Eqz() } - public mutating func visitI32Eq() throws -> V.Output { + public mutating func visitI32Eq() throws { trace(.i32Eq) return try visitor.visitI32Eq() } - public mutating func visitI32Ne() throws -> V.Output { + public mutating func visitI32Ne() throws { trace(.i32Ne) return try visitor.visitI32Ne() } - public mutating func visitI32LtS() throws -> V.Output { + public mutating func visitI32LtS() throws { trace(.i32LtS) return try visitor.visitI32LtS() } - public mutating func visitI32LtU() throws -> V.Output { + public mutating func visitI32LtU() throws { trace(.i32LtU) return try visitor.visitI32LtU() } - public mutating func visitI32GtS() throws -> V.Output { + public mutating func visitI32GtS() throws { trace(.i32GtS) return try visitor.visitI32GtS() } - public mutating func visitI32GtU() throws -> V.Output { + public mutating func visitI32GtU() throws { trace(.i32GtU) return try visitor.visitI32GtU() } - public mutating func visitI32LeS() throws -> V.Output { + public mutating func visitI32LeS() throws { trace(.i32LeS) return try visitor.visitI32LeS() } - public mutating func visitI32LeU() throws -> V.Output { + public mutating func visitI32LeU() throws { trace(.i32LeU) return try visitor.visitI32LeU() } - public mutating func visitI32GeS() throws -> V.Output { + public mutating func visitI32GeS() throws { trace(.i32GeS) return try visitor.visitI32GeS() } - public mutating func visitI32GeU() throws -> V.Output { + public mutating func visitI32GeU() throws { trace(.i32GeU) return try visitor.visitI32GeU() } - public mutating func visitI64Eqz() throws -> V.Output { + public mutating func visitI64Eqz() throws { trace(.i64Eqz) return try visitor.visitI64Eqz() } - public mutating func visitI64Eq() throws -> V.Output { + public mutating func visitI64Eq() throws { trace(.i64Eq) return try visitor.visitI64Eq() } - public mutating func visitI64Ne() throws -> V.Output { + public mutating func visitI64Ne() throws { trace(.i64Ne) return try visitor.visitI64Ne() } - public mutating func visitI64LtS() throws -> V.Output { + public mutating func visitI64LtS() throws { trace(.i64LtS) return try visitor.visitI64LtS() } - public mutating func visitI64LtU() throws -> V.Output { + public mutating func visitI64LtU() throws { trace(.i64LtU) return try visitor.visitI64LtU() } - public mutating func visitI64GtS() throws -> V.Output { + public mutating func visitI64GtS() throws { trace(.i64GtS) return try visitor.visitI64GtS() } - public mutating func visitI64GtU() throws -> V.Output { + public mutating func visitI64GtU() throws { trace(.i64GtU) return try visitor.visitI64GtU() } - public mutating func visitI64LeS() throws -> V.Output { + public mutating func visitI64LeS() throws { trace(.i64LeS) return try visitor.visitI64LeS() } - public mutating func visitI64LeU() throws -> V.Output { + public mutating func visitI64LeU() throws { trace(.i64LeU) return try visitor.visitI64LeU() } - public mutating func visitI64GeS() throws -> V.Output { + public mutating func visitI64GeS() throws { trace(.i64GeS) return try visitor.visitI64GeS() } - public mutating func visitI64GeU() throws -> V.Output { + public mutating func visitI64GeU() throws { trace(.i64GeU) return try visitor.visitI64GeU() } - public mutating func visitF32Eq() throws -> V.Output { + public mutating func visitF32Eq() throws { trace(.f32Eq) return try visitor.visitF32Eq() } - public mutating func visitF32Ne() throws -> V.Output { + public mutating func visitF32Ne() throws { trace(.f32Ne) return try visitor.visitF32Ne() } - public mutating func visitF32Lt() throws -> V.Output { + public mutating func visitF32Lt() throws { trace(.f32Lt) return try visitor.visitF32Lt() } - public mutating func visitF32Gt() throws -> V.Output { + public mutating func visitF32Gt() throws { trace(.f32Gt) return try visitor.visitF32Gt() } - public mutating func visitF32Le() throws -> V.Output { + public mutating func visitF32Le() throws { trace(.f32Le) return try visitor.visitF32Le() } - public mutating func visitF32Ge() throws -> V.Output { + public mutating func visitF32Ge() throws { trace(.f32Ge) return try visitor.visitF32Ge() } - public mutating func visitF64Eq() throws -> V.Output { + public mutating func visitF64Eq() throws { trace(.f64Eq) return try visitor.visitF64Eq() } - public mutating func visitF64Ne() throws -> V.Output { + public mutating func visitF64Ne() throws { trace(.f64Ne) return try visitor.visitF64Ne() } - public mutating func visitF64Lt() throws -> V.Output { + public mutating func visitF64Lt() throws { trace(.f64Lt) return try visitor.visitF64Lt() } - public mutating func visitF64Gt() throws -> V.Output { + public mutating func visitF64Gt() throws { trace(.f64Gt) return try visitor.visitF64Gt() } - public mutating func visitF64Le() throws -> V.Output { + public mutating func visitF64Le() throws { trace(.f64Le) return try visitor.visitF64Le() } - public mutating func visitF64Ge() throws -> V.Output { + public mutating func visitF64Ge() throws { trace(.f64Ge) return try visitor.visitF64Ge() } - public mutating func visitI32Clz() throws -> V.Output { + public mutating func visitI32Clz() throws { trace(.i32Clz) return try visitor.visitI32Clz() } - public mutating func visitI32Ctz() throws -> V.Output { + public mutating func visitI32Ctz() throws { trace(.i32Ctz) return try visitor.visitI32Ctz() } - public mutating func visitI32Popcnt() throws -> V.Output { + public mutating func visitI32Popcnt() throws { trace(.i32Popcnt) return try visitor.visitI32Popcnt() } - public mutating func visitI32Add() throws -> V.Output { + public mutating func visitI32Add() throws { trace(.i32Add) return try visitor.visitI32Add() } - public mutating func visitI32Sub() throws -> V.Output { + public mutating func visitI32Sub() throws { trace(.i32Sub) return try visitor.visitI32Sub() } - public mutating func visitI32Mul() throws -> V.Output { + public mutating func visitI32Mul() throws { trace(.i32Mul) return try visitor.visitI32Mul() } - public mutating func visitI32DivS() throws -> V.Output { + public mutating func visitI32DivS() throws { trace(.i32DivS) return try visitor.visitI32DivS() } - public mutating func visitI32DivU() throws -> V.Output { + public mutating func visitI32DivU() throws { trace(.i32DivU) return try visitor.visitI32DivU() } - public mutating func visitI32RemS() throws -> V.Output { + public mutating func visitI32RemS() throws { trace(.i32RemS) return try visitor.visitI32RemS() } - public mutating func visitI32RemU() throws -> V.Output { + public mutating func visitI32RemU() throws { trace(.i32RemU) return try visitor.visitI32RemU() } - public mutating func visitI32And() throws -> V.Output { + public mutating func visitI32And() throws { trace(.i32And) return try visitor.visitI32And() } - public mutating func visitI32Or() throws -> V.Output { + public mutating func visitI32Or() throws { trace(.i32Or) return try visitor.visitI32Or() } - public mutating func visitI32Xor() throws -> V.Output { + public mutating func visitI32Xor() throws { trace(.i32Xor) return try visitor.visitI32Xor() } - public mutating func visitI32Shl() throws -> V.Output { + public mutating func visitI32Shl() throws { trace(.i32Shl) return try visitor.visitI32Shl() } - public mutating func visitI32ShrS() throws -> V.Output { + public mutating func visitI32ShrS() throws { trace(.i32ShrS) return try visitor.visitI32ShrS() } - public mutating func visitI32ShrU() throws -> V.Output { + public mutating func visitI32ShrU() throws { trace(.i32ShrU) return try visitor.visitI32ShrU() } - public mutating func visitI32Rotl() throws -> V.Output { + public mutating func visitI32Rotl() throws { trace(.i32Rotl) return try visitor.visitI32Rotl() } - public mutating func visitI32Rotr() throws -> V.Output { + public mutating func visitI32Rotr() throws { trace(.i32Rotr) return try visitor.visitI32Rotr() } - public mutating func visitI64Clz() throws -> V.Output { + public mutating func visitI64Clz() throws { trace(.i64Clz) return try visitor.visitI64Clz() } - public mutating func visitI64Ctz() throws -> V.Output { + public mutating func visitI64Ctz() throws { trace(.i64Ctz) return try visitor.visitI64Ctz() } - public mutating func visitI64Popcnt() throws -> V.Output { + public mutating func visitI64Popcnt() throws { trace(.i64Popcnt) return try visitor.visitI64Popcnt() } - public mutating func visitI64Add() throws -> V.Output { + public mutating func visitI64Add() throws { trace(.i64Add) return try visitor.visitI64Add() } - public mutating func visitI64Sub() throws -> V.Output { + public mutating func visitI64Sub() throws { trace(.i64Sub) return try visitor.visitI64Sub() } - public mutating func visitI64Mul() throws -> V.Output { + public mutating func visitI64Mul() throws { trace(.i64Mul) return try visitor.visitI64Mul() } - public mutating func visitI64DivS() throws -> V.Output { + public mutating func visitI64DivS() throws { trace(.i64DivS) return try visitor.visitI64DivS() } - public mutating func visitI64DivU() throws -> V.Output { + public mutating func visitI64DivU() throws { trace(.i64DivU) return try visitor.visitI64DivU() } - public mutating func visitI64RemS() throws -> V.Output { + public mutating func visitI64RemS() throws { trace(.i64RemS) return try visitor.visitI64RemS() } - public mutating func visitI64RemU() throws -> V.Output { + public mutating func visitI64RemU() throws { trace(.i64RemU) return try visitor.visitI64RemU() } - public mutating func visitI64And() throws -> V.Output { + public mutating func visitI64And() throws { trace(.i64And) return try visitor.visitI64And() } - public mutating func visitI64Or() throws -> V.Output { + public mutating func visitI64Or() throws { trace(.i64Or) return try visitor.visitI64Or() } - public mutating func visitI64Xor() throws -> V.Output { + public mutating func visitI64Xor() throws { trace(.i64Xor) return try visitor.visitI64Xor() } - public mutating func visitI64Shl() throws -> V.Output { + public mutating func visitI64Shl() throws { trace(.i64Shl) return try visitor.visitI64Shl() } - public mutating func visitI64ShrS() throws -> V.Output { + public mutating func visitI64ShrS() throws { trace(.i64ShrS) return try visitor.visitI64ShrS() } - public mutating func visitI64ShrU() throws -> V.Output { + public mutating func visitI64ShrU() throws { trace(.i64ShrU) return try visitor.visitI64ShrU() } - public mutating func visitI64Rotl() throws -> V.Output { + public mutating func visitI64Rotl() throws { trace(.i64Rotl) return try visitor.visitI64Rotl() } - public mutating func visitI64Rotr() throws -> V.Output { + public mutating func visitI64Rotr() throws { trace(.i64Rotr) return try visitor.visitI64Rotr() } - public mutating func visitF32Abs() throws -> V.Output { + public mutating func visitF32Abs() throws { trace(.f32Abs) return try visitor.visitF32Abs() } - public mutating func visitF32Neg() throws -> V.Output { + public mutating func visitF32Neg() throws { trace(.f32Neg) return try visitor.visitF32Neg() } - public mutating func visitF32Ceil() throws -> V.Output { + public mutating func visitF32Ceil() throws { trace(.f32Ceil) return try visitor.visitF32Ceil() } - public mutating func visitF32Floor() throws -> V.Output { + public mutating func visitF32Floor() throws { trace(.f32Floor) return try visitor.visitF32Floor() } - public mutating func visitF32Trunc() throws -> V.Output { + public mutating func visitF32Trunc() throws { trace(.f32Trunc) return try visitor.visitF32Trunc() } - public mutating func visitF32Nearest() throws -> V.Output { + public mutating func visitF32Nearest() throws { trace(.f32Nearest) return try visitor.visitF32Nearest() } - public mutating func visitF32Sqrt() throws -> V.Output { + public mutating func visitF32Sqrt() throws { trace(.f32Sqrt) return try visitor.visitF32Sqrt() } - public mutating func visitF32Add() throws -> V.Output { + public mutating func visitF32Add() throws { trace(.f32Add) return try visitor.visitF32Add() } - public mutating func visitF32Sub() throws -> V.Output { + public mutating func visitF32Sub() throws { trace(.f32Sub) return try visitor.visitF32Sub() } - public mutating func visitF32Mul() throws -> V.Output { + public mutating func visitF32Mul() throws { trace(.f32Mul) return try visitor.visitF32Mul() } - public mutating func visitF32Div() throws -> V.Output { + public mutating func visitF32Div() throws { trace(.f32Div) return try visitor.visitF32Div() } - public mutating func visitF32Min() throws -> V.Output { + public mutating func visitF32Min() throws { trace(.f32Min) return try visitor.visitF32Min() } - public mutating func visitF32Max() throws -> V.Output { + public mutating func visitF32Max() throws { trace(.f32Max) return try visitor.visitF32Max() } - public mutating func visitF32Copysign() throws -> V.Output { + public mutating func visitF32Copysign() throws { trace(.f32Copysign) return try visitor.visitF32Copysign() } - public mutating func visitF64Abs() throws -> V.Output { + public mutating func visitF64Abs() throws { trace(.f64Abs) return try visitor.visitF64Abs() } - public mutating func visitF64Neg() throws -> V.Output { + public mutating func visitF64Neg() throws { trace(.f64Neg) return try visitor.visitF64Neg() } - public mutating func visitF64Ceil() throws -> V.Output { + public mutating func visitF64Ceil() throws { trace(.f64Ceil) return try visitor.visitF64Ceil() } - public mutating func visitF64Floor() throws -> V.Output { + public mutating func visitF64Floor() throws { trace(.f64Floor) return try visitor.visitF64Floor() } - public mutating func visitF64Trunc() throws -> V.Output { + public mutating func visitF64Trunc() throws { trace(.f64Trunc) return try visitor.visitF64Trunc() } - public mutating func visitF64Nearest() throws -> V.Output { + public mutating func visitF64Nearest() throws { trace(.f64Nearest) return try visitor.visitF64Nearest() } - public mutating func visitF64Sqrt() throws -> V.Output { + public mutating func visitF64Sqrt() throws { trace(.f64Sqrt) return try visitor.visitF64Sqrt() } - public mutating func visitF64Add() throws -> V.Output { + public mutating func visitF64Add() throws { trace(.f64Add) return try visitor.visitF64Add() } - public mutating func visitF64Sub() throws -> V.Output { + public mutating func visitF64Sub() throws { trace(.f64Sub) return try visitor.visitF64Sub() } - public mutating func visitF64Mul() throws -> V.Output { + public mutating func visitF64Mul() throws { trace(.f64Mul) return try visitor.visitF64Mul() } - public mutating func visitF64Div() throws -> V.Output { + public mutating func visitF64Div() throws { trace(.f64Div) return try visitor.visitF64Div() } - public mutating func visitF64Min() throws -> V.Output { + public mutating func visitF64Min() throws { trace(.f64Min) return try visitor.visitF64Min() } - public mutating func visitF64Max() throws -> V.Output { + public mutating func visitF64Max() throws { trace(.f64Max) return try visitor.visitF64Max() } - public mutating func visitF64Copysign() throws -> V.Output { + public mutating func visitF64Copysign() throws { trace(.f64Copysign) return try visitor.visitF64Copysign() } - public mutating func visitI32WrapI64() throws -> V.Output { + public mutating func visitI32WrapI64() throws { trace(.i32WrapI64) return try visitor.visitI32WrapI64() } - public mutating func visitI32TruncF32S() throws -> V.Output { + public mutating func visitI32TruncF32S() throws { trace(.i32TruncF32S) return try visitor.visitI32TruncF32S() } - public mutating func visitI32TruncF32U() throws -> V.Output { + public mutating func visitI32TruncF32U() throws { trace(.i32TruncF32U) return try visitor.visitI32TruncF32U() } - public mutating func visitI32TruncF64S() throws -> V.Output { + public mutating func visitI32TruncF64S() throws { trace(.i32TruncF64S) return try visitor.visitI32TruncF64S() } - public mutating func visitI32TruncF64U() throws -> V.Output { + public mutating func visitI32TruncF64U() throws { trace(.i32TruncF64U) return try visitor.visitI32TruncF64U() } - public mutating func visitI64ExtendI32S() throws -> V.Output { + public mutating func visitI64ExtendI32S() throws { trace(.i64ExtendI32S) return try visitor.visitI64ExtendI32S() } - public mutating func visitI64ExtendI32U() throws -> V.Output { + public mutating func visitI64ExtendI32U() throws { trace(.i64ExtendI32U) return try visitor.visitI64ExtendI32U() } - public mutating func visitI64TruncF32S() throws -> V.Output { + public mutating func visitI64TruncF32S() throws { trace(.i64TruncF32S) return try visitor.visitI64TruncF32S() } - public mutating func visitI64TruncF32U() throws -> V.Output { + public mutating func visitI64TruncF32U() throws { trace(.i64TruncF32U) return try visitor.visitI64TruncF32U() } - public mutating func visitI64TruncF64S() throws -> V.Output { + public mutating func visitI64TruncF64S() throws { trace(.i64TruncF64S) return try visitor.visitI64TruncF64S() } - public mutating func visitI64TruncF64U() throws -> V.Output { + public mutating func visitI64TruncF64U() throws { trace(.i64TruncF64U) return try visitor.visitI64TruncF64U() } - public mutating func visitF32ConvertI32S() throws -> V.Output { + public mutating func visitF32ConvertI32S() throws { trace(.f32ConvertI32S) return try visitor.visitF32ConvertI32S() } - public mutating func visitF32ConvertI32U() throws -> V.Output { + public mutating func visitF32ConvertI32U() throws { trace(.f32ConvertI32U) return try visitor.visitF32ConvertI32U() } - public mutating func visitF32ConvertI64S() throws -> V.Output { + public mutating func visitF32ConvertI64S() throws { trace(.f32ConvertI64S) return try visitor.visitF32ConvertI64S() } - public mutating func visitF32ConvertI64U() throws -> V.Output { + public mutating func visitF32ConvertI64U() throws { trace(.f32ConvertI64U) return try visitor.visitF32ConvertI64U() } - public mutating func visitF32DemoteF64() throws -> V.Output { + public mutating func visitF32DemoteF64() throws { trace(.f32DemoteF64) return try visitor.visitF32DemoteF64() } - public mutating func visitF64ConvertI32S() throws -> V.Output { + public mutating func visitF64ConvertI32S() throws { trace(.f64ConvertI32S) return try visitor.visitF64ConvertI32S() } - public mutating func visitF64ConvertI32U() throws -> V.Output { + public mutating func visitF64ConvertI32U() throws { trace(.f64ConvertI32U) return try visitor.visitF64ConvertI32U() } - public mutating func visitF64ConvertI64S() throws -> V.Output { + public mutating func visitF64ConvertI64S() throws { trace(.f64ConvertI64S) return try visitor.visitF64ConvertI64S() } - public mutating func visitF64ConvertI64U() throws -> V.Output { + public mutating func visitF64ConvertI64U() throws { trace(.f64ConvertI64U) return try visitor.visitF64ConvertI64U() } - public mutating func visitF64PromoteF32() throws -> V.Output { + public mutating func visitF64PromoteF32() throws { trace(.f64PromoteF32) return try visitor.visitF64PromoteF32() } - public mutating func visitI32ReinterpretF32() throws -> V.Output { + public mutating func visitI32ReinterpretF32() throws { trace(.i32ReinterpretF32) return try visitor.visitI32ReinterpretF32() } - public mutating func visitI64ReinterpretF64() throws -> V.Output { + public mutating func visitI64ReinterpretF64() throws { trace(.i64ReinterpretF64) return try visitor.visitI64ReinterpretF64() } - public mutating func visitF32ReinterpretI32() throws -> V.Output { + public mutating func visitF32ReinterpretI32() throws { trace(.f32ReinterpretI32) return try visitor.visitF32ReinterpretI32() } - public mutating func visitF64ReinterpretI64() throws -> V.Output { + public mutating func visitF64ReinterpretI64() throws { trace(.f64ReinterpretI64) return try visitor.visitF64ReinterpretI64() } - public mutating func visitI32Extend8S() throws -> V.Output { + public mutating func visitI32Extend8S() throws { trace(.i32Extend8S) return try visitor.visitI32Extend8S() } - public mutating func visitI32Extend16S() throws -> V.Output { + public mutating func visitI32Extend16S() throws { trace(.i32Extend16S) return try visitor.visitI32Extend16S() } - public mutating func visitI64Extend8S() throws -> V.Output { + public mutating func visitI64Extend8S() throws { trace(.i64Extend8S) return try visitor.visitI64Extend8S() } - public mutating func visitI64Extend16S() throws -> V.Output { + public mutating func visitI64Extend16S() throws { trace(.i64Extend16S) return try visitor.visitI64Extend16S() } - public mutating func visitI64Extend32S() throws -> V.Output { + public mutating func visitI64Extend32S() throws { trace(.i64Extend32S) return try visitor.visitI64Extend32S() } - public mutating func visitMemoryInit(dataIndex: UInt32) throws -> V.Output { + public mutating func visitMemoryInit(dataIndex: UInt32) throws { trace(.memoryInit(dataIndex: dataIndex)) return try visitor.visitMemoryInit(dataIndex: dataIndex) } - public mutating func visitDataDrop(dataIndex: UInt32) throws -> V.Output { + public mutating func visitDataDrop(dataIndex: UInt32) throws { trace(.dataDrop(dataIndex: dataIndex)) return try visitor.visitDataDrop(dataIndex: dataIndex) } - public mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws -> V.Output { + public mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws { trace(.memoryCopy(dstMem: dstMem, srcMem: srcMem)) return try visitor.visitMemoryCopy(dstMem: dstMem, srcMem: srcMem) } - public mutating func visitMemoryFill(memory: UInt32) throws -> V.Output { + public mutating func visitMemoryFill(memory: UInt32) throws { trace(.memoryFill(memory: memory)) return try visitor.visitMemoryFill(memory: memory) } - public mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws -> V.Output { + public mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws { trace(.tableInit(elemIndex: elemIndex, table: table)) return try visitor.visitTableInit(elemIndex: elemIndex, table: table) } - public mutating func visitElemDrop(elemIndex: UInt32) throws -> V.Output { + public mutating func visitElemDrop(elemIndex: UInt32) throws { trace(.elemDrop(elemIndex: elemIndex)) return try visitor.visitElemDrop(elemIndex: elemIndex) } - public mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws -> V.Output { + public mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws { trace(.tableCopy(dstTable: dstTable, srcTable: srcTable)) return try visitor.visitTableCopy(dstTable: dstTable, srcTable: srcTable) } - public mutating func visitTableFill(table: UInt32) throws -> V.Output { + public mutating func visitTableFill(table: UInt32) throws { trace(.tableFill(table: table)) return try visitor.visitTableFill(table: table) } - public mutating func visitTableGet(table: UInt32) throws -> V.Output { + public mutating func visitTableGet(table: UInt32) throws { trace(.tableGet(table: table)) return try visitor.visitTableGet(table: table) } - public mutating func visitTableSet(table: UInt32) throws -> V.Output { + public mutating func visitTableSet(table: UInt32) throws { trace(.tableSet(table: table)) return try visitor.visitTableSet(table: table) } - public mutating func visitTableGrow(table: UInt32) throws -> V.Output { + public mutating func visitTableGrow(table: UInt32) throws { trace(.tableGrow(table: table)) return try visitor.visitTableGrow(table: table) } - public mutating func visitTableSize(table: UInt32) throws -> V.Output { + public mutating func visitTableSize(table: UInt32) throws { trace(.tableSize(table: table)) return try visitor.visitTableSize(table: table) } - public mutating func visitI32TruncSatF32S() throws -> V.Output { + public mutating func visitI32TruncSatF32S() throws { trace(.i32TruncSatF32S) return try visitor.visitI32TruncSatF32S() } - public mutating func visitI32TruncSatF32U() throws -> V.Output { + public mutating func visitI32TruncSatF32U() throws { trace(.i32TruncSatF32U) return try visitor.visitI32TruncSatF32U() } - public mutating func visitI32TruncSatF64S() throws -> V.Output { + public mutating func visitI32TruncSatF64S() throws { trace(.i32TruncSatF64S) return try visitor.visitI32TruncSatF64S() } - public mutating func visitI32TruncSatF64U() throws -> V.Output { + public mutating func visitI32TruncSatF64U() throws { trace(.i32TruncSatF64U) return try visitor.visitI32TruncSatF64U() } - public mutating func visitI64TruncSatF32S() throws -> V.Output { + public mutating func visitI64TruncSatF32S() throws { trace(.i64TruncSatF32S) return try visitor.visitI64TruncSatF32S() } - public mutating func visitI64TruncSatF32U() throws -> V.Output { + public mutating func visitI64TruncSatF32U() throws { trace(.i64TruncSatF32U) return try visitor.visitI64TruncSatF32U() } - public mutating func visitI64TruncSatF64S() throws -> V.Output { + public mutating func visitI64TruncSatF64S() throws { trace(.i64TruncSatF64S) return try visitor.visitI64TruncSatF64S() } - public mutating func visitI64TruncSatF64U() throws -> V.Output { + public mutating func visitI64TruncSatF64U() throws { trace(.i64TruncSatF64U) return try visitor.visitI64TruncSatF64U() } @@ -1245,416 +1245,413 @@ public struct InstructionTracingVisitor: InstructionVisit /// The visitor pattern is used while parsing WebAssembly expressions to allow for easy extensibility. /// See the expression parsing method ``Code/parseExpression(visitor:)`` public protocol InstructionVisitor { - - /// The return type of visitor methods. - associatedtype Output /// Visiting `unreachable` instruction. - mutating func visitUnreachable() throws -> Output + mutating func visitUnreachable() throws /// Visiting `nop` instruction. - mutating func visitNop() throws -> Output + mutating func visitNop() throws /// Visiting `block` instruction. - mutating func visitBlock(blockType: BlockType) throws -> Output + mutating func visitBlock(blockType: BlockType) throws /// Visiting `loop` instruction. - mutating func visitLoop(blockType: BlockType) throws -> Output + mutating func visitLoop(blockType: BlockType) throws /// Visiting `if` instruction. - mutating func visitIf(blockType: BlockType) throws -> Output + mutating func visitIf(blockType: BlockType) throws /// Visiting `else` instruction. - mutating func visitElse() throws -> Output + mutating func visitElse() throws /// Visiting `end` instruction. - mutating func visitEnd() throws -> Output + mutating func visitEnd() throws /// Visiting `br` instruction. - mutating func visitBr(relativeDepth: UInt32) throws -> Output + mutating func visitBr(relativeDepth: UInt32) throws /// Visiting `br_if` instruction. - mutating func visitBrIf(relativeDepth: UInt32) throws -> Output + mutating func visitBrIf(relativeDepth: UInt32) throws /// Visiting `br_table` instruction. - mutating func visitBrTable(targets: BrTable) throws -> Output + mutating func visitBrTable(targets: BrTable) throws /// Visiting `return` instruction. - mutating func visitReturn() throws -> Output + mutating func visitReturn() throws /// Visiting `call` instruction. - mutating func visitCall(functionIndex: UInt32) throws -> Output + mutating func visitCall(functionIndex: UInt32) throws /// Visiting `call_indirect` instruction. - mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws -> Output + mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws /// Visiting `drop` instruction. - mutating func visitDrop() throws -> Output + mutating func visitDrop() throws /// Visiting `select` instruction. - mutating func visitSelect() throws -> Output + mutating func visitSelect() throws /// Visiting `typedSelect` instruction. - mutating func visitTypedSelect(type: ValueType) throws -> Output + mutating func visitTypedSelect(type: ValueType) throws /// Visiting `local.get` instruction. - mutating func visitLocalGet(localIndex: UInt32) throws -> Output + mutating func visitLocalGet(localIndex: UInt32) throws /// Visiting `local.set` instruction. - mutating func visitLocalSet(localIndex: UInt32) throws -> Output + mutating func visitLocalSet(localIndex: UInt32) throws /// Visiting `local.tee` instruction. - mutating func visitLocalTee(localIndex: UInt32) throws -> Output + mutating func visitLocalTee(localIndex: UInt32) throws /// Visiting `global.get` instruction. - mutating func visitGlobalGet(globalIndex: UInt32) throws -> Output + mutating func visitGlobalGet(globalIndex: UInt32) throws /// Visiting `global.set` instruction. - mutating func visitGlobalSet(globalIndex: UInt32) throws -> Output + mutating func visitGlobalSet(globalIndex: UInt32) throws /// Visiting `i32.load` instruction. - mutating func visitI32Load(memarg: MemArg) throws -> Output + mutating func visitI32Load(memarg: MemArg) throws /// Visiting `i64.load` instruction. - mutating func visitI64Load(memarg: MemArg) throws -> Output + mutating func visitI64Load(memarg: MemArg) throws /// Visiting `f32.load` instruction. - mutating func visitF32Load(memarg: MemArg) throws -> Output + mutating func visitF32Load(memarg: MemArg) throws /// Visiting `f64.load` instruction. - mutating func visitF64Load(memarg: MemArg) throws -> Output + mutating func visitF64Load(memarg: MemArg) throws /// Visiting `i32.load8_s` instruction. - mutating func visitI32Load8S(memarg: MemArg) throws -> Output + mutating func visitI32Load8S(memarg: MemArg) throws /// Visiting `i32.load8_u` instruction. - mutating func visitI32Load8U(memarg: MemArg) throws -> Output + mutating func visitI32Load8U(memarg: MemArg) throws /// Visiting `i32.load16_s` instruction. - mutating func visitI32Load16S(memarg: MemArg) throws -> Output + mutating func visitI32Load16S(memarg: MemArg) throws /// Visiting `i32.load16_u` instruction. - mutating func visitI32Load16U(memarg: MemArg) throws -> Output + mutating func visitI32Load16U(memarg: MemArg) throws /// Visiting `i64.load8_s` instruction. - mutating func visitI64Load8S(memarg: MemArg) throws -> Output + mutating func visitI64Load8S(memarg: MemArg) throws /// Visiting `i64.load8_u` instruction. - mutating func visitI64Load8U(memarg: MemArg) throws -> Output + mutating func visitI64Load8U(memarg: MemArg) throws /// Visiting `i64.load16_s` instruction. - mutating func visitI64Load16S(memarg: MemArg) throws -> Output + mutating func visitI64Load16S(memarg: MemArg) throws /// Visiting `i64.load16_u` instruction. - mutating func visitI64Load16U(memarg: MemArg) throws -> Output + mutating func visitI64Load16U(memarg: MemArg) throws /// Visiting `i64.load32_s` instruction. - mutating func visitI64Load32S(memarg: MemArg) throws -> Output + mutating func visitI64Load32S(memarg: MemArg) throws /// Visiting `i64.load32_u` instruction. - mutating func visitI64Load32U(memarg: MemArg) throws -> Output + mutating func visitI64Load32U(memarg: MemArg) throws /// Visiting `i32.store` instruction. - mutating func visitI32Store(memarg: MemArg) throws -> Output + mutating func visitI32Store(memarg: MemArg) throws /// Visiting `i64.store` instruction. - mutating func visitI64Store(memarg: MemArg) throws -> Output + mutating func visitI64Store(memarg: MemArg) throws /// Visiting `f32.store` instruction. - mutating func visitF32Store(memarg: MemArg) throws -> Output + mutating func visitF32Store(memarg: MemArg) throws /// Visiting `f64.store` instruction. - mutating func visitF64Store(memarg: MemArg) throws -> Output + mutating func visitF64Store(memarg: MemArg) throws /// Visiting `i32.store8` instruction. - mutating func visitI32Store8(memarg: MemArg) throws -> Output + mutating func visitI32Store8(memarg: MemArg) throws /// Visiting `i32.store16` instruction. - mutating func visitI32Store16(memarg: MemArg) throws -> Output + mutating func visitI32Store16(memarg: MemArg) throws /// Visiting `i64.store8` instruction. - mutating func visitI64Store8(memarg: MemArg) throws -> Output + mutating func visitI64Store8(memarg: MemArg) throws /// Visiting `i64.store16` instruction. - mutating func visitI64Store16(memarg: MemArg) throws -> Output + mutating func visitI64Store16(memarg: MemArg) throws /// Visiting `i64.store32` instruction. - mutating func visitI64Store32(memarg: MemArg) throws -> Output + mutating func visitI64Store32(memarg: MemArg) throws /// Visiting `memory.size` instruction. - mutating func visitMemorySize(memory: UInt32) throws -> Output + mutating func visitMemorySize(memory: UInt32) throws /// Visiting `memory.grow` instruction. - mutating func visitMemoryGrow(memory: UInt32) throws -> Output + mutating func visitMemoryGrow(memory: UInt32) throws /// Visiting `i32.const` instruction. - mutating func visitI32Const(value: Int32) throws -> Output + mutating func visitI32Const(value: Int32) throws /// Visiting `i64.const` instruction. - mutating func visitI64Const(value: Int64) throws -> Output + mutating func visitI64Const(value: Int64) throws /// Visiting `f32.const` instruction. - mutating func visitF32Const(value: IEEE754.Float32) throws -> Output + mutating func visitF32Const(value: IEEE754.Float32) throws /// Visiting `f64.const` instruction. - mutating func visitF64Const(value: IEEE754.Float64) throws -> Output + mutating func visitF64Const(value: IEEE754.Float64) throws /// Visiting `ref.null` instruction. - mutating func visitRefNull(type: ReferenceType) throws -> Output + mutating func visitRefNull(type: ReferenceType) throws /// Visiting `ref.is_null` instruction. - mutating func visitRefIsNull() throws -> Output + mutating func visitRefIsNull() throws /// Visiting `ref.func` instruction. - mutating func visitRefFunc(functionIndex: UInt32) throws -> Output + mutating func visitRefFunc(functionIndex: UInt32) throws /// Visiting `i32.eqz` instruction. - mutating func visitI32Eqz() throws -> Output + mutating func visitI32Eqz() throws /// Visiting `i32.eq` instruction. - mutating func visitI32Eq() throws -> Output + mutating func visitI32Eq() throws /// Visiting `i32.ne` instruction. - mutating func visitI32Ne() throws -> Output + mutating func visitI32Ne() throws /// Visiting `i32.lt_s` instruction. - mutating func visitI32LtS() throws -> Output + mutating func visitI32LtS() throws /// Visiting `i32.lt_u` instruction. - mutating func visitI32LtU() throws -> Output + mutating func visitI32LtU() throws /// Visiting `i32.gt_s` instruction. - mutating func visitI32GtS() throws -> Output + mutating func visitI32GtS() throws /// Visiting `i32.gt_u` instruction. - mutating func visitI32GtU() throws -> Output + mutating func visitI32GtU() throws /// Visiting `i32.le_s` instruction. - mutating func visitI32LeS() throws -> Output + mutating func visitI32LeS() throws /// Visiting `i32.le_u` instruction. - mutating func visitI32LeU() throws -> Output + mutating func visitI32LeU() throws /// Visiting `i32.ge_s` instruction. - mutating func visitI32GeS() throws -> Output + mutating func visitI32GeS() throws /// Visiting `i32.ge_u` instruction. - mutating func visitI32GeU() throws -> Output + mutating func visitI32GeU() throws /// Visiting `i64.eqz` instruction. - mutating func visitI64Eqz() throws -> Output + mutating func visitI64Eqz() throws /// Visiting `i64.eq` instruction. - mutating func visitI64Eq() throws -> Output + mutating func visitI64Eq() throws /// Visiting `i64.ne` instruction. - mutating func visitI64Ne() throws -> Output + mutating func visitI64Ne() throws /// Visiting `i64.lt_s` instruction. - mutating func visitI64LtS() throws -> Output + mutating func visitI64LtS() throws /// Visiting `i64.lt_u` instruction. - mutating func visitI64LtU() throws -> Output + mutating func visitI64LtU() throws /// Visiting `i64.gt_s` instruction. - mutating func visitI64GtS() throws -> Output + mutating func visitI64GtS() throws /// Visiting `i64.gt_u` instruction. - mutating func visitI64GtU() throws -> Output + mutating func visitI64GtU() throws /// Visiting `i64.le_s` instruction. - mutating func visitI64LeS() throws -> Output + mutating func visitI64LeS() throws /// Visiting `i64.le_u` instruction. - mutating func visitI64LeU() throws -> Output + mutating func visitI64LeU() throws /// Visiting `i64.ge_s` instruction. - mutating func visitI64GeS() throws -> Output + mutating func visitI64GeS() throws /// Visiting `i64.ge_u` instruction. - mutating func visitI64GeU() throws -> Output + mutating func visitI64GeU() throws /// Visiting `f32.eq` instruction. - mutating func visitF32Eq() throws -> Output + mutating func visitF32Eq() throws /// Visiting `f32.ne` instruction. - mutating func visitF32Ne() throws -> Output + mutating func visitF32Ne() throws /// Visiting `f32.lt` instruction. - mutating func visitF32Lt() throws -> Output + mutating func visitF32Lt() throws /// Visiting `f32.gt` instruction. - mutating func visitF32Gt() throws -> Output + mutating func visitF32Gt() throws /// Visiting `f32.le` instruction. - mutating func visitF32Le() throws -> Output + mutating func visitF32Le() throws /// Visiting `f32.ge` instruction. - mutating func visitF32Ge() throws -> Output + mutating func visitF32Ge() throws /// Visiting `f64.eq` instruction. - mutating func visitF64Eq() throws -> Output + mutating func visitF64Eq() throws /// Visiting `f64.ne` instruction. - mutating func visitF64Ne() throws -> Output + mutating func visitF64Ne() throws /// Visiting `f64.lt` instruction. - mutating func visitF64Lt() throws -> Output + mutating func visitF64Lt() throws /// Visiting `f64.gt` instruction. - mutating func visitF64Gt() throws -> Output + mutating func visitF64Gt() throws /// Visiting `f64.le` instruction. - mutating func visitF64Le() throws -> Output + mutating func visitF64Le() throws /// Visiting `f64.ge` instruction. - mutating func visitF64Ge() throws -> Output + mutating func visitF64Ge() throws /// Visiting `i32.clz` instruction. - mutating func visitI32Clz() throws -> Output + mutating func visitI32Clz() throws /// Visiting `i32.ctz` instruction. - mutating func visitI32Ctz() throws -> Output + mutating func visitI32Ctz() throws /// Visiting `i32.popcnt` instruction. - mutating func visitI32Popcnt() throws -> Output + mutating func visitI32Popcnt() throws /// Visiting `i32.add` instruction. - mutating func visitI32Add() throws -> Output + mutating func visitI32Add() throws /// Visiting `i32.sub` instruction. - mutating func visitI32Sub() throws -> Output + mutating func visitI32Sub() throws /// Visiting `i32.mul` instruction. - mutating func visitI32Mul() throws -> Output + mutating func visitI32Mul() throws /// Visiting `i32.div_s` instruction. - mutating func visitI32DivS() throws -> Output + mutating func visitI32DivS() throws /// Visiting `i32.div_u` instruction. - mutating func visitI32DivU() throws -> Output + mutating func visitI32DivU() throws /// Visiting `i32.rem_s` instruction. - mutating func visitI32RemS() throws -> Output + mutating func visitI32RemS() throws /// Visiting `i32.rem_u` instruction. - mutating func visitI32RemU() throws -> Output + mutating func visitI32RemU() throws /// Visiting `i32.and` instruction. - mutating func visitI32And() throws -> Output + mutating func visitI32And() throws /// Visiting `i32.or` instruction. - mutating func visitI32Or() throws -> Output + mutating func visitI32Or() throws /// Visiting `i32.xor` instruction. - mutating func visitI32Xor() throws -> Output + mutating func visitI32Xor() throws /// Visiting `i32.shl` instruction. - mutating func visitI32Shl() throws -> Output + mutating func visitI32Shl() throws /// Visiting `i32.shr_s` instruction. - mutating func visitI32ShrS() throws -> Output + mutating func visitI32ShrS() throws /// Visiting `i32.shr_u` instruction. - mutating func visitI32ShrU() throws -> Output + mutating func visitI32ShrU() throws /// Visiting `i32.rotl` instruction. - mutating func visitI32Rotl() throws -> Output + mutating func visitI32Rotl() throws /// Visiting `i32.rotr` instruction. - mutating func visitI32Rotr() throws -> Output + mutating func visitI32Rotr() throws /// Visiting `i64.clz` instruction. - mutating func visitI64Clz() throws -> Output + mutating func visitI64Clz() throws /// Visiting `i64.ctz` instruction. - mutating func visitI64Ctz() throws -> Output + mutating func visitI64Ctz() throws /// Visiting `i64.popcnt` instruction. - mutating func visitI64Popcnt() throws -> Output + mutating func visitI64Popcnt() throws /// Visiting `i64.add` instruction. - mutating func visitI64Add() throws -> Output + mutating func visitI64Add() throws /// Visiting `i64.sub` instruction. - mutating func visitI64Sub() throws -> Output + mutating func visitI64Sub() throws /// Visiting `i64.mul` instruction. - mutating func visitI64Mul() throws -> Output + mutating func visitI64Mul() throws /// Visiting `i64.div_s` instruction. - mutating func visitI64DivS() throws -> Output + mutating func visitI64DivS() throws /// Visiting `i64.div_u` instruction. - mutating func visitI64DivU() throws -> Output + mutating func visitI64DivU() throws /// Visiting `i64.rem_s` instruction. - mutating func visitI64RemS() throws -> Output + mutating func visitI64RemS() throws /// Visiting `i64.rem_u` instruction. - mutating func visitI64RemU() throws -> Output + mutating func visitI64RemU() throws /// Visiting `i64.and` instruction. - mutating func visitI64And() throws -> Output + mutating func visitI64And() throws /// Visiting `i64.or` instruction. - mutating func visitI64Or() throws -> Output + mutating func visitI64Or() throws /// Visiting `i64.xor` instruction. - mutating func visitI64Xor() throws -> Output + mutating func visitI64Xor() throws /// Visiting `i64.shl` instruction. - mutating func visitI64Shl() throws -> Output + mutating func visitI64Shl() throws /// Visiting `i64.shr_s` instruction. - mutating func visitI64ShrS() throws -> Output + mutating func visitI64ShrS() throws /// Visiting `i64.shr_u` instruction. - mutating func visitI64ShrU() throws -> Output + mutating func visitI64ShrU() throws /// Visiting `i64.rotl` instruction. - mutating func visitI64Rotl() throws -> Output + mutating func visitI64Rotl() throws /// Visiting `i64.rotr` instruction. - mutating func visitI64Rotr() throws -> Output + mutating func visitI64Rotr() throws /// Visiting `f32.abs` instruction. - mutating func visitF32Abs() throws -> Output + mutating func visitF32Abs() throws /// Visiting `f32.neg` instruction. - mutating func visitF32Neg() throws -> Output + mutating func visitF32Neg() throws /// Visiting `f32.ceil` instruction. - mutating func visitF32Ceil() throws -> Output + mutating func visitF32Ceil() throws /// Visiting `f32.floor` instruction. - mutating func visitF32Floor() throws -> Output + mutating func visitF32Floor() throws /// Visiting `f32.trunc` instruction. - mutating func visitF32Trunc() throws -> Output + mutating func visitF32Trunc() throws /// Visiting `f32.nearest` instruction. - mutating func visitF32Nearest() throws -> Output + mutating func visitF32Nearest() throws /// Visiting `f32.sqrt` instruction. - mutating func visitF32Sqrt() throws -> Output + mutating func visitF32Sqrt() throws /// Visiting `f32.add` instruction. - mutating func visitF32Add() throws -> Output + mutating func visitF32Add() throws /// Visiting `f32.sub` instruction. - mutating func visitF32Sub() throws -> Output + mutating func visitF32Sub() throws /// Visiting `f32.mul` instruction. - mutating func visitF32Mul() throws -> Output + mutating func visitF32Mul() throws /// Visiting `f32.div` instruction. - mutating func visitF32Div() throws -> Output + mutating func visitF32Div() throws /// Visiting `f32.min` instruction. - mutating func visitF32Min() throws -> Output + mutating func visitF32Min() throws /// Visiting `f32.max` instruction. - mutating func visitF32Max() throws -> Output + mutating func visitF32Max() throws /// Visiting `f32.copysign` instruction. - mutating func visitF32Copysign() throws -> Output + mutating func visitF32Copysign() throws /// Visiting `f64.abs` instruction. - mutating func visitF64Abs() throws -> Output + mutating func visitF64Abs() throws /// Visiting `f64.neg` instruction. - mutating func visitF64Neg() throws -> Output + mutating func visitF64Neg() throws /// Visiting `f64.ceil` instruction. - mutating func visitF64Ceil() throws -> Output + mutating func visitF64Ceil() throws /// Visiting `f64.floor` instruction. - mutating func visitF64Floor() throws -> Output + mutating func visitF64Floor() throws /// Visiting `f64.trunc` instruction. - mutating func visitF64Trunc() throws -> Output + mutating func visitF64Trunc() throws /// Visiting `f64.nearest` instruction. - mutating func visitF64Nearest() throws -> Output + mutating func visitF64Nearest() throws /// Visiting `f64.sqrt` instruction. - mutating func visitF64Sqrt() throws -> Output + mutating func visitF64Sqrt() throws /// Visiting `f64.add` instruction. - mutating func visitF64Add() throws -> Output + mutating func visitF64Add() throws /// Visiting `f64.sub` instruction. - mutating func visitF64Sub() throws -> Output + mutating func visitF64Sub() throws /// Visiting `f64.mul` instruction. - mutating func visitF64Mul() throws -> Output + mutating func visitF64Mul() throws /// Visiting `f64.div` instruction. - mutating func visitF64Div() throws -> Output + mutating func visitF64Div() throws /// Visiting `f64.min` instruction. - mutating func visitF64Min() throws -> Output + mutating func visitF64Min() throws /// Visiting `f64.max` instruction. - mutating func visitF64Max() throws -> Output + mutating func visitF64Max() throws /// Visiting `f64.copysign` instruction. - mutating func visitF64Copysign() throws -> Output + mutating func visitF64Copysign() throws /// Visiting `i32.wrap_i64` instruction. - mutating func visitI32WrapI64() throws -> Output + mutating func visitI32WrapI64() throws /// Visiting `i32.trunc_f32_s` instruction. - mutating func visitI32TruncF32S() throws -> Output + mutating func visitI32TruncF32S() throws /// Visiting `i32.trunc_f32_u` instruction. - mutating func visitI32TruncF32U() throws -> Output + mutating func visitI32TruncF32U() throws /// Visiting `i32.trunc_f64_s` instruction. - mutating func visitI32TruncF64S() throws -> Output + mutating func visitI32TruncF64S() throws /// Visiting `i32.trunc_f64_u` instruction. - mutating func visitI32TruncF64U() throws -> Output + mutating func visitI32TruncF64U() throws /// Visiting `i64.extend_i32_s` instruction. - mutating func visitI64ExtendI32S() throws -> Output + mutating func visitI64ExtendI32S() throws /// Visiting `i64.extend_i32_u` instruction. - mutating func visitI64ExtendI32U() throws -> Output + mutating func visitI64ExtendI32U() throws /// Visiting `i64.trunc_f32_s` instruction. - mutating func visitI64TruncF32S() throws -> Output + mutating func visitI64TruncF32S() throws /// Visiting `i64.trunc_f32_u` instruction. - mutating func visitI64TruncF32U() throws -> Output + mutating func visitI64TruncF32U() throws /// Visiting `i64.trunc_f64_s` instruction. - mutating func visitI64TruncF64S() throws -> Output + mutating func visitI64TruncF64S() throws /// Visiting `i64.trunc_f64_u` instruction. - mutating func visitI64TruncF64U() throws -> Output + mutating func visitI64TruncF64U() throws /// Visiting `f32.convert_i32_s` instruction. - mutating func visitF32ConvertI32S() throws -> Output + mutating func visitF32ConvertI32S() throws /// Visiting `f32.convert_i32_u` instruction. - mutating func visitF32ConvertI32U() throws -> Output + mutating func visitF32ConvertI32U() throws /// Visiting `f32.convert_i64_s` instruction. - mutating func visitF32ConvertI64S() throws -> Output + mutating func visitF32ConvertI64S() throws /// Visiting `f32.convert_i64_u` instruction. - mutating func visitF32ConvertI64U() throws -> Output + mutating func visitF32ConvertI64U() throws /// Visiting `f32.demote_f64` instruction. - mutating func visitF32DemoteF64() throws -> Output + mutating func visitF32DemoteF64() throws /// Visiting `f64.convert_i32_s` instruction. - mutating func visitF64ConvertI32S() throws -> Output + mutating func visitF64ConvertI32S() throws /// Visiting `f64.convert_i32_u` instruction. - mutating func visitF64ConvertI32U() throws -> Output + mutating func visitF64ConvertI32U() throws /// Visiting `f64.convert_i64_s` instruction. - mutating func visitF64ConvertI64S() throws -> Output + mutating func visitF64ConvertI64S() throws /// Visiting `f64.convert_i64_u` instruction. - mutating func visitF64ConvertI64U() throws -> Output + mutating func visitF64ConvertI64U() throws /// Visiting `f64.promote_f32` instruction. - mutating func visitF64PromoteF32() throws -> Output + mutating func visitF64PromoteF32() throws /// Visiting `i32.reinterpret_f32` instruction. - mutating func visitI32ReinterpretF32() throws -> Output + mutating func visitI32ReinterpretF32() throws /// Visiting `i64.reinterpret_f64` instruction. - mutating func visitI64ReinterpretF64() throws -> Output + mutating func visitI64ReinterpretF64() throws /// Visiting `f32.reinterpret_i32` instruction. - mutating func visitF32ReinterpretI32() throws -> Output + mutating func visitF32ReinterpretI32() throws /// Visiting `f64.reinterpret_i64` instruction. - mutating func visitF64ReinterpretI64() throws -> Output + mutating func visitF64ReinterpretI64() throws /// Visiting `i32.extend8_s` instruction. - mutating func visitI32Extend8S() throws -> Output + mutating func visitI32Extend8S() throws /// Visiting `i32.extend16_s` instruction. - mutating func visitI32Extend16S() throws -> Output + mutating func visitI32Extend16S() throws /// Visiting `i64.extend8_s` instruction. - mutating func visitI64Extend8S() throws -> Output + mutating func visitI64Extend8S() throws /// Visiting `i64.extend16_s` instruction. - mutating func visitI64Extend16S() throws -> Output + mutating func visitI64Extend16S() throws /// Visiting `i64.extend32_s` instruction. - mutating func visitI64Extend32S() throws -> Output + mutating func visitI64Extend32S() throws /// Visiting `memory.init` instruction. - mutating func visitMemoryInit(dataIndex: UInt32) throws -> Output + mutating func visitMemoryInit(dataIndex: UInt32) throws /// Visiting `data.drop` instruction. - mutating func visitDataDrop(dataIndex: UInt32) throws -> Output + mutating func visitDataDrop(dataIndex: UInt32) throws /// Visiting `memory.copy` instruction. - mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws -> Output + mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws /// Visiting `memory.fill` instruction. - mutating func visitMemoryFill(memory: UInt32) throws -> Output + mutating func visitMemoryFill(memory: UInt32) throws /// Visiting `table.init` instruction. - mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws -> Output + mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws /// Visiting `elem.drop` instruction. - mutating func visitElemDrop(elemIndex: UInt32) throws -> Output + mutating func visitElemDrop(elemIndex: UInt32) throws /// Visiting `table.copy` instruction. - mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws -> Output + mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws /// Visiting `table.fill` instruction. - mutating func visitTableFill(table: UInt32) throws -> Output + mutating func visitTableFill(table: UInt32) throws /// Visiting `table.get` instruction. - mutating func visitTableGet(table: UInt32) throws -> Output + mutating func visitTableGet(table: UInt32) throws /// Visiting `table.set` instruction. - mutating func visitTableSet(table: UInt32) throws -> Output + mutating func visitTableSet(table: UInt32) throws /// Visiting `table.grow` instruction. - mutating func visitTableGrow(table: UInt32) throws -> Output + mutating func visitTableGrow(table: UInt32) throws /// Visiting `table.size` instruction. - mutating func visitTableSize(table: UInt32) throws -> Output + mutating func visitTableSize(table: UInt32) throws /// Visiting `i32.trunc_sat_f32_s` instruction. - mutating func visitI32TruncSatF32S() throws -> Output + mutating func visitI32TruncSatF32S() throws /// Visiting `i32.trunc_sat_f32_u` instruction. - mutating func visitI32TruncSatF32U() throws -> Output + mutating func visitI32TruncSatF32U() throws /// Visiting `i32.trunc_sat_f64_s` instruction. - mutating func visitI32TruncSatF64S() throws -> Output + mutating func visitI32TruncSatF64S() throws /// Visiting `i32.trunc_sat_f64_u` instruction. - mutating func visitI32TruncSatF64U() throws -> Output + mutating func visitI32TruncSatF64U() throws /// Visiting `i64.trunc_sat_f32_s` instruction. - mutating func visitI64TruncSatF32S() throws -> Output + mutating func visitI64TruncSatF32S() throws /// Visiting `i64.trunc_sat_f32_u` instruction. - mutating func visitI64TruncSatF32U() throws -> Output + mutating func visitI64TruncSatF32U() throws /// Visiting `i64.trunc_sat_f64_s` instruction. - mutating func visitI64TruncSatF64S() throws -> Output + mutating func visitI64TruncSatF64S() throws /// Visiting `i64.trunc_sat_f64_u` instruction. - mutating func visitI64TruncSatF64U() throws -> Output + mutating func visitI64TruncSatF64U() throws } extension InstructionVisitor { /// Visits an instruction. - public mutating func visit(_ instruction: Instruction) throws -> Output { + public mutating func visit(_ instruction: Instruction) throws { switch instruction { case .unreachable: return try visitUnreachable() case .nop: return try visitNop() @@ -1861,211 +1858,208 @@ extension InstructionVisitor { } } - -/// A visitor for WebAssembly instructions that returns `Void` with default implementations. -public protocol VoidInstructionVisitor: InstructionVisitor where Output == Void {} - -extension VoidInstructionVisitor { - public mutating func visitUnreachable() throws -> Void {} - public mutating func visitNop() throws -> Void {} - public mutating func visitBlock(blockType: BlockType) throws -> Void {} - public mutating func visitLoop(blockType: BlockType) throws -> Void {} - public mutating func visitIf(blockType: BlockType) throws -> Void {} - public mutating func visitElse() throws -> Void {} - public mutating func visitEnd() throws -> Void {} - public mutating func visitBr(relativeDepth: UInt32) throws -> Void {} - public mutating func visitBrIf(relativeDepth: UInt32) throws -> Void {} - public mutating func visitBrTable(targets: BrTable) throws -> Void {} - public mutating func visitReturn() throws -> Void {} - public mutating func visitCall(functionIndex: UInt32) throws -> Void {} - public mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws -> Void {} - public mutating func visitDrop() throws -> Void {} - public mutating func visitSelect() throws -> Void {} - public mutating func visitTypedSelect(type: ValueType) throws -> Void {} - public mutating func visitLocalGet(localIndex: UInt32) throws -> Void {} - public mutating func visitLocalSet(localIndex: UInt32) throws -> Void {} - public mutating func visitLocalTee(localIndex: UInt32) throws -> Void {} - public mutating func visitGlobalGet(globalIndex: UInt32) throws -> Void {} - public mutating func visitGlobalSet(globalIndex: UInt32) throws -> Void {} - public mutating func visitI32Load(memarg: MemArg) throws -> Void {} - public mutating func visitI64Load(memarg: MemArg) throws -> Void {} - public mutating func visitF32Load(memarg: MemArg) throws -> Void {} - public mutating func visitF64Load(memarg: MemArg) throws -> Void {} - public mutating func visitI32Load8S(memarg: MemArg) throws -> Void {} - public mutating func visitI32Load8U(memarg: MemArg) throws -> Void {} - public mutating func visitI32Load16S(memarg: MemArg) throws -> Void {} - public mutating func visitI32Load16U(memarg: MemArg) throws -> Void {} - public mutating func visitI64Load8S(memarg: MemArg) throws -> Void {} - public mutating func visitI64Load8U(memarg: MemArg) throws -> Void {} - public mutating func visitI64Load16S(memarg: MemArg) throws -> Void {} - public mutating func visitI64Load16U(memarg: MemArg) throws -> Void {} - public mutating func visitI64Load32S(memarg: MemArg) throws -> Void {} - public mutating func visitI64Load32U(memarg: MemArg) throws -> Void {} - public mutating func visitI32Store(memarg: MemArg) throws -> Void {} - public mutating func visitI64Store(memarg: MemArg) throws -> Void {} - public mutating func visitF32Store(memarg: MemArg) throws -> Void {} - public mutating func visitF64Store(memarg: MemArg) throws -> Void {} - public mutating func visitI32Store8(memarg: MemArg) throws -> Void {} - public mutating func visitI32Store16(memarg: MemArg) throws -> Void {} - public mutating func visitI64Store8(memarg: MemArg) throws -> Void {} - public mutating func visitI64Store16(memarg: MemArg) throws -> Void {} - public mutating func visitI64Store32(memarg: MemArg) throws -> Void {} - public mutating func visitMemorySize(memory: UInt32) throws -> Void {} - public mutating func visitMemoryGrow(memory: UInt32) throws -> Void {} - public mutating func visitI32Const(value: Int32) throws -> Void {} - public mutating func visitI64Const(value: Int64) throws -> Void {} - public mutating func visitF32Const(value: IEEE754.Float32) throws -> Void {} - public mutating func visitF64Const(value: IEEE754.Float64) throws -> Void {} - public mutating func visitRefNull(type: ReferenceType) throws -> Void {} - public mutating func visitRefIsNull() throws -> Void {} - public mutating func visitRefFunc(functionIndex: UInt32) throws -> Void {} - public mutating func visitI32Eqz() throws -> Void {} - public mutating func visitI32Eq() throws -> Void {} - public mutating func visitI32Ne() throws -> Void {} - public mutating func visitI32LtS() throws -> Void {} - public mutating func visitI32LtU() throws -> Void {} - public mutating func visitI32GtS() throws -> Void {} - public mutating func visitI32GtU() throws -> Void {} - public mutating func visitI32LeS() throws -> Void {} - public mutating func visitI32LeU() throws -> Void {} - public mutating func visitI32GeS() throws -> Void {} - public mutating func visitI32GeU() throws -> Void {} - public mutating func visitI64Eqz() throws -> Void {} - public mutating func visitI64Eq() throws -> Void {} - public mutating func visitI64Ne() throws -> Void {} - public mutating func visitI64LtS() throws -> Void {} - public mutating func visitI64LtU() throws -> Void {} - public mutating func visitI64GtS() throws -> Void {} - public mutating func visitI64GtU() throws -> Void {} - public mutating func visitI64LeS() throws -> Void {} - public mutating func visitI64LeU() throws -> Void {} - public mutating func visitI64GeS() throws -> Void {} - public mutating func visitI64GeU() throws -> Void {} - public mutating func visitF32Eq() throws -> Void {} - public mutating func visitF32Ne() throws -> Void {} - public mutating func visitF32Lt() throws -> Void {} - public mutating func visitF32Gt() throws -> Void {} - public mutating func visitF32Le() throws -> Void {} - public mutating func visitF32Ge() throws -> Void {} - public mutating func visitF64Eq() throws -> Void {} - public mutating func visitF64Ne() throws -> Void {} - public mutating func visitF64Lt() throws -> Void {} - public mutating func visitF64Gt() throws -> Void {} - public mutating func visitF64Le() throws -> Void {} - public mutating func visitF64Ge() throws -> Void {} - public mutating func visitI32Clz() throws -> Void {} - public mutating func visitI32Ctz() throws -> Void {} - public mutating func visitI32Popcnt() throws -> Void {} - public mutating func visitI32Add() throws -> Void {} - public mutating func visitI32Sub() throws -> Void {} - public mutating func visitI32Mul() throws -> Void {} - public mutating func visitI32DivS() throws -> Void {} - public mutating func visitI32DivU() throws -> Void {} - public mutating func visitI32RemS() throws -> Void {} - public mutating func visitI32RemU() throws -> Void {} - public mutating func visitI32And() throws -> Void {} - public mutating func visitI32Or() throws -> Void {} - public mutating func visitI32Xor() throws -> Void {} - public mutating func visitI32Shl() throws -> Void {} - public mutating func visitI32ShrS() throws -> Void {} - public mutating func visitI32ShrU() throws -> Void {} - public mutating func visitI32Rotl() throws -> Void {} - public mutating func visitI32Rotr() throws -> Void {} - public mutating func visitI64Clz() throws -> Void {} - public mutating func visitI64Ctz() throws -> Void {} - public mutating func visitI64Popcnt() throws -> Void {} - public mutating func visitI64Add() throws -> Void {} - public mutating func visitI64Sub() throws -> Void {} - public mutating func visitI64Mul() throws -> Void {} - public mutating func visitI64DivS() throws -> Void {} - public mutating func visitI64DivU() throws -> Void {} - public mutating func visitI64RemS() throws -> Void {} - public mutating func visitI64RemU() throws -> Void {} - public mutating func visitI64And() throws -> Void {} - public mutating func visitI64Or() throws -> Void {} - public mutating func visitI64Xor() throws -> Void {} - public mutating func visitI64Shl() throws -> Void {} - public mutating func visitI64ShrS() throws -> Void {} - public mutating func visitI64ShrU() throws -> Void {} - public mutating func visitI64Rotl() throws -> Void {} - public mutating func visitI64Rotr() throws -> Void {} - public mutating func visitF32Abs() throws -> Void {} - public mutating func visitF32Neg() throws -> Void {} - public mutating func visitF32Ceil() throws -> Void {} - public mutating func visitF32Floor() throws -> Void {} - public mutating func visitF32Trunc() throws -> Void {} - public mutating func visitF32Nearest() throws -> Void {} - public mutating func visitF32Sqrt() throws -> Void {} - public mutating func visitF32Add() throws -> Void {} - public mutating func visitF32Sub() throws -> Void {} - public mutating func visitF32Mul() throws -> Void {} - public mutating func visitF32Div() throws -> Void {} - public mutating func visitF32Min() throws -> Void {} - public mutating func visitF32Max() throws -> Void {} - public mutating func visitF32Copysign() throws -> Void {} - public mutating func visitF64Abs() throws -> Void {} - public mutating func visitF64Neg() throws -> Void {} - public mutating func visitF64Ceil() throws -> Void {} - public mutating func visitF64Floor() throws -> Void {} - public mutating func visitF64Trunc() throws -> Void {} - public mutating func visitF64Nearest() throws -> Void {} - public mutating func visitF64Sqrt() throws -> Void {} - public mutating func visitF64Add() throws -> Void {} - public mutating func visitF64Sub() throws -> Void {} - public mutating func visitF64Mul() throws -> Void {} - public mutating func visitF64Div() throws -> Void {} - public mutating func visitF64Min() throws -> Void {} - public mutating func visitF64Max() throws -> Void {} - public mutating func visitF64Copysign() throws -> Void {} - public mutating func visitI32WrapI64() throws -> Void {} - public mutating func visitI32TruncF32S() throws -> Void {} - public mutating func visitI32TruncF32U() throws -> Void {} - public mutating func visitI32TruncF64S() throws -> Void {} - public mutating func visitI32TruncF64U() throws -> Void {} - public mutating func visitI64ExtendI32S() throws -> Void {} - public mutating func visitI64ExtendI32U() throws -> Void {} - public mutating func visitI64TruncF32S() throws -> Void {} - public mutating func visitI64TruncF32U() throws -> Void {} - public mutating func visitI64TruncF64S() throws -> Void {} - public mutating func visitI64TruncF64U() throws -> Void {} - public mutating func visitF32ConvertI32S() throws -> Void {} - public mutating func visitF32ConvertI32U() throws -> Void {} - public mutating func visitF32ConvertI64S() throws -> Void {} - public mutating func visitF32ConvertI64U() throws -> Void {} - public mutating func visitF32DemoteF64() throws -> Void {} - public mutating func visitF64ConvertI32S() throws -> Void {} - public mutating func visitF64ConvertI32U() throws -> Void {} - public mutating func visitF64ConvertI64S() throws -> Void {} - public mutating func visitF64ConvertI64U() throws -> Void {} - public mutating func visitF64PromoteF32() throws -> Void {} - public mutating func visitI32ReinterpretF32() throws -> Void {} - public mutating func visitI64ReinterpretF64() throws -> Void {} - public mutating func visitF32ReinterpretI32() throws -> Void {} - public mutating func visitF64ReinterpretI64() throws -> Void {} - public mutating func visitI32Extend8S() throws -> Void {} - public mutating func visitI32Extend16S() throws -> Void {} - public mutating func visitI64Extend8S() throws -> Void {} - public mutating func visitI64Extend16S() throws -> Void {} - public mutating func visitI64Extend32S() throws -> Void {} - public mutating func visitMemoryInit(dataIndex: UInt32) throws -> Void {} - public mutating func visitDataDrop(dataIndex: UInt32) throws -> Void {} - public mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws -> Void {} - public mutating func visitMemoryFill(memory: UInt32) throws -> Void {} - public mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws -> Void {} - public mutating func visitElemDrop(elemIndex: UInt32) throws -> Void {} - public mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws -> Void {} - public mutating func visitTableFill(table: UInt32) throws -> Void {} - public mutating func visitTableGet(table: UInt32) throws -> Void {} - public mutating func visitTableSet(table: UInt32) throws -> Void {} - public mutating func visitTableGrow(table: UInt32) throws -> Void {} - public mutating func visitTableSize(table: UInt32) throws -> Void {} - public mutating func visitI32TruncSatF32S() throws -> Void {} - public mutating func visitI32TruncSatF32U() throws -> Void {} - public mutating func visitI32TruncSatF64S() throws -> Void {} - public mutating func visitI32TruncSatF64U() throws -> Void {} - public mutating func visitI64TruncSatF32S() throws -> Void {} - public mutating func visitI64TruncSatF32U() throws -> Void {} - public mutating func visitI64TruncSatF64S() throws -> Void {} - public mutating func visitI64TruncSatF64U() throws -> Void {} +// MARK: - Placeholder implementations +extension InstructionVisitor { + public mutating func visitUnreachable() throws {} + public mutating func visitNop() throws {} + public mutating func visitBlock(blockType: BlockType) throws {} + public mutating func visitLoop(blockType: BlockType) throws {} + public mutating func visitIf(blockType: BlockType) throws {} + public mutating func visitElse() throws {} + public mutating func visitEnd() throws {} + public mutating func visitBr(relativeDepth: UInt32) throws {} + public mutating func visitBrIf(relativeDepth: UInt32) throws {} + public mutating func visitBrTable(targets: BrTable) throws {} + public mutating func visitReturn() throws {} + public mutating func visitCall(functionIndex: UInt32) throws {} + public mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws {} + public mutating func visitDrop() throws {} + public mutating func visitSelect() throws {} + public mutating func visitTypedSelect(type: ValueType) throws {} + public mutating func visitLocalGet(localIndex: UInt32) throws {} + public mutating func visitLocalSet(localIndex: UInt32) throws {} + public mutating func visitLocalTee(localIndex: UInt32) throws {} + public mutating func visitGlobalGet(globalIndex: UInt32) throws {} + public mutating func visitGlobalSet(globalIndex: UInt32) throws {} + public mutating func visitI32Load(memarg: MemArg) throws {} + public mutating func visitI64Load(memarg: MemArg) throws {} + public mutating func visitF32Load(memarg: MemArg) throws {} + public mutating func visitF64Load(memarg: MemArg) throws {} + public mutating func visitI32Load8S(memarg: MemArg) throws {} + public mutating func visitI32Load8U(memarg: MemArg) throws {} + public mutating func visitI32Load16S(memarg: MemArg) throws {} + public mutating func visitI32Load16U(memarg: MemArg) throws {} + public mutating func visitI64Load8S(memarg: MemArg) throws {} + public mutating func visitI64Load8U(memarg: MemArg) throws {} + public mutating func visitI64Load16S(memarg: MemArg) throws {} + public mutating func visitI64Load16U(memarg: MemArg) throws {} + public mutating func visitI64Load32S(memarg: MemArg) throws {} + public mutating func visitI64Load32U(memarg: MemArg) throws {} + public mutating func visitI32Store(memarg: MemArg) throws {} + public mutating func visitI64Store(memarg: MemArg) throws {} + public mutating func visitF32Store(memarg: MemArg) throws {} + public mutating func visitF64Store(memarg: MemArg) throws {} + public mutating func visitI32Store8(memarg: MemArg) throws {} + public mutating func visitI32Store16(memarg: MemArg) throws {} + public mutating func visitI64Store8(memarg: MemArg) throws {} + public mutating func visitI64Store16(memarg: MemArg) throws {} + public mutating func visitI64Store32(memarg: MemArg) throws {} + public mutating func visitMemorySize(memory: UInt32) throws {} + public mutating func visitMemoryGrow(memory: UInt32) throws {} + public mutating func visitI32Const(value: Int32) throws {} + public mutating func visitI64Const(value: Int64) throws {} + public mutating func visitF32Const(value: IEEE754.Float32) throws {} + public mutating func visitF64Const(value: IEEE754.Float64) throws {} + public mutating func visitRefNull(type: ReferenceType) throws {} + public mutating func visitRefIsNull() throws {} + public mutating func visitRefFunc(functionIndex: UInt32) throws {} + public mutating func visitI32Eqz() throws {} + public mutating func visitI32Eq() throws {} + public mutating func visitI32Ne() throws {} + public mutating func visitI32LtS() throws {} + public mutating func visitI32LtU() throws {} + public mutating func visitI32GtS() throws {} + public mutating func visitI32GtU() throws {} + public mutating func visitI32LeS() throws {} + public mutating func visitI32LeU() throws {} + public mutating func visitI32GeS() throws {} + public mutating func visitI32GeU() throws {} + public mutating func visitI64Eqz() throws {} + public mutating func visitI64Eq() throws {} + public mutating func visitI64Ne() throws {} + public mutating func visitI64LtS() throws {} + public mutating func visitI64LtU() throws {} + public mutating func visitI64GtS() throws {} + public mutating func visitI64GtU() throws {} + public mutating func visitI64LeS() throws {} + public mutating func visitI64LeU() throws {} + public mutating func visitI64GeS() throws {} + public mutating func visitI64GeU() throws {} + public mutating func visitF32Eq() throws {} + public mutating func visitF32Ne() throws {} + public mutating func visitF32Lt() throws {} + public mutating func visitF32Gt() throws {} + public mutating func visitF32Le() throws {} + public mutating func visitF32Ge() throws {} + public mutating func visitF64Eq() throws {} + public mutating func visitF64Ne() throws {} + public mutating func visitF64Lt() throws {} + public mutating func visitF64Gt() throws {} + public mutating func visitF64Le() throws {} + public mutating func visitF64Ge() throws {} + public mutating func visitI32Clz() throws {} + public mutating func visitI32Ctz() throws {} + public mutating func visitI32Popcnt() throws {} + public mutating func visitI32Add() throws {} + public mutating func visitI32Sub() throws {} + public mutating func visitI32Mul() throws {} + public mutating func visitI32DivS() throws {} + public mutating func visitI32DivU() throws {} + public mutating func visitI32RemS() throws {} + public mutating func visitI32RemU() throws {} + public mutating func visitI32And() throws {} + public mutating func visitI32Or() throws {} + public mutating func visitI32Xor() throws {} + public mutating func visitI32Shl() throws {} + public mutating func visitI32ShrS() throws {} + public mutating func visitI32ShrU() throws {} + public mutating func visitI32Rotl() throws {} + public mutating func visitI32Rotr() throws {} + public mutating func visitI64Clz() throws {} + public mutating func visitI64Ctz() throws {} + public mutating func visitI64Popcnt() throws {} + public mutating func visitI64Add() throws {} + public mutating func visitI64Sub() throws {} + public mutating func visitI64Mul() throws {} + public mutating func visitI64DivS() throws {} + public mutating func visitI64DivU() throws {} + public mutating func visitI64RemS() throws {} + public mutating func visitI64RemU() throws {} + public mutating func visitI64And() throws {} + public mutating func visitI64Or() throws {} + public mutating func visitI64Xor() throws {} + public mutating func visitI64Shl() throws {} + public mutating func visitI64ShrS() throws {} + public mutating func visitI64ShrU() throws {} + public mutating func visitI64Rotl() throws {} + public mutating func visitI64Rotr() throws {} + public mutating func visitF32Abs() throws {} + public mutating func visitF32Neg() throws {} + public mutating func visitF32Ceil() throws {} + public mutating func visitF32Floor() throws {} + public mutating func visitF32Trunc() throws {} + public mutating func visitF32Nearest() throws {} + public mutating func visitF32Sqrt() throws {} + public mutating func visitF32Add() throws {} + public mutating func visitF32Sub() throws {} + public mutating func visitF32Mul() throws {} + public mutating func visitF32Div() throws {} + public mutating func visitF32Min() throws {} + public mutating func visitF32Max() throws {} + public mutating func visitF32Copysign() throws {} + public mutating func visitF64Abs() throws {} + public mutating func visitF64Neg() throws {} + public mutating func visitF64Ceil() throws {} + public mutating func visitF64Floor() throws {} + public mutating func visitF64Trunc() throws {} + public mutating func visitF64Nearest() throws {} + public mutating func visitF64Sqrt() throws {} + public mutating func visitF64Add() throws {} + public mutating func visitF64Sub() throws {} + public mutating func visitF64Mul() throws {} + public mutating func visitF64Div() throws {} + public mutating func visitF64Min() throws {} + public mutating func visitF64Max() throws {} + public mutating func visitF64Copysign() throws {} + public mutating func visitI32WrapI64() throws {} + public mutating func visitI32TruncF32S() throws {} + public mutating func visitI32TruncF32U() throws {} + public mutating func visitI32TruncF64S() throws {} + public mutating func visitI32TruncF64U() throws {} + public mutating func visitI64ExtendI32S() throws {} + public mutating func visitI64ExtendI32U() throws {} + public mutating func visitI64TruncF32S() throws {} + public mutating func visitI64TruncF32U() throws {} + public mutating func visitI64TruncF64S() throws {} + public mutating func visitI64TruncF64U() throws {} + public mutating func visitF32ConvertI32S() throws {} + public mutating func visitF32ConvertI32U() throws {} + public mutating func visitF32ConvertI64S() throws {} + public mutating func visitF32ConvertI64U() throws {} + public mutating func visitF32DemoteF64() throws {} + public mutating func visitF64ConvertI32S() throws {} + public mutating func visitF64ConvertI32U() throws {} + public mutating func visitF64ConvertI64S() throws {} + public mutating func visitF64ConvertI64U() throws {} + public mutating func visitF64PromoteF32() throws {} + public mutating func visitI32ReinterpretF32() throws {} + public mutating func visitI64ReinterpretF64() throws {} + public mutating func visitF32ReinterpretI32() throws {} + public mutating func visitF64ReinterpretI64() throws {} + public mutating func visitI32Extend8S() throws {} + public mutating func visitI32Extend16S() throws {} + public mutating func visitI64Extend8S() throws {} + public mutating func visitI64Extend16S() throws {} + public mutating func visitI64Extend32S() throws {} + public mutating func visitMemoryInit(dataIndex: UInt32) throws {} + public mutating func visitDataDrop(dataIndex: UInt32) throws {} + public mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws {} + public mutating func visitMemoryFill(memory: UInt32) throws {} + public mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws {} + public mutating func visitElemDrop(elemIndex: UInt32) throws {} + public mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws {} + public mutating func visitTableFill(table: UInt32) throws {} + public mutating func visitTableGet(table: UInt32) throws {} + public mutating func visitTableSet(table: UInt32) throws {} + public mutating func visitTableGrow(table: UInt32) throws {} + public mutating func visitTableSize(table: UInt32) throws {} + public mutating func visitI32TruncSatF32S() throws {} + public mutating func visitI32TruncSatF32U() throws {} + public mutating func visitI32TruncSatF64S() throws {} + public mutating func visitI32TruncSatF64U() throws {} + public mutating func visitI64TruncSatF32S() throws {} + public mutating func visitI64TruncSatF32U() throws {} + public mutating func visitI64TruncSatF64S() throws {} + public mutating func visitI64TruncSatF64U() throws {} } diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 0fe93e83..88861c37 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -89,7 +89,7 @@ extension Code { /// ```swift /// import WasmParser /// - /// struct MyVisitor: VoidInstructionVisitor { + /// struct MyVisitor: InstructionVisitor { /// func visitLocalGet(localIndex: UInt32) { /// print("local.get \(localIndex)") /// } @@ -118,7 +118,7 @@ extension Code { let parser = Parser(stream: StaticByteStream(bytes: self.expression), features: self.features, hasDataCount: self.hasDataCount) var lastCode: InstructionCode? while try !parser.stream.hasReachedEnd() { - (lastCode, _) = try parser.parseInstruction(visitor: &visitor) + lastCode = try parser.parseInstruction(visitor: &visitor) } guard lastCode == .end else { throw WasmParserError.endOpcodeExpected @@ -126,6 +126,39 @@ extension Code { } } +// TODO: Move `doParseInstruction` under `ExpressionParser` struct +@_documentation(visibility: internal) +public struct ExpressionParser { + @usableFromInline + let parser: Parser + @usableFromInline + var lastCode: InstructionCode? + + public var offset: Int { + self.parser.currentIndex + } + + public init(code: Code) { + self.parser = Parser( + stream: StaticByteStream(bytes: code.expression), + features: code.features, + hasDataCount: code.hasDataCount + ) + } + + @inlinable + public mutating func visit(visitor: inout V) throws -> Bool { + lastCode = try parser.parseInstruction(visitor: &visitor) + let shouldContinue = try !parser.stream.hasReachedEnd() + if !shouldContinue { + guard lastCode == .end else { + throw WasmParserError.endOpcodeExpected + } + } + return shouldContinue + } +} + /// Flags for enabling/disabling WebAssembly features public struct WasmFeatureSet: OptionSet { /// The raw value of the feature set @@ -480,16 +513,17 @@ extension Parser { /// extension Parser { @inlinable - func parseInstruction(visitor v: inout V) throws -> (InstructionCode, V.Output) { + func parseInstruction(visitor v: inout V) throws -> InstructionCode { let rawCode = try stream.consumeAny() guard let code = InstructionCode(rawValue: rawCode) else { throw WasmParserError.illegalOpcode(rawCode) } - return (code, try doParseInstruction(code: code, visitor: &v)) + try doParseInstruction(code: code, visitor: &v) + return code } @inlinable - func doParseInstruction(code: InstructionCode, visitor v: inout V) throws -> V.Output { + func doParseInstruction(code: InstructionCode, visitor v: inout V) throws { switch code { case .unreachable: return try v.visitUnreachable() case .nop: return try v.visitNop() @@ -815,22 +849,20 @@ extension Parser { } struct InstructionFactory: AnyInstructionVisitor { - typealias Output = Instruction + var insts: [Instruction] = [] - func visit(_ instruction: Instruction) throws -> Instruction { - return instruction + mutating func visit(_ instruction: Instruction) throws { + insts.append(instruction) } } func parseConstExpression() throws -> ConstExpression { var factory = InstructionFactory() - var insts: [Instruction] = [] - var inst: Instruction + var inst: InstructionCode repeat { - (_, inst) = try self.parseInstruction(visitor: &factory) - insts.append(inst) + inst = try self.parseInstruction(visitor: &factory) } while inst != .end - return insts + return factory.insts } } diff --git a/Tests/WasmKitTests/ExecutionTests.swift b/Tests/WasmKitTests/ExecutionTests.swift index 297d8a41..724b4713 100644 --- a/Tests/WasmKitTests/ExecutionTests.swift +++ b/Tests/WasmKitTests/ExecutionTests.swift @@ -35,7 +35,7 @@ final class ExecutionTests: XCTestCase { (module (memory 0) (func (export "_start") (result i32) - (memory.grow (i32.const 1)) + (drop (memory.grow (i32.const 1))) (i32.store (i32.const 1) (i32.const 42)) (i32.load (i32.const 1)) ) diff --git a/Tests/WasmKitTests/ExtraSuite/const_slot.wast b/Tests/WasmKitTests/ExtraSuite/const_slot.wast index 188ac591..ece3f55f 100644 --- a/Tests/WasmKitTests/ExtraSuite/const_slot.wast +++ b/Tests/WasmKitTests/ExtraSuite/const_slot.wast @@ -17,6 +17,7 @@ ;; emit its own instruction. (i32.const 0) (local.set 0) + (drop) ;; drop i32.add (local.get 0) ) ) diff --git a/Tests/WasmKitTests/ExtraSuite/local_cow.wast b/Tests/WasmKitTests/ExtraSuite/local_cow.wast index 7e2912e2..68d6f02b 100644 --- a/Tests/WasmKitTests/ExtraSuite/local_cow.wast +++ b/Tests/WasmKitTests/ExtraSuite/local_cow.wast @@ -43,6 +43,7 @@ ;; emit its own instruction. (local.get 1) (local.set 0) + (drop) ;; drop i32.add (local.get 0) ) ) diff --git a/Tests/WasmKitTests/Spectest/TestCase.swift b/Tests/WasmKitTests/Spectest/TestCase.swift index 5edb5425..ca0fcc43 100644 --- a/Tests/WasmKitTests/Spectest/TestCase.swift +++ b/Tests/WasmKitTests/Spectest/TestCase.swift @@ -143,8 +143,8 @@ extension TestCase { if let result = try context.run(directive: directive) { handler(self, location, result) } - } catch let error as SpectestError { - handler(self, location, .failed(error.description)) + } catch let error { + handler(self, location, .failed("\(error)")) } } } catch let parseError as WatParserError { @@ -234,7 +234,7 @@ extension WastRunContext { importsSpace.define(module: name, instance.exports) return nil - case .assertMalformed(let module, let message): + case .assertMalformed(let module, let message), .assertInvalid(let module, let message): currentInstance = nil do { let module = try parseModule(rootPath: rootPath, moduleSource: module.source) @@ -244,7 +244,7 @@ extension WastRunContext { } catch { return .passed } - return .failed("module should not be parsed: expected \"\(message)\"") + return .failed("module should not be parsed nor valid: expected \"\(message)\"") case .assertTrap(execute: .wat(var wat), let message): currentInstance = nil @@ -321,9 +321,6 @@ extension WastRunContext { } return .passed - case .assertInvalid: - return .skipped("validation is no implemented yet") - case .invoke(let invoke): _ = try wastInvoke(call: invoke) return .passed diff --git a/Tests/WasmKitTests/SpectestTests.swift b/Tests/WasmKitTests/SpectestTests.swift index 0b6e2353..fa82496e 100644 --- a/Tests/WasmKitTests/SpectestTests.swift +++ b/Tests/WasmKitTests/SpectestTests.swift @@ -20,8 +20,10 @@ final class SpectestTests: XCTestCase { let defaultConfig = EngineConfiguration() let ok = try await spectest( path: Self.testPaths, - include: [], - exclude: [], + include: [ + ], + exclude: [ + ], parallel: true, configuration: defaultConfig ) diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index a3bb4a88..94d305cd 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -63,9 +63,6 @@ enum WasmGen { /// The visitor pattern is used while parsing WebAssembly expressions to allow for easy extensibility. /// See the expression parsing method ``Code/parseExpression(visitor:)`` public protocol InstructionVisitor { - - /// The return type of visitor methods. - associatedtype Output """ for instruction in instructions { @@ -75,7 +72,7 @@ enum WasmGen { code += instruction.immediates.map { i in "\(i.label): \(i.type)" }.joined(separator: ", ") - code += ") throws -> Output" + code += ") throws" } code += """ @@ -88,7 +85,7 @@ enum WasmGen { extension InstructionVisitor { /// Visits an instruction. - public mutating func visit(_ instruction: Instruction) throws -> Output { + public mutating func visit(_ instruction: Instruction) throws { switch instruction { """ @@ -113,11 +110,8 @@ enum WasmGen { code += """ - - /// A visitor for WebAssembly instructions that returns `Void` with default implementations. - public protocol VoidInstructionVisitor: InstructionVisitor where Output == Void {} - - extension VoidInstructionVisitor { + // MARK: - Placeholder implementations + extension InstructionVisitor { """ for instruction in instructions { @@ -125,7 +119,7 @@ enum WasmGen { code += instruction.immediates.map { i in "\(i.label): \(i.type)" }.joined(separator: ", ") - code += ") throws -> Void {}\n" + code += ") throws {}\n" } code += "}\n" @@ -176,7 +170,7 @@ enum WasmGen { /// A visitor that visits all instructions by a single visit method. public protocol AnyInstructionVisitor: InstructionVisitor { /// Visiting any instruction. - mutating func visit(_ instruction: Instruction) throws -> Output + mutating func visit(_ instruction: Instruction) throws } extension AnyInstructionVisitor { @@ -188,7 +182,7 @@ enum WasmGen { code += instruction.immediates.map { i in "\(i.label): \(i.type)" }.joined(separator: ", ") - code += ") throws -> Output { " + code += ") throws { " code += "return try self.visit(" + buildInstructionInstanceFromContext(instruction) + ")" code += " }\n" } @@ -224,7 +218,7 @@ enum WasmGen { code += instruction.immediates.map { i in "\(i.label): \(i.type)" }.joined(separator: ", ") - code += ") throws -> V.Output {\n" + code += ") throws {\n" code += " trace(" code += buildInstructionInstanceFromContext(instruction) code += ")\n" @@ -253,7 +247,7 @@ enum WasmGen { /// - Returns: A closure that invokes the corresponding visitor method. Nil if the keyword is not recognized. /// /// Note: The returned closure does not consume any tokens. - func parseTextInstruction(keyword: String, expressionParser: inout ExpressionParser, wat: inout Wat) throws -> ((inout V) throws -> V.Output)? { + func parseTextInstruction(keyword: String, expressionParser: inout ExpressionParser, wat: inout Wat) throws -> ((inout V) throws -> Void)? { switch keyword { """ @@ -312,10 +306,16 @@ enum WasmGen { static func generateInstructionEncoder(_ instructions: InstructionSet) -> String { var code = """ + import WasmParser + import WasmTypes + /// An instruction encoder that is responsible for encoding opcodes and immediates. protocol InstructionEncoder: InstructionVisitor { + /// Encodes an instruction opcode. mutating func encodeInstruction(_ opcode: UInt8, _ prefix: UInt8?) throws + // MARK: - Immediates encoding + """ var immediateTypes: Set<[Instruction.Immediate]> = [] @@ -348,6 +348,7 @@ enum WasmGen { code += """ } + // InstructionEncoder implements the InstructionVisitor protocol to call the corresponding encode method. extension InstructionEncoder { """ @@ -487,8 +488,10 @@ enum WasmGen { GeneratedFile( projectSources + ["WAT", "ParseInstruction.swift"], header + generateTextParser(instructions) - + "\n" - + generateInstructionEncoder(instructions) + ), + GeneratedFile( + projectSources + ["WAT", "InstructionEncoder.swift"], + header + generateInstructionEncoder(instructions) ), ]