diff --git a/Benchmarks/Package.swift b/Benchmarks/Package.swift index c00e2759..d0d6dc18 100644 --- a/Benchmarks/Package.swift +++ b/Benchmarks/Package.swift @@ -6,7 +6,7 @@ let package = Package( name: "Benchmarks", platforms: [.macOS(.v13)], dependencies: [ - .package(path: "../"), + .package(name: "WasmKit", path: "../"), .package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "1.4.0")), ] ) diff --git a/Benchmarks/bench.py b/Benchmarks/bench.py index 8bbb120a..c831d59f 100755 --- a/Benchmarks/bench.py +++ b/Benchmarks/bench.py @@ -71,6 +71,8 @@ def __init__(self): def add_dir(subpath): path = os.path.join(suites_path, subpath) + if not os.path.exists(path): + return for filename in os.listdir(path): if filename.endswith(".wasm"): targets.append(os.path.join(path, filename)) diff --git a/Sources/WAT/BinaryInstructionEncoder.swift b/Sources/WAT/BinaryInstructionEncoder.swift new file mode 100644 index 00000000..7ac44df9 --- /dev/null +++ b/Sources/WAT/BinaryInstructionEncoder.swift @@ -0,0 +1,387 @@ +// 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 +/// in Wasm binary format. +protocol BinaryInstructionEncoder: InstructionVisitor { + /// Encodes an instruction opcode. + mutating func encodeInstruction(_ opcode: [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 +} + +// BinaryInstructionEncoder implements the InstructionVisitor protocol to call the corresponding encode method. +extension BinaryInstructionEncoder { + mutating func visitUnreachable() throws { try encodeInstruction([0x00]) } + mutating func visitNop() throws { try encodeInstruction([0x01]) } + mutating func visitBlock(blockType: BlockType) throws { + try encodeInstruction([0x02]) + try encodeImmediates(blockType: blockType) + } + mutating func visitLoop(blockType: BlockType) throws { + try encodeInstruction([0x03]) + try encodeImmediates(blockType: blockType) + } + mutating func visitIf(blockType: BlockType) throws { + try encodeInstruction([0x04]) + try encodeImmediates(blockType: blockType) + } + mutating func visitElse() throws { try encodeInstruction([0x05]) } + mutating func visitEnd() throws { try encodeInstruction([0x0B]) } + mutating func visitBr(relativeDepth: UInt32) throws { + try encodeInstruction([0x0C]) + try encodeImmediates(relativeDepth: relativeDepth) + } + mutating func visitBrIf(relativeDepth: UInt32) throws { + try encodeInstruction([0x0D]) + try encodeImmediates(relativeDepth: relativeDepth) + } + mutating func visitBrTable(targets: BrTable) throws { + try encodeInstruction([0x0E]) + try encodeImmediates(targets: targets) + } + mutating func visitReturn() throws { try encodeInstruction([0x0F]) } + mutating func visitCall(functionIndex: UInt32) throws { + try encodeInstruction([0x10]) + try encodeImmediates(functionIndex: functionIndex) + } + mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws { + try encodeInstruction([0x11]) + try encodeImmediates(typeIndex: typeIndex, tableIndex: tableIndex) + } + mutating func visitDrop() throws { try encodeInstruction([0x1A]) } + mutating func visitSelect() throws { try encodeInstruction([0x1B]) } + mutating func visitTypedSelect(type: ValueType) throws { + try encodeInstruction([0x1C]) + try encodeImmediates(type: type) + } + mutating func visitLocalGet(localIndex: UInt32) throws { + try encodeInstruction([0x20]) + try encodeImmediates(localIndex: localIndex) + } + mutating func visitLocalSet(localIndex: UInt32) throws { + try encodeInstruction([0x21]) + try encodeImmediates(localIndex: localIndex) + } + mutating func visitLocalTee(localIndex: UInt32) throws { + try encodeInstruction([0x22]) + try encodeImmediates(localIndex: localIndex) + } + mutating func visitGlobalGet(globalIndex: UInt32) throws { + try encodeInstruction([0x23]) + try encodeImmediates(globalIndex: globalIndex) + } + mutating func visitGlobalSet(globalIndex: UInt32) throws { + try encodeInstruction([0x24]) + try encodeImmediates(globalIndex: globalIndex) + } + mutating func visitLoad(_ load: Instruction.Load, memarg: MemArg) throws { + let opcode: [UInt8] + switch load { + case .i32Load: opcode = [0x28] + case .i64Load: opcode = [0x29] + case .f32Load: opcode = [0x2A] + case .f64Load: opcode = [0x2B] + case .i32Load8S: opcode = [0x2C] + case .i32Load8U: opcode = [0x2D] + case .i32Load16S: opcode = [0x2E] + case .i32Load16U: opcode = [0x2F] + case .i64Load8S: opcode = [0x30] + case .i64Load8U: opcode = [0x31] + case .i64Load16S: opcode = [0x32] + case .i64Load16U: opcode = [0x33] + case .i64Load32S: opcode = [0x34] + case .i64Load32U: opcode = [0x35] + } + + try encodeInstruction(opcode) + try encodeImmediates(memarg: memarg) + } + mutating func visitStore(_ store: Instruction.Store, memarg: MemArg) throws { + let opcode: [UInt8] + switch store { + case .i32Store: opcode = [0x36] + case .i64Store: opcode = [0x37] + case .f32Store: opcode = [0x38] + case .f64Store: opcode = [0x39] + case .i32Store8: opcode = [0x3A] + case .i32Store16: opcode = [0x3B] + case .i64Store8: opcode = [0x3C] + case .i64Store16: opcode = [0x3D] + case .i64Store32: opcode = [0x3E] + } + + try encodeInstruction(opcode) + try encodeImmediates(memarg: memarg) + } + mutating func visitMemorySize(memory: UInt32) throws { + try encodeInstruction([0x3F]) + try encodeImmediates(memory: memory) + } + mutating func visitMemoryGrow(memory: UInt32) throws { + try encodeInstruction([0x40]) + try encodeImmediates(memory: memory) + } + mutating func visitI32Const(value: Int32) throws { + try encodeInstruction([0x41]) + try encodeImmediates(value: value) + } + mutating func visitI64Const(value: Int64) throws { + try encodeInstruction([0x42]) + try encodeImmediates(value: value) + } + mutating func visitF32Const(value: IEEE754.Float32) throws { + try encodeInstruction([0x43]) + try encodeImmediates(value: value) + } + mutating func visitF64Const(value: IEEE754.Float64) throws { + try encodeInstruction([0x44]) + try encodeImmediates(value: value) + } + mutating func visitRefNull(type: ReferenceType) throws { + try encodeInstruction([0xD0]) + try encodeImmediates(type: type) + } + mutating func visitRefIsNull() throws { try encodeInstruction([0xD1]) } + mutating func visitRefFunc(functionIndex: UInt32) throws { + try encodeInstruction([0xD2]) + try encodeImmediates(functionIndex: functionIndex) + } + mutating func visitI32Eqz() throws { try encodeInstruction([0x45]) } + mutating func visitCmp(_ cmp: Instruction.Cmp) throws { + let opcode: [UInt8] + switch cmp { + case .i32Eq: opcode = [0x46] + case .i32Ne: opcode = [0x47] + case .i32LtS: opcode = [0x48] + case .i32LtU: opcode = [0x49] + case .i32GtS: opcode = [0x4A] + case .i32GtU: opcode = [0x4B] + case .i32LeS: opcode = [0x4C] + case .i32LeU: opcode = [0x4D] + case .i32GeS: opcode = [0x4E] + case .i32GeU: opcode = [0x4F] + case .i64Eq: opcode = [0x51] + case .i64Ne: opcode = [0x52] + case .i64LtS: opcode = [0x53] + case .i64LtU: opcode = [0x54] + case .i64GtS: opcode = [0x55] + case .i64GtU: opcode = [0x56] + case .i64LeS: opcode = [0x57] + case .i64LeU: opcode = [0x58] + case .i64GeS: opcode = [0x59] + case .i64GeU: opcode = [0x5A] + case .f32Eq: opcode = [0x5B] + case .f32Ne: opcode = [0x5C] + case .f32Lt: opcode = [0x5D] + case .f32Gt: opcode = [0x5E] + case .f32Le: opcode = [0x5F] + case .f32Ge: opcode = [0x60] + case .f64Eq: opcode = [0x61] + case .f64Ne: opcode = [0x62] + case .f64Lt: opcode = [0x63] + case .f64Gt: opcode = [0x64] + case .f64Le: opcode = [0x65] + case .f64Ge: opcode = [0x66] + } + + try encodeInstruction(opcode) + } + mutating func visitI64Eqz() throws { try encodeInstruction([0x50]) } + mutating func visitUnary(_ unary: Instruction.Unary) throws { + let opcode: [UInt8] + switch unary { + case .i32Clz: opcode = [0x67] + case .i32Ctz: opcode = [0x68] + case .i32Popcnt: opcode = [0x69] + case .i64Clz: opcode = [0x79] + case .i64Ctz: opcode = [0x7A] + case .i64Popcnt: opcode = [0x7B] + case .f32Abs: opcode = [0x8B] + case .f32Neg: opcode = [0x8C] + case .f32Ceil: opcode = [0x8D] + case .f32Floor: opcode = [0x8E] + case .f32Trunc: opcode = [0x8F] + case .f32Nearest: opcode = [0x90] + case .f32Sqrt: opcode = [0x91] + case .f64Abs: opcode = [0x99] + case .f64Neg: opcode = [0x9A] + case .f64Ceil: opcode = [0x9B] + case .f64Floor: opcode = [0x9C] + case .f64Trunc: opcode = [0x9D] + case .f64Nearest: opcode = [0x9E] + case .f64Sqrt: opcode = [0x9F] + case .i32Extend8S: opcode = [0xC0] + case .i32Extend16S: opcode = [0xC1] + case .i64Extend8S: opcode = [0xC2] + case .i64Extend16S: opcode = [0xC3] + case .i64Extend32S: opcode = [0xC4] + } + + try encodeInstruction(opcode) + } + mutating func visitBinary(_ binary: Instruction.Binary) throws { + let opcode: [UInt8] + switch binary { + case .i32Add: opcode = [0x6A] + case .i32Sub: opcode = [0x6B] + case .i32Mul: opcode = [0x6C] + case .i32DivS: opcode = [0x6D] + case .i32DivU: opcode = [0x6E] + case .i32RemS: opcode = [0x6F] + case .i32RemU: opcode = [0x70] + case .i32And: opcode = [0x71] + case .i32Or: opcode = [0x72] + case .i32Xor: opcode = [0x73] + case .i32Shl: opcode = [0x74] + case .i32ShrS: opcode = [0x75] + case .i32ShrU: opcode = [0x76] + case .i32Rotl: opcode = [0x77] + case .i32Rotr: opcode = [0x78] + case .i64Add: opcode = [0x7C] + case .i64Sub: opcode = [0x7D] + case .i64Mul: opcode = [0x7E] + case .i64DivS: opcode = [0x7F] + case .i64DivU: opcode = [0x80] + case .i64RemS: opcode = [0x81] + case .i64RemU: opcode = [0x82] + case .i64And: opcode = [0x83] + case .i64Or: opcode = [0x84] + case .i64Xor: opcode = [0x85] + case .i64Shl: opcode = [0x86] + case .i64ShrS: opcode = [0x87] + case .i64ShrU: opcode = [0x88] + case .i64Rotl: opcode = [0x89] + case .i64Rotr: opcode = [0x8A] + case .f32Add: opcode = [0x92] + case .f32Sub: opcode = [0x93] + case .f32Mul: opcode = [0x94] + case .f32Div: opcode = [0x95] + case .f32Min: opcode = [0x96] + case .f32Max: opcode = [0x97] + case .f32Copysign: opcode = [0x98] + case .f64Add: opcode = [0xA0] + case .f64Sub: opcode = [0xA1] + case .f64Mul: opcode = [0xA2] + case .f64Div: opcode = [0xA3] + case .f64Min: opcode = [0xA4] + case .f64Max: opcode = [0xA5] + case .f64Copysign: opcode = [0xA6] + } + + try encodeInstruction(opcode) + } + mutating func visitConversion(_ conversion: Instruction.Conversion) throws { + let opcode: [UInt8] + switch conversion { + case .i32WrapI64: opcode = [0xA7] + case .i32TruncF32S: opcode = [0xA8] + case .i32TruncF32U: opcode = [0xA9] + case .i32TruncF64S: opcode = [0xAA] + case .i32TruncF64U: opcode = [0xAB] + case .i64ExtendI32S: opcode = [0xAC] + case .i64ExtendI32U: opcode = [0xAD] + case .i64TruncF32S: opcode = [0xAE] + case .i64TruncF32U: opcode = [0xAF] + case .i64TruncF64S: opcode = [0xB0] + case .i64TruncF64U: opcode = [0xB1] + case .f32ConvertI32S: opcode = [0xB2] + case .f32ConvertI32U: opcode = [0xB3] + case .f32ConvertI64S: opcode = [0xB4] + case .f32ConvertI64U: opcode = [0xB5] + case .f32DemoteF64: opcode = [0xB6] + case .f64ConvertI32S: opcode = [0xB7] + case .f64ConvertI32U: opcode = [0xB8] + case .f64ConvertI64S: opcode = [0xB9] + case .f64ConvertI64U: opcode = [0xBA] + case .f64PromoteF32: opcode = [0xBB] + case .i32ReinterpretF32: opcode = [0xBC] + case .i64ReinterpretF64: opcode = [0xBD] + case .f32ReinterpretI32: opcode = [0xBE] + case .f64ReinterpretI64: opcode = [0xBF] + case .i32TruncSatF32S: opcode = [0xFC, 0x00] + case .i32TruncSatF32U: opcode = [0xFC, 0x01] + case .i32TruncSatF64S: opcode = [0xFC, 0x02] + case .i32TruncSatF64U: opcode = [0xFC, 0x03] + case .i64TruncSatF32S: opcode = [0xFC, 0x04] + case .i64TruncSatF32U: opcode = [0xFC, 0x05] + case .i64TruncSatF64S: opcode = [0xFC, 0x06] + case .i64TruncSatF64U: opcode = [0xFC, 0x07] + } + + try encodeInstruction(opcode) + } + mutating func visitMemoryInit(dataIndex: UInt32) throws { + try encodeInstruction([0xFC, 0x08]) + try encodeImmediates(dataIndex: dataIndex) + } + mutating func visitDataDrop(dataIndex: UInt32) throws { + try encodeInstruction([0xFC, 0x09]) + try encodeImmediates(dataIndex: dataIndex) + } + mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws { + try encodeInstruction([0xFC, 0x0A]) + try encodeImmediates(dstMem: dstMem, srcMem: srcMem) + } + mutating func visitMemoryFill(memory: UInt32) throws { + try encodeInstruction([0xFC, 0x0B]) + try encodeImmediates(memory: memory) + } + mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws { + try encodeInstruction([0xFC, 0x0C]) + try encodeImmediates(elemIndex: elemIndex, table: table) + } + mutating func visitElemDrop(elemIndex: UInt32) throws { + try encodeInstruction([0xFC, 0x0D]) + try encodeImmediates(elemIndex: elemIndex) + } + mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws { + try encodeInstruction([0xFC, 0x0E]) + try encodeImmediates(dstTable: dstTable, srcTable: srcTable) + } + mutating func visitTableFill(table: UInt32) throws { + try encodeInstruction([0xFC, 0x11]) + try encodeImmediates(table: table) + } + mutating func visitTableGet(table: UInt32) throws { + try encodeInstruction([0x25]) + try encodeImmediates(table: table) + } + mutating func visitTableSet(table: UInt32) throws { + try encodeInstruction([0x26]) + try encodeImmediates(table: table) + } + mutating func visitTableGrow(table: UInt32) throws { + try encodeInstruction([0xFC, 0x0F]) + try encodeImmediates(table: table) + } + mutating func visitTableSize(table: UInt32) throws { + try encodeInstruction([0xFC, 0x10]) + try encodeImmediates(table: table) + } +} diff --git a/Sources/WAT/Encoder.swift b/Sources/WAT/Encoder.swift index 0a89e345..5e7c9a42 100644 --- a/Sources/WAT/Encoder.swift +++ b/Sources/WAT/Encoder.swift @@ -441,7 +441,7 @@ extension WatParser.DataSegmentDecl { } } -struct ExpressionEncoder: InstructionEncoder { +struct ExpressionEncoder: BinaryInstructionEncoder { var encoder = Encoder() var hasDataSegmentInstruction: Bool = false @@ -463,24 +463,21 @@ struct ExpressionEncoder: InstructionEncoder { // MARK: Special instructions mutating func visitMemoryInit(dataIndex: UInt32) throws { - try encodeInstruction(0x08, 0xFC) + try encodeInstruction([0xFC, 0x08]) try encodeImmediates(dataIndex: dataIndex) encodeByte(0x00) // reserved value } mutating func visitTypedSelect(type: ValueType) throws { - try encodeInstruction(0x1C, nil) + try encodeInstruction([0x1C]) encodeByte(0x01) // number of result types try encodeImmediates(type: type) } // MARK: InstructionEncoder conformance - mutating func encodeInstruction(_ opcode: UInt8, _ prefix: UInt8?) throws { - if let prefix { - encoder.output.append(prefix) - } - encoder.output.append(opcode) + mutating func encodeInstruction(_ opcode: [UInt8]) throws { + encoder.output.append(contentsOf: opcode) } mutating func encodeImmediates(blockType: WasmParser.BlockType) throws { switch blockType { diff --git a/Sources/WAT/InstructionEncoder.swift b/Sources/WAT/InstructionEncoder.swift deleted file mode 100644 index 14a2b8ba..00000000 --- a/Sources/WAT/InstructionEncoder.swift +++ /dev/null @@ -1,386 +0,0 @@ -// 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 -} - -// 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 visitLoad(_ load: Instruction.Load, memarg: MemArg) throws { - let (prefix, opcode): (UInt8?, UInt8) - switch load { - case .i32Load: (prefix, opcode) = (nil, 0x28) - case .i64Load: (prefix, opcode) = (nil, 0x29) - case .f32Load: (prefix, opcode) = (nil, 0x2A) - case .f64Load: (prefix, opcode) = (nil, 0x2B) - case .i32Load8S: (prefix, opcode) = (nil, 0x2C) - case .i32Load8U: (prefix, opcode) = (nil, 0x2D) - case .i32Load16S: (prefix, opcode) = (nil, 0x2E) - case .i32Load16U: (prefix, opcode) = (nil, 0x2F) - case .i64Load8S: (prefix, opcode) = (nil, 0x30) - case .i64Load8U: (prefix, opcode) = (nil, 0x31) - case .i64Load16S: (prefix, opcode) = (nil, 0x32) - case .i64Load16U: (prefix, opcode) = (nil, 0x33) - case .i64Load32S: (prefix, opcode) = (nil, 0x34) - case .i64Load32U: (prefix, opcode) = (nil, 0x35) - } - - try encodeInstruction(opcode, prefix) - try encodeImmediates(memarg: memarg) - } - mutating func visitStore(_ store: Instruction.Store, memarg: MemArg) throws { - let (prefix, opcode): (UInt8?, UInt8) - switch store { - case .i32Store: (prefix, opcode) = (nil, 0x36) - case .i64Store: (prefix, opcode) = (nil, 0x37) - case .f32Store: (prefix, opcode) = (nil, 0x38) - case .f64Store: (prefix, opcode) = (nil, 0x39) - case .i32Store8: (prefix, opcode) = (nil, 0x3A) - case .i32Store16: (prefix, opcode) = (nil, 0x3B) - case .i64Store8: (prefix, opcode) = (nil, 0x3C) - case .i64Store16: (prefix, opcode) = (nil, 0x3D) - case .i64Store32: (prefix, opcode) = (nil, 0x3E) - } - - try encodeInstruction(opcode, prefix) - 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 visitCmp(_ cmp: Instruction.Cmp) throws { - let (prefix, opcode): (UInt8?, UInt8) - switch cmp { - case .i32Eq: (prefix, opcode) = (nil, 0x46) - case .i32Ne: (prefix, opcode) = (nil, 0x47) - case .i32LtS: (prefix, opcode) = (nil, 0x48) - case .i32LtU: (prefix, opcode) = (nil, 0x49) - case .i32GtS: (prefix, opcode) = (nil, 0x4A) - case .i32GtU: (prefix, opcode) = (nil, 0x4B) - case .i32LeS: (prefix, opcode) = (nil, 0x4C) - case .i32LeU: (prefix, opcode) = (nil, 0x4D) - case .i32GeS: (prefix, opcode) = (nil, 0x4E) - case .i32GeU: (prefix, opcode) = (nil, 0x4F) - case .i64Eq: (prefix, opcode) = (nil, 0x51) - case .i64Ne: (prefix, opcode) = (nil, 0x52) - case .i64LtS: (prefix, opcode) = (nil, 0x53) - case .i64LtU: (prefix, opcode) = (nil, 0x54) - case .i64GtS: (prefix, opcode) = (nil, 0x55) - case .i64GtU: (prefix, opcode) = (nil, 0x56) - case .i64LeS: (prefix, opcode) = (nil, 0x57) - case .i64LeU: (prefix, opcode) = (nil, 0x58) - case .i64GeS: (prefix, opcode) = (nil, 0x59) - case .i64GeU: (prefix, opcode) = (nil, 0x5A) - case .f32Eq: (prefix, opcode) = (nil, 0x5B) - case .f32Ne: (prefix, opcode) = (nil, 0x5C) - case .f32Lt: (prefix, opcode) = (nil, 0x5D) - case .f32Gt: (prefix, opcode) = (nil, 0x5E) - case .f32Le: (prefix, opcode) = (nil, 0x5F) - case .f32Ge: (prefix, opcode) = (nil, 0x60) - case .f64Eq: (prefix, opcode) = (nil, 0x61) - case .f64Ne: (prefix, opcode) = (nil, 0x62) - case .f64Lt: (prefix, opcode) = (nil, 0x63) - case .f64Gt: (prefix, opcode) = (nil, 0x64) - case .f64Le: (prefix, opcode) = (nil, 0x65) - case .f64Ge: (prefix, opcode) = (nil, 0x66) - } - - try encodeInstruction(opcode, prefix) - } - mutating func visitI64Eqz() throws { try encodeInstruction(0x50, nil) } - mutating func visitUnary(_ unary: Instruction.Unary) throws { - let (prefix, opcode): (UInt8?, UInt8) - switch unary { - case .i32Clz: (prefix, opcode) = (nil, 0x67) - case .i32Ctz: (prefix, opcode) = (nil, 0x68) - case .i32Popcnt: (prefix, opcode) = (nil, 0x69) - case .i64Clz: (prefix, opcode) = (nil, 0x79) - case .i64Ctz: (prefix, opcode) = (nil, 0x7A) - case .i64Popcnt: (prefix, opcode) = (nil, 0x7B) - case .f32Abs: (prefix, opcode) = (nil, 0x8B) - case .f32Neg: (prefix, opcode) = (nil, 0x8C) - case .f32Ceil: (prefix, opcode) = (nil, 0x8D) - case .f32Floor: (prefix, opcode) = (nil, 0x8E) - case .f32Trunc: (prefix, opcode) = (nil, 0x8F) - case .f32Nearest: (prefix, opcode) = (nil, 0x90) - case .f32Sqrt: (prefix, opcode) = (nil, 0x91) - case .f64Abs: (prefix, opcode) = (nil, 0x99) - case .f64Neg: (prefix, opcode) = (nil, 0x9A) - case .f64Ceil: (prefix, opcode) = (nil, 0x9B) - case .f64Floor: (prefix, opcode) = (nil, 0x9C) - case .f64Trunc: (prefix, opcode) = (nil, 0x9D) - case .f64Nearest: (prefix, opcode) = (nil, 0x9E) - case .f64Sqrt: (prefix, opcode) = (nil, 0x9F) - case .i32Extend8S: (prefix, opcode) = (nil, 0xC0) - case .i32Extend16S: (prefix, opcode) = (nil, 0xC1) - case .i64Extend8S: (prefix, opcode) = (nil, 0xC2) - case .i64Extend16S: (prefix, opcode) = (nil, 0xC3) - case .i64Extend32S: (prefix, opcode) = (nil, 0xC4) - } - - try encodeInstruction(opcode, prefix) - } - mutating func visitBinary(_ binary: Instruction.Binary) throws { - let (prefix, opcode): (UInt8?, UInt8) - switch binary { - case .i32Add: (prefix, opcode) = (nil, 0x6A) - case .i32Sub: (prefix, opcode) = (nil, 0x6B) - case .i32Mul: (prefix, opcode) = (nil, 0x6C) - case .i32DivS: (prefix, opcode) = (nil, 0x6D) - case .i32DivU: (prefix, opcode) = (nil, 0x6E) - case .i32RemS: (prefix, opcode) = (nil, 0x6F) - case .i32RemU: (prefix, opcode) = (nil, 0x70) - case .i32And: (prefix, opcode) = (nil, 0x71) - case .i32Or: (prefix, opcode) = (nil, 0x72) - case .i32Xor: (prefix, opcode) = (nil, 0x73) - case .i32Shl: (prefix, opcode) = (nil, 0x74) - case .i32ShrS: (prefix, opcode) = (nil, 0x75) - case .i32ShrU: (prefix, opcode) = (nil, 0x76) - case .i32Rotl: (prefix, opcode) = (nil, 0x77) - case .i32Rotr: (prefix, opcode) = (nil, 0x78) - case .i64Add: (prefix, opcode) = (nil, 0x7C) - case .i64Sub: (prefix, opcode) = (nil, 0x7D) - case .i64Mul: (prefix, opcode) = (nil, 0x7E) - case .i64DivS: (prefix, opcode) = (nil, 0x7F) - case .i64DivU: (prefix, opcode) = (nil, 0x80) - case .i64RemS: (prefix, opcode) = (nil, 0x81) - case .i64RemU: (prefix, opcode) = (nil, 0x82) - case .i64And: (prefix, opcode) = (nil, 0x83) - case .i64Or: (prefix, opcode) = (nil, 0x84) - case .i64Xor: (prefix, opcode) = (nil, 0x85) - case .i64Shl: (prefix, opcode) = (nil, 0x86) - case .i64ShrS: (prefix, opcode) = (nil, 0x87) - case .i64ShrU: (prefix, opcode) = (nil, 0x88) - case .i64Rotl: (prefix, opcode) = (nil, 0x89) - case .i64Rotr: (prefix, opcode) = (nil, 0x8A) - case .f32Add: (prefix, opcode) = (nil, 0x92) - case .f32Sub: (prefix, opcode) = (nil, 0x93) - case .f32Mul: (prefix, opcode) = (nil, 0x94) - case .f32Div: (prefix, opcode) = (nil, 0x95) - case .f32Min: (prefix, opcode) = (nil, 0x96) - case .f32Max: (prefix, opcode) = (nil, 0x97) - case .f32Copysign: (prefix, opcode) = (nil, 0x98) - case .f64Add: (prefix, opcode) = (nil, 0xA0) - case .f64Sub: (prefix, opcode) = (nil, 0xA1) - case .f64Mul: (prefix, opcode) = (nil, 0xA2) - case .f64Div: (prefix, opcode) = (nil, 0xA3) - case .f64Min: (prefix, opcode) = (nil, 0xA4) - case .f64Max: (prefix, opcode) = (nil, 0xA5) - case .f64Copysign: (prefix, opcode) = (nil, 0xA6) - } - - try encodeInstruction(opcode, prefix) - } - mutating func visitConversion(_ conversion: Instruction.Conversion) throws { - let (prefix, opcode): (UInt8?, UInt8) - switch conversion { - case .i32WrapI64: (prefix, opcode) = (nil, 0xA7) - case .i32TruncF32S: (prefix, opcode) = (nil, 0xA8) - case .i32TruncF32U: (prefix, opcode) = (nil, 0xA9) - case .i32TruncF64S: (prefix, opcode) = (nil, 0xAA) - case .i32TruncF64U: (prefix, opcode) = (nil, 0xAB) - case .i64ExtendI32S: (prefix, opcode) = (nil, 0xAC) - case .i64ExtendI32U: (prefix, opcode) = (nil, 0xAD) - case .i64TruncF32S: (prefix, opcode) = (nil, 0xAE) - case .i64TruncF32U: (prefix, opcode) = (nil, 0xAF) - case .i64TruncF64S: (prefix, opcode) = (nil, 0xB0) - case .i64TruncF64U: (prefix, opcode) = (nil, 0xB1) - case .f32ConvertI32S: (prefix, opcode) = (nil, 0xB2) - case .f32ConvertI32U: (prefix, opcode) = (nil, 0xB3) - case .f32ConvertI64S: (prefix, opcode) = (nil, 0xB4) - case .f32ConvertI64U: (prefix, opcode) = (nil, 0xB5) - case .f32DemoteF64: (prefix, opcode) = (nil, 0xB6) - case .f64ConvertI32S: (prefix, opcode) = (nil, 0xB7) - case .f64ConvertI32U: (prefix, opcode) = (nil, 0xB8) - case .f64ConvertI64S: (prefix, opcode) = (nil, 0xB9) - case .f64ConvertI64U: (prefix, opcode) = (nil, 0xBA) - case .f64PromoteF32: (prefix, opcode) = (nil, 0xBB) - case .i32ReinterpretF32: (prefix, opcode) = (nil, 0xBC) - case .i64ReinterpretF64: (prefix, opcode) = (nil, 0xBD) - case .f32ReinterpretI32: (prefix, opcode) = (nil, 0xBE) - case .f64ReinterpretI64: (prefix, opcode) = (nil, 0xBF) - case .i32TruncSatF32S: (prefix, opcode) = (0xFC, 0x00) - case .i32TruncSatF32U: (prefix, opcode) = (0xFC, 0x01) - case .i32TruncSatF64S: (prefix, opcode) = (0xFC, 0x02) - case .i32TruncSatF64U: (prefix, opcode) = (0xFC, 0x03) - case .i64TruncSatF32S: (prefix, opcode) = (0xFC, 0x04) - case .i64TruncSatF32U: (prefix, opcode) = (0xFC, 0x05) - case .i64TruncSatF64S: (prefix, opcode) = (0xFC, 0x06) - case .i64TruncSatF64U: (prefix, opcode) = (0xFC, 0x07) - } - - try encodeInstruction(opcode, prefix) - } - 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) - } -} diff --git a/Sources/WAT/ParseInstruction.swift b/Sources/WAT/ParseTextInstruction.swift similarity index 100% rename from Sources/WAT/ParseInstruction.swift rename to Sources/WAT/ParseTextInstruction.swift diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift new file mode 100644 index 00000000..488bbb34 --- /dev/null +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -0,0 +1,561 @@ +// swift-format-ignore-file +//// Automatically generated by Utilities/Sources/WasmGen.swift +//// DO NOT EDIT DIRECTLY + +import WasmTypes + +@usableFromInline +protocol BinaryInstructionDecoder { + /// Claim the next byte to be decoded + @inlinable func claimNextByte() throws -> UInt8 + /// Visit unknown instruction + @inlinable func visitUnknown(_ opcode: [UInt8]) throws + /// Decode `block` immediates + @inlinable mutating func visitBlock() throws -> BlockType + /// Decode `loop` immediates + @inlinable mutating func visitLoop() throws -> BlockType + /// Decode `if` immediates + @inlinable mutating func visitIf() throws -> BlockType + /// Decode `br` immediates + @inlinable mutating func visitBr() throws -> UInt32 + /// Decode `br_if` immediates + @inlinable mutating func visitBrIf() throws -> UInt32 + /// Decode `br_table` immediates + @inlinable mutating func visitBrTable() throws -> BrTable + /// Decode `call` immediates + @inlinable mutating func visitCall() throws -> UInt32 + /// Decode `call_indirect` immediates + @inlinable mutating func visitCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) + /// Decode `typedSelect` immediates + @inlinable mutating func visitTypedSelect() throws -> ValueType + /// Decode `local.get` immediates + @inlinable mutating func visitLocalGet() throws -> UInt32 + /// Decode `local.set` immediates + @inlinable mutating func visitLocalSet() throws -> UInt32 + /// Decode `local.tee` immediates + @inlinable mutating func visitLocalTee() throws -> UInt32 + /// Decode `global.get` immediates + @inlinable mutating func visitGlobalGet() throws -> UInt32 + /// Decode `global.set` immediates + @inlinable mutating func visitGlobalSet() throws -> UInt32 + /// Decode `load` category immediates + @inlinable mutating func visitLoad(_: Instruction.Load) throws -> MemArg + /// Decode `store` category immediates + @inlinable mutating func visitStore(_: Instruction.Store) throws -> MemArg + /// Decode `memory.size` immediates + @inlinable mutating func visitMemorySize() throws -> UInt32 + /// Decode `memory.grow` immediates + @inlinable mutating func visitMemoryGrow() throws -> UInt32 + /// Decode `i32.const` immediates + @inlinable mutating func visitI32Const() throws -> Int32 + /// Decode `i64.const` immediates + @inlinable mutating func visitI64Const() throws -> Int64 + /// Decode `f32.const` immediates + @inlinable mutating func visitF32Const() throws -> IEEE754.Float32 + /// Decode `f64.const` immediates + @inlinable mutating func visitF64Const() throws -> IEEE754.Float64 + /// Decode `ref.null` immediates + @inlinable mutating func visitRefNull() throws -> ReferenceType + /// Decode `ref.func` immediates + @inlinable mutating func visitRefFunc() throws -> UInt32 + /// Decode `memory.init` immediates + @inlinable mutating func visitMemoryInit() throws -> UInt32 + /// Decode `data.drop` immediates + @inlinable mutating func visitDataDrop() throws -> UInt32 + /// Decode `memory.copy` immediates + @inlinable mutating func visitMemoryCopy() throws -> (dstMem: UInt32, srcMem: UInt32) + /// Decode `memory.fill` immediates + @inlinable mutating func visitMemoryFill() throws -> UInt32 + /// Decode `table.init` immediates + @inlinable mutating func visitTableInit() throws -> (elemIndex: UInt32, table: UInt32) + /// Decode `elem.drop` immediates + @inlinable mutating func visitElemDrop() throws -> UInt32 + /// Decode `table.copy` immediates + @inlinable mutating func visitTableCopy() throws -> (dstTable: UInt32, srcTable: UInt32) + /// Decode `table.fill` immediates + @inlinable mutating func visitTableFill() throws -> UInt32 + /// Decode `table.get` immediates + @inlinable mutating func visitTableGet() throws -> UInt32 + /// Decode `table.set` immediates + @inlinable mutating func visitTableSet() throws -> UInt32 + /// Decode `table.grow` immediates + @inlinable mutating func visitTableGrow() throws -> UInt32 + /// Decode `table.size` immediates + @inlinable mutating func visitTableSize() throws -> UInt32 +} +@inlinable +func parseBinaryInstruction(visitor: inout V, decoder: inout D) throws -> Bool { + let opcode0 = try decoder.claimNextByte() + switch opcode0 { + case 0x00: + try visitor.visitUnreachable() + case 0x01: + try visitor.visitNop() + case 0x02: + let (blockType) = try decoder.visitBlock() + try visitor.visitBlock(blockType: blockType) + case 0x03: + let (blockType) = try decoder.visitLoop() + try visitor.visitLoop(blockType: blockType) + case 0x04: + let (blockType) = try decoder.visitIf() + try visitor.visitIf(blockType: blockType) + case 0x05: + try visitor.visitElse() + case 0x0B: + try visitor.visitEnd() + return true + case 0x0C: + let (relativeDepth) = try decoder.visitBr() + try visitor.visitBr(relativeDepth: relativeDepth) + case 0x0D: + let (relativeDepth) = try decoder.visitBrIf() + try visitor.visitBrIf(relativeDepth: relativeDepth) + case 0x0E: + let (targets) = try decoder.visitBrTable() + try visitor.visitBrTable(targets: targets) + case 0x0F: + try visitor.visitReturn() + case 0x10: + let (functionIndex) = try decoder.visitCall() + try visitor.visitCall(functionIndex: functionIndex) + case 0x11: + let (typeIndex, tableIndex) = try decoder.visitCallIndirect() + try visitor.visitCallIndirect(typeIndex: typeIndex, tableIndex: tableIndex) + case 0x1A: + try visitor.visitDrop() + case 0x1B: + try visitor.visitSelect() + case 0x1C: + let (type) = try decoder.visitTypedSelect() + try visitor.visitTypedSelect(type: type) + case 0x20: + let (localIndex) = try decoder.visitLocalGet() + try visitor.visitLocalGet(localIndex: localIndex) + case 0x21: + let (localIndex) = try decoder.visitLocalSet() + try visitor.visitLocalSet(localIndex: localIndex) + case 0x22: + let (localIndex) = try decoder.visitLocalTee() + try visitor.visitLocalTee(localIndex: localIndex) + case 0x23: + let (globalIndex) = try decoder.visitGlobalGet() + try visitor.visitGlobalGet(globalIndex: globalIndex) + case 0x24: + let (globalIndex) = try decoder.visitGlobalSet() + try visitor.visitGlobalSet(globalIndex: globalIndex) + case 0x25: + let (table) = try decoder.visitTableGet() + try visitor.visitTableGet(table: table) + case 0x26: + let (table) = try decoder.visitTableSet() + try visitor.visitTableSet(table: table) + case 0x28: + let (memarg) = try decoder.visitLoad(.i32Load) + try visitor.visitLoad(.i32Load, memarg: memarg) + case 0x29: + let (memarg) = try decoder.visitLoad(.i64Load) + try visitor.visitLoad(.i64Load, memarg: memarg) + case 0x2A: + let (memarg) = try decoder.visitLoad(.f32Load) + try visitor.visitLoad(.f32Load, memarg: memarg) + case 0x2B: + let (memarg) = try decoder.visitLoad(.f64Load) + try visitor.visitLoad(.f64Load, memarg: memarg) + case 0x2C: + let (memarg) = try decoder.visitLoad(.i32Load8S) + try visitor.visitLoad(.i32Load8S, memarg: memarg) + case 0x2D: + let (memarg) = try decoder.visitLoad(.i32Load8U) + try visitor.visitLoad(.i32Load8U, memarg: memarg) + case 0x2E: + let (memarg) = try decoder.visitLoad(.i32Load16S) + try visitor.visitLoad(.i32Load16S, memarg: memarg) + case 0x2F: + let (memarg) = try decoder.visitLoad(.i32Load16U) + try visitor.visitLoad(.i32Load16U, memarg: memarg) + case 0x30: + let (memarg) = try decoder.visitLoad(.i64Load8S) + try visitor.visitLoad(.i64Load8S, memarg: memarg) + case 0x31: + let (memarg) = try decoder.visitLoad(.i64Load8U) + try visitor.visitLoad(.i64Load8U, memarg: memarg) + case 0x32: + let (memarg) = try decoder.visitLoad(.i64Load16S) + try visitor.visitLoad(.i64Load16S, memarg: memarg) + case 0x33: + let (memarg) = try decoder.visitLoad(.i64Load16U) + try visitor.visitLoad(.i64Load16U, memarg: memarg) + case 0x34: + let (memarg) = try decoder.visitLoad(.i64Load32S) + try visitor.visitLoad(.i64Load32S, memarg: memarg) + case 0x35: + let (memarg) = try decoder.visitLoad(.i64Load32U) + try visitor.visitLoad(.i64Load32U, memarg: memarg) + case 0x36: + let (memarg) = try decoder.visitStore(.i32Store) + try visitor.visitStore(.i32Store, memarg: memarg) + case 0x37: + let (memarg) = try decoder.visitStore(.i64Store) + try visitor.visitStore(.i64Store, memarg: memarg) + case 0x38: + let (memarg) = try decoder.visitStore(.f32Store) + try visitor.visitStore(.f32Store, memarg: memarg) + case 0x39: + let (memarg) = try decoder.visitStore(.f64Store) + try visitor.visitStore(.f64Store, memarg: memarg) + case 0x3A: + let (memarg) = try decoder.visitStore(.i32Store8) + try visitor.visitStore(.i32Store8, memarg: memarg) + case 0x3B: + let (memarg) = try decoder.visitStore(.i32Store16) + try visitor.visitStore(.i32Store16, memarg: memarg) + case 0x3C: + let (memarg) = try decoder.visitStore(.i64Store8) + try visitor.visitStore(.i64Store8, memarg: memarg) + case 0x3D: + let (memarg) = try decoder.visitStore(.i64Store16) + try visitor.visitStore(.i64Store16, memarg: memarg) + case 0x3E: + let (memarg) = try decoder.visitStore(.i64Store32) + try visitor.visitStore(.i64Store32, memarg: memarg) + case 0x3F: + let (memory) = try decoder.visitMemorySize() + try visitor.visitMemorySize(memory: memory) + case 0x40: + let (memory) = try decoder.visitMemoryGrow() + try visitor.visitMemoryGrow(memory: memory) + case 0x41: + let (value) = try decoder.visitI32Const() + try visitor.visitI32Const(value: value) + case 0x42: + let (value) = try decoder.visitI64Const() + try visitor.visitI64Const(value: value) + case 0x43: + let (value) = try decoder.visitF32Const() + try visitor.visitF32Const(value: value) + case 0x44: + let (value) = try decoder.visitF64Const() + try visitor.visitF64Const(value: value) + case 0x45: + try visitor.visitI32Eqz() + case 0x46: + try visitor.visitCmp(.i32Eq) + case 0x47: + try visitor.visitCmp(.i32Ne) + case 0x48: + try visitor.visitCmp(.i32LtS) + case 0x49: + try visitor.visitCmp(.i32LtU) + case 0x4A: + try visitor.visitCmp(.i32GtS) + case 0x4B: + try visitor.visitCmp(.i32GtU) + case 0x4C: + try visitor.visitCmp(.i32LeS) + case 0x4D: + try visitor.visitCmp(.i32LeU) + case 0x4E: + try visitor.visitCmp(.i32GeS) + case 0x4F: + try visitor.visitCmp(.i32GeU) + case 0x50: + try visitor.visitI64Eqz() + case 0x51: + try visitor.visitCmp(.i64Eq) + case 0x52: + try visitor.visitCmp(.i64Ne) + case 0x53: + try visitor.visitCmp(.i64LtS) + case 0x54: + try visitor.visitCmp(.i64LtU) + case 0x55: + try visitor.visitCmp(.i64GtS) + case 0x56: + try visitor.visitCmp(.i64GtU) + case 0x57: + try visitor.visitCmp(.i64LeS) + case 0x58: + try visitor.visitCmp(.i64LeU) + case 0x59: + try visitor.visitCmp(.i64GeS) + case 0x5A: + try visitor.visitCmp(.i64GeU) + case 0x5B: + try visitor.visitCmp(.f32Eq) + case 0x5C: + try visitor.visitCmp(.f32Ne) + case 0x5D: + try visitor.visitCmp(.f32Lt) + case 0x5E: + try visitor.visitCmp(.f32Gt) + case 0x5F: + try visitor.visitCmp(.f32Le) + case 0x60: + try visitor.visitCmp(.f32Ge) + case 0x61: + try visitor.visitCmp(.f64Eq) + case 0x62: + try visitor.visitCmp(.f64Ne) + case 0x63: + try visitor.visitCmp(.f64Lt) + case 0x64: + try visitor.visitCmp(.f64Gt) + case 0x65: + try visitor.visitCmp(.f64Le) + case 0x66: + try visitor.visitCmp(.f64Ge) + case 0x67: + try visitor.visitUnary(.i32Clz) + case 0x68: + try visitor.visitUnary(.i32Ctz) + case 0x69: + try visitor.visitUnary(.i32Popcnt) + case 0x6A: + try visitor.visitBinary(.i32Add) + case 0x6B: + try visitor.visitBinary(.i32Sub) + case 0x6C: + try visitor.visitBinary(.i32Mul) + case 0x6D: + try visitor.visitBinary(.i32DivS) + case 0x6E: + try visitor.visitBinary(.i32DivU) + case 0x6F: + try visitor.visitBinary(.i32RemS) + case 0x70: + try visitor.visitBinary(.i32RemU) + case 0x71: + try visitor.visitBinary(.i32And) + case 0x72: + try visitor.visitBinary(.i32Or) + case 0x73: + try visitor.visitBinary(.i32Xor) + case 0x74: + try visitor.visitBinary(.i32Shl) + case 0x75: + try visitor.visitBinary(.i32ShrS) + case 0x76: + try visitor.visitBinary(.i32ShrU) + case 0x77: + try visitor.visitBinary(.i32Rotl) + case 0x78: + try visitor.visitBinary(.i32Rotr) + case 0x79: + try visitor.visitUnary(.i64Clz) + case 0x7A: + try visitor.visitUnary(.i64Ctz) + case 0x7B: + try visitor.visitUnary(.i64Popcnt) + case 0x7C: + try visitor.visitBinary(.i64Add) + case 0x7D: + try visitor.visitBinary(.i64Sub) + case 0x7E: + try visitor.visitBinary(.i64Mul) + case 0x7F: + try visitor.visitBinary(.i64DivS) + case 0x80: + try visitor.visitBinary(.i64DivU) + case 0x81: + try visitor.visitBinary(.i64RemS) + case 0x82: + try visitor.visitBinary(.i64RemU) + case 0x83: + try visitor.visitBinary(.i64And) + case 0x84: + try visitor.visitBinary(.i64Or) + case 0x85: + try visitor.visitBinary(.i64Xor) + case 0x86: + try visitor.visitBinary(.i64Shl) + case 0x87: + try visitor.visitBinary(.i64ShrS) + case 0x88: + try visitor.visitBinary(.i64ShrU) + case 0x89: + try visitor.visitBinary(.i64Rotl) + case 0x8A: + try visitor.visitBinary(.i64Rotr) + case 0x8B: + try visitor.visitUnary(.f32Abs) + case 0x8C: + try visitor.visitUnary(.f32Neg) + case 0x8D: + try visitor.visitUnary(.f32Ceil) + case 0x8E: + try visitor.visitUnary(.f32Floor) + case 0x8F: + try visitor.visitUnary(.f32Trunc) + case 0x90: + try visitor.visitUnary(.f32Nearest) + case 0x91: + try visitor.visitUnary(.f32Sqrt) + case 0x92: + try visitor.visitBinary(.f32Add) + case 0x93: + try visitor.visitBinary(.f32Sub) + case 0x94: + try visitor.visitBinary(.f32Mul) + case 0x95: + try visitor.visitBinary(.f32Div) + case 0x96: + try visitor.visitBinary(.f32Min) + case 0x97: + try visitor.visitBinary(.f32Max) + case 0x98: + try visitor.visitBinary(.f32Copysign) + case 0x99: + try visitor.visitUnary(.f64Abs) + case 0x9A: + try visitor.visitUnary(.f64Neg) + case 0x9B: + try visitor.visitUnary(.f64Ceil) + case 0x9C: + try visitor.visitUnary(.f64Floor) + case 0x9D: + try visitor.visitUnary(.f64Trunc) + case 0x9E: + try visitor.visitUnary(.f64Nearest) + case 0x9F: + try visitor.visitUnary(.f64Sqrt) + case 0xA0: + try visitor.visitBinary(.f64Add) + case 0xA1: + try visitor.visitBinary(.f64Sub) + case 0xA2: + try visitor.visitBinary(.f64Mul) + case 0xA3: + try visitor.visitBinary(.f64Div) + case 0xA4: + try visitor.visitBinary(.f64Min) + case 0xA5: + try visitor.visitBinary(.f64Max) + case 0xA6: + try visitor.visitBinary(.f64Copysign) + case 0xA7: + try visitor.visitConversion(.i32WrapI64) + case 0xA8: + try visitor.visitConversion(.i32TruncF32S) + case 0xA9: + try visitor.visitConversion(.i32TruncF32U) + case 0xAA: + try visitor.visitConversion(.i32TruncF64S) + case 0xAB: + try visitor.visitConversion(.i32TruncF64U) + case 0xAC: + try visitor.visitConversion(.i64ExtendI32S) + case 0xAD: + try visitor.visitConversion(.i64ExtendI32U) + case 0xAE: + try visitor.visitConversion(.i64TruncF32S) + case 0xAF: + try visitor.visitConversion(.i64TruncF32U) + case 0xB0: + try visitor.visitConversion(.i64TruncF64S) + case 0xB1: + try visitor.visitConversion(.i64TruncF64U) + case 0xB2: + try visitor.visitConversion(.f32ConvertI32S) + case 0xB3: + try visitor.visitConversion(.f32ConvertI32U) + case 0xB4: + try visitor.visitConversion(.f32ConvertI64S) + case 0xB5: + try visitor.visitConversion(.f32ConvertI64U) + case 0xB6: + try visitor.visitConversion(.f32DemoteF64) + case 0xB7: + try visitor.visitConversion(.f64ConvertI32S) + case 0xB8: + try visitor.visitConversion(.f64ConvertI32U) + case 0xB9: + try visitor.visitConversion(.f64ConvertI64S) + case 0xBA: + try visitor.visitConversion(.f64ConvertI64U) + case 0xBB: + try visitor.visitConversion(.f64PromoteF32) + case 0xBC: + try visitor.visitConversion(.i32ReinterpretF32) + case 0xBD: + try visitor.visitConversion(.i64ReinterpretF64) + case 0xBE: + try visitor.visitConversion(.f32ReinterpretI32) + case 0xBF: + try visitor.visitConversion(.f64ReinterpretI64) + case 0xC0: + try visitor.visitUnary(.i32Extend8S) + case 0xC1: + try visitor.visitUnary(.i32Extend16S) + case 0xC2: + try visitor.visitUnary(.i64Extend8S) + case 0xC3: + try visitor.visitUnary(.i64Extend16S) + case 0xC4: + try visitor.visitUnary(.i64Extend32S) + case 0xD0: + let (type) = try decoder.visitRefNull() + try visitor.visitRefNull(type: type) + case 0xD1: + try visitor.visitRefIsNull() + case 0xD2: + let (functionIndex) = try decoder.visitRefFunc() + try visitor.visitRefFunc(functionIndex: functionIndex) + case 0xFC: + + let opcode1 = try decoder.claimNextByte() + switch opcode1 { + case 0x00: + try visitor.visitConversion(.i32TruncSatF32S) + case 0x01: + try visitor.visitConversion(.i32TruncSatF32U) + case 0x02: + try visitor.visitConversion(.i32TruncSatF64S) + case 0x03: + try visitor.visitConversion(.i32TruncSatF64U) + case 0x04: + try visitor.visitConversion(.i64TruncSatF32S) + case 0x05: + try visitor.visitConversion(.i64TruncSatF32U) + case 0x06: + try visitor.visitConversion(.i64TruncSatF64S) + case 0x07: + try visitor.visitConversion(.i64TruncSatF64U) + case 0x08: + let (dataIndex) = try decoder.visitMemoryInit() + try visitor.visitMemoryInit(dataIndex: dataIndex) + case 0x09: + let (dataIndex) = try decoder.visitDataDrop() + try visitor.visitDataDrop(dataIndex: dataIndex) + case 0x0A: + let (dstMem, srcMem) = try decoder.visitMemoryCopy() + try visitor.visitMemoryCopy(dstMem: dstMem, srcMem: srcMem) + case 0x0B: + let (memory) = try decoder.visitMemoryFill() + try visitor.visitMemoryFill(memory: memory) + case 0x0C: + let (elemIndex, table) = try decoder.visitTableInit() + try visitor.visitTableInit(elemIndex: elemIndex, table: table) + case 0x0D: + let (elemIndex) = try decoder.visitElemDrop() + try visitor.visitElemDrop(elemIndex: elemIndex) + case 0x0E: + let (dstTable, srcTable) = try decoder.visitTableCopy() + try visitor.visitTableCopy(dstTable: dstTable, srcTable: srcTable) + case 0x0F: + let (table) = try decoder.visitTableGrow() + try visitor.visitTableGrow(table: table) + case 0x10: + let (table) = try decoder.visitTableSize() + try visitor.visitTableSize(table: table) + case 0x11: + let (table) = try decoder.visitTableFill() + try visitor.visitTableFill(table: table) + default: + try decoder.visitUnknown([opcode0, opcode1]) + } + default: + try decoder.visitUnknown([opcode0]) + } + return false +} diff --git a/Sources/WasmParser/CMakeLists.txt b/Sources/WasmParser/CMakeLists.txt index 3428378c..b5b05612 100644 --- a/Sources/WasmParser/CMakeLists.txt +++ b/Sources/WasmParser/CMakeLists.txt @@ -2,7 +2,7 @@ add_wasmkit_library(WasmParser Stream/ByteStream.swift Stream/FileHandleStream.swift Stream/Stream.swift - InstructionCode.swift + BinaryInstructionDecoder.swift InstructionVisitor.swift LEB.swift ParsingLimits.swift diff --git a/Sources/WasmParser/InstructionCode.swift b/Sources/WasmParser/InstructionCode.swift deleted file mode 100644 index 67ab4e62..00000000 --- a/Sources/WasmParser/InstructionCode.swift +++ /dev/null @@ -1,209 +0,0 @@ -@usableFromInline -enum InstructionCode: UInt8 { - case unreachable = 0x00 - case nop = 0x01 - case block = 0x02 - case loop = 0x03 - case `if` = 0x04 - case `else` = 0x05 - - case end = 0x0B - case br - case br_if - case br_table - case `return` - case call - case call_indirect - - case drop = 0x1A - case select = 0x1B - case typed_select = 0x1C - - case local_get = 0x20 - case local_set = 0x21 - case local_tee = 0x22 - - case global_get = 0x23 - case global_set = 0x24 - - case table_get = 0x25 - case table_set = 0x26 - - case i32_load = 0x28 - case i64_load = 0x29 - case f32_load = 0x2A - case f64_load = 0x2B - - case i32_load8_s = 0x2C - case i32_load8_u - case i32_load16_s - case i32_load16_u - case i64_load8_s - case i64_load8_u - case i64_load16_s - case i64_load16_u - case i64_load32_s - case i64_load32_u - - case i32_store = 0x36 - case i64_store = 0x37 - case f32_store = 0x38 - case f64_store = 0x39 - case i32_store8 = 0x3A - case i32_store16 = 0x3B - case i64_store8 = 0x3C - case i64_store16 = 0x3D - case i64_store32 = 0x3E - - case memory_size = 0x3F - case memory_grow = 0x40 - - case i32_const - case i64_const - case f32_const - case f64_const - - case i32_eqz - case i32_eq - case i32_ne - case i32_lt_s - case i32_lt_u - case i32_gt_s - case i32_gt_u - case i32_le_s - case i32_le_u - case i32_ge_s - case i32_ge_u - - case i64_eqz - case i64_eq - case i64_ne - case i64_lt_s - case i64_lt_u - case i64_gt_s - case i64_gt_u - case i64_le_s - case i64_le_u - case i64_ge_s - case i64_ge_u - - case f32_eq - case f32_ne - case f32_lt - case f32_gt - case f32_le - case f32_ge - - case f64_eq - case f64_ne - case f64_lt - case f64_gt - case f64_le - case f64_ge - - case i32_clz - case i32_ctz - case i32_popcnt - case i32_add - case i32_sub - case i32_mul - case i32_div_s - case i32_div_u - case i32_rem_s - case i32_rem_u - case i32_and - case i32_or - case i32_xor - case i32_shl - case i32_shr_s - case i32_shr_u - case i32_rotl - case i32_rotr - - case i64_clz - case i64_ctz - case i64_popcnt - case i64_add - case i64_sub - case i64_mul - case i64_div_s - case i64_div_u - case i64_rem_s - case i64_rem_u - case i64_and - case i64_or - case i64_xor - case i64_shl - case i64_shr_s - case i64_shr_u - case i64_rotl - case i64_rotr - - case f32_abs - case f32_neg - case f32_ceil - case f32_floor - case f32_trunc - case f32_nearest - case f32_sqrt - case f32_add - case f32_sub - case f32_mul - case f32_div - case f32_min - case f32_max - case f32_copysign - - case f64_abs - case f64_neg - case f64_ceil - case f64_floor - case f64_trunc - case f64_nearest - case f64_sqrt - case f64_add - case f64_sub - case f64_mul - case f64_div - case f64_min - case f64_max - case f64_copysign - - case i32_wrap_i64 = 0xA7 - case i32_trunc_f32_s - case i32_trunc_f32_u - case i32_trunc_f64_s - case i32_trunc_f64_u - case i64_extend_i32_s - case i64_extend_i32_u - case i64_trunc_f32_s - case i64_trunc_f32_u - case i64_trunc_f64_s - case i64_trunc_f64_u - case f32_convert_i32_s - case f32_convert_i32_u - case f32_convert_i64_s - case f32_convert_i64_u - case f32_demote_f64 - case f64_convert_i32_s - case f64_convert_i32_u - case f64_convert_i64_s - case f64_convert_i64_u - case f64_promote_f32 - case i32_reinterpret_f32 = 0xBC - case i64_reinterpret_f64 = 0xBD - case f32_reinterpret_i32 = 0xBE - case f64_reinterpret_i64 = 0xBF - - case i32_extend8_s = 0xC0 - case i32_extend16_s = 0xC1 - case i64_extend8_s = 0xC2 - case i64_extend16_s = 0xC3 - case i64_extend32_s = 0xC4 - - case ref_null = 0xD0 - case ref_is_null = 0xD1 - case ref_func = 0xD2 - - case wasm2InstructionPrefix = 0xFC -} diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 8a7e4c94..312712f1 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -122,18 +122,17 @@ extension Code { /// ```` @inlinable public func parseExpression(visitor: inout V) throws { - let parser = Parser(stream: StaticByteStream(bytes: self.expression), features: self.features) - var lastCode: InstructionCode? + var parser = Parser(stream: StaticByteStream(bytes: self.expression), features: self.features) + var lastIsEnd: Bool? while try !parser.stream.hasReachedEnd() { - lastCode = try parser.parseInstruction(visitor: &visitor) + lastIsEnd = try parser.parseInstruction(visitor: &visitor) } - guard lastCode == .end else { + guard lastIsEnd == true else { throw parser.makeError(.endOpcodeExpected) } } } -// TODO: Move `doParseInstruction` under `ExpressionParser` struct @_documentation(visibility: internal) public struct ExpressionParser { /// The byte offset of the code in the module @@ -143,9 +142,9 @@ public struct ExpressionParser { /// is not a part of the initial `FileHandleStream` buffer let initialStreamOffset: Int @usableFromInline - let parser: Parser + var parser: Parser @usableFromInline - var lastCode: InstructionCode? + var isLastEnd: Bool? public var offset: Int { self.codeOffset + self.parser.offset - self.initialStreamOffset @@ -162,10 +161,10 @@ public struct ExpressionParser { @inlinable public mutating func visit(visitor: inout V) throws -> Bool { - lastCode = try parser.parseInstruction(visitor: &visitor) + isLastEnd = try parser.parseInstruction(visitor: &visitor) let shouldContinue = try !parser.stream.hasReachedEnd() if !shouldContinue { - guard lastCode == .end else { + guard isLastEnd == true else { throw WasmParserError(.endOpcodeExpected, offset: offset) } } @@ -267,11 +266,6 @@ extension WasmParserError.Message { Self("Expected reference type but got \(actual)") } - @usableFromInline static func unimplementedInstruction(_ opcode: UInt8, suffix: UInt32? = nil) -> Self { - let suffixText = suffix.map { " with suffix \($0)" } ?? "" - return Self("Unimplemented instruction: \(opcode)\(suffixText)") - } - @usableFromInline static func unexpectedElementKind(expected: UInt32, actual: UInt32) -> Self { Self("Unexpected element kind: expected \(expected) but got \(actual)") @@ -291,7 +285,7 @@ extension WasmParserError.Message { Self("Section size mismatch: expected \(expected) but got \(actual)") } - @usableFromInline static func illegalOpcode(_ opcode: UInt8) -> Self { + @usableFromInline static func illegalOpcode(_ opcode: [UInt8]) -> Self { Self("Illegal opcode: \(opcode)") } @@ -586,333 +580,147 @@ extension Parser { /// > Note: /// -extension Parser { - @inlinable - func parseInstruction(visitor v: inout V) throws -> InstructionCode { - let rawCode = try stream.consumeAny() - guard let code = InstructionCode(rawValue: rawCode) else { - throw makeError(.illegalOpcode(rawCode)) +extension Parser: BinaryInstructionDecoder { + @inlinable func parseMemoryIndex() throws -> UInt32 { + let zero = try stream.consumeAny() + guard zero == 0x00 else { + throw makeError(.zeroExpected(actual: zero)) } - try doParseInstruction(code: code, visitor: &v) - return code + return 0 } - @inlinable - func doParseInstruction(code: InstructionCode, visitor v: inout V) throws { - switch code { - case .unreachable: return try v.visitUnreachable() - case .nop: return try v.visitNop() - case .block: return try v.visitBlock(blockType: try parseResultType()) - case .loop: return try v.visitLoop(blockType: try parseResultType()) - case .if: return try v.visitIf(blockType: try parseResultType()) - case .else: return try v.visitElse() - case .end: return try v.visitEnd() - case .br: - let label: UInt32 = try parseUnsigned() - return try v.visitBr(relativeDepth: label) - case .br_if: - let label: UInt32 = try parseUnsigned() - return try v.visitBrIf(relativeDepth: label) - case .br_table: - let labelIndices: [UInt32] = try parseVector { try parseUnsigned() } - let labelIndex: UInt32 = try parseUnsigned() - return try v.visitBrTable(targets: BrTable(labelIndices: labelIndices, defaultIndex: labelIndex)) - case .return: - return try v.visitReturn() - case .call: - let index: UInt32 = try parseUnsigned() - return try v.visitCall(functionIndex: index) - case .call_indirect: - let typeIndex: TypeIndex = try parseUnsigned() - if try !features.contains(.referenceTypes) && stream.peek() != 0 { - // Check that reserved byte is zero when reference-types is disabled - throw makeError(.malformedIndirectCall) - } - let tableIndex: TableIndex = try parseUnsigned() - return try v.visitCallIndirect(typeIndex: typeIndex, tableIndex: tableIndex) - case .drop: return try v.visitDrop() - case .select: return try v.visitSelect() - case .typed_select: - let results = try parseVector { try parseValueType() } - guard results.count == 1 else { - throw makeError(.invalidResultArity(expected: 1, actual: results.count)) - } - return try v.visitTypedSelect(type: results[0]) - - case .local_get: - let index: UInt32 = try parseUnsigned() - return try v.visitLocalGet(localIndex: index) - case .local_set: - let index: UInt32 = try parseUnsigned() - return try v.visitLocalSet(localIndex: index) - case .local_tee: - let index: UInt32 = try parseUnsigned() - return try v.visitLocalTee(localIndex: index) - case .global_get: - let index: UInt32 = try parseUnsigned() - return try v.visitGlobalGet(globalIndex: index) - case .global_set: - let index: UInt32 = try parseUnsigned() - return try v.visitGlobalSet(globalIndex: index) - - case .i32_load: return try v.visitLoad(.i32Load, memarg: try parseMemarg()) - case .i64_load: return try v.visitLoad(.i64Load, memarg: try parseMemarg()) - case .f32_load: return try v.visitLoad(.f32Load, memarg: try parseMemarg()) - case .f64_load: return try v.visitLoad(.f64Load, memarg: try parseMemarg()) - case .i32_load8_s: return try v.visitLoad(.i32Load8S, memarg: try parseMemarg()) - case .i32_load8_u: return try v.visitLoad(.i32Load8U, memarg: try parseMemarg()) - case .i32_load16_s: return try v.visitLoad(.i32Load16S, memarg: try parseMemarg()) - case .i32_load16_u: return try v.visitLoad(.i32Load16U, memarg: try parseMemarg()) - case .i64_load8_s: return try v.visitLoad(.i64Load8S, memarg: try parseMemarg()) - case .i64_load8_u: return try v.visitLoad(.i64Load8U, memarg: try parseMemarg()) - case .i64_load16_s: return try v.visitLoad(.i64Load16S, memarg: try parseMemarg()) - case .i64_load16_u: return try v.visitLoad(.i64Load16U, memarg: try parseMemarg()) - case .i64_load32_s: return try v.visitLoad(.i64Load32S, memarg: try parseMemarg()) - case .i64_load32_u: return try v.visitLoad(.i64Load32U, memarg: try parseMemarg()) - case .i32_store: return try v.visitStore(.i32Store, memarg: try parseMemarg()) - case .i64_store: return try v.visitStore(.i64Store, memarg: try parseMemarg()) - case .f32_store: return try v.visitStore(.f32Store, memarg: try parseMemarg()) - case .f64_store: return try v.visitStore(.f64Store, memarg: try parseMemarg()) - case .i32_store8: return try v.visitStore(.i32Store8, memarg: try parseMemarg()) - case .i32_store16: return try v.visitStore(.i32Store16, memarg: try parseMemarg()) - case .i64_store8: return try v.visitStore(.i64Store8, memarg: try parseMemarg()) - case .i64_store16: return try v.visitStore(.i64Store16, memarg: try parseMemarg()) - case .i64_store32: return try v.visitStore(.i64Store32, memarg: try parseMemarg()) - case .memory_size: - let zero = try stream.consumeAny() - guard zero == 0x00 else { - throw makeError(.zeroExpected(actual: zero)) - } - return try v.visitMemorySize(memory: UInt32(zero)) - case .memory_grow: - let zero = try stream.consumeAny() - guard zero == 0x00 else { - throw makeError(.zeroExpected(actual: zero)) - } - return try v.visitMemoryGrow(memory: UInt32(zero)) - - case .i32_const: - let n: UInt32 = try parseInteger() - return try v.visitI32Const(value: Int32(bitPattern: n)) - case .i64_const: - let n: UInt64 = try parseInteger() - return try v.visitI64Const(value: Int64(bitPattern: n)) - case .f32_const: - let n = try parseFloat() - return try v.visitF32Const(value: IEEE754.Float32(bitPattern: n)) - case .f64_const: - let n = try parseDouble() - return try v.visitF64Const(value: IEEE754.Float64(bitPattern: n)) - - case .i32_eqz: return try v.visitI32Eqz() - case .i32_eq: return try v.visitCmp(.i32Eq) - case .i32_ne: return try v.visitCmp(.i32Ne) - case .i32_lt_s: return try v.visitCmp(.i32LtS) - case .i32_lt_u: return try v.visitCmp(.i32LtU) - case .i32_gt_s: return try v.visitCmp(.i32GtS) - case .i32_gt_u: return try v.visitCmp(.i32GtU) - case .i32_le_s: return try v.visitCmp(.i32LeS) - case .i32_le_u: return try v.visitCmp(.i32LeU) - case .i32_ge_s: return try v.visitCmp(.i32GeS) - case .i32_ge_u: return try v.visitCmp(.i32GeU) - - case .i64_eqz: return try v.visitI64Eqz() - case .i64_eq: return try v.visitCmp(.i64Eq) - case .i64_ne: return try v.visitCmp(.i64Ne) - case .i64_lt_s: return try v.visitCmp(.i64LtS) - case .i64_lt_u: return try v.visitCmp(.i64LtU) - case .i64_gt_s: return try v.visitCmp(.i64GtS) - case .i64_gt_u: return try v.visitCmp(.i64GtU) - case .i64_le_s: return try v.visitCmp(.i64LeS) - case .i64_le_u: return try v.visitCmp(.i64LeU) - case .i64_ge_s: return try v.visitCmp(.i64GeS) - case .i64_ge_u: return try v.visitCmp(.i64GeU) - - case .f32_eq: return try v.visitCmp(.f32Eq) - case .f32_ne: return try v.visitCmp(.f32Ne) - case .f32_lt: return try v.visitCmp(.f32Lt) - case .f32_gt: return try v.visitCmp(.f32Gt) - case .f32_le: return try v.visitCmp(.f32Le) - case .f32_ge: return try v.visitCmp(.f32Ge) - - case .f64_eq: return try v.visitCmp(.f64Eq) - case .f64_ne: return try v.visitCmp(.f64Ne) - case .f64_lt: return try v.visitCmp(.f64Lt) - case .f64_gt: return try v.visitCmp(.f64Gt) - case .f64_le: return try v.visitCmp(.f64Le) - case .f64_ge: return try v.visitCmp(.f64Ge) - - case .i32_clz: return try v.visitUnary(.i32Clz) - case .i32_ctz: return try v.visitUnary(.i32Ctz) - case .i32_popcnt: return try v.visitUnary(.i32Popcnt) - case .i32_add: return try v.visitBinary(.i32Add) - case .i32_sub: return try v.visitBinary(.i32Sub) - case .i32_mul: return try v.visitBinary(.i32Mul) - case .i32_div_s: return try v.visitBinary(.i32DivS) - case .i32_div_u: return try v.visitBinary(.i32DivU) - case .i32_rem_s: return try v.visitBinary(.i32RemS) - case .i32_rem_u: return try v.visitBinary(.i32RemU) - case .i32_and: return try v.visitBinary(.i32And) - case .i32_or: return try v.visitBinary(.i32Or) - case .i32_xor: return try v.visitBinary(.i32Xor) - case .i32_shl: return try v.visitBinary(.i32Shl) - case .i32_shr_s: return try v.visitBinary(.i32ShrS) - case .i32_shr_u: return try v.visitBinary(.i32ShrU) - case .i32_rotl: return try v.visitBinary(.i32Rotl) - case .i32_rotr: return try v.visitBinary(.i32Rotr) - - case .i64_clz: return try v.visitUnary(.i64Clz) - case .i64_ctz: return try v.visitUnary(.i64Ctz) - case .i64_popcnt: return try v.visitUnary(.i64Popcnt) - case .i64_add: return try v.visitBinary(.i64Add) - case .i64_sub: return try v.visitBinary(.i64Sub) - case .i64_mul: return try v.visitBinary(.i64Mul) - case .i64_div_s: return try v.visitBinary(.i64DivS) - case .i64_div_u: return try v.visitBinary(.i64DivU) - case .i64_rem_s: return try v.visitBinary(.i64RemS) - case .i64_rem_u: return try v.visitBinary(.i64RemU) - case .i64_and: return try v.visitBinary(.i64And) - case .i64_or: return try v.visitBinary(.i64Or) - case .i64_xor: return try v.visitBinary(.i64Xor) - case .i64_shl: return try v.visitBinary(.i64Shl) - case .i64_shr_s: return try v.visitBinary(.i64ShrS) - case .i64_shr_u: return try v.visitBinary(.i64ShrU) - case .i64_rotl: return try v.visitBinary(.i64Rotl) - case .i64_rotr: return try v.visitBinary(.i64Rotr) - - case .f32_abs: return try v.visitUnary(.f32Abs) - case .f32_neg: return try v.visitUnary(.f32Neg) - case .f32_ceil: return try v.visitUnary(.f32Ceil) - case .f32_floor: return try v.visitUnary(.f32Floor) - case .f32_trunc: return try v.visitUnary(.f32Trunc) - case .f32_nearest: return try v.visitUnary(.f32Nearest) - case .f32_sqrt: return try v.visitUnary(.f32Sqrt) - - case .f32_add: return try v.visitBinary(.f32Add) - case .f32_sub: return try v.visitBinary(.f32Sub) - case .f32_mul: return try v.visitBinary(.f32Mul) - case .f32_div: return try v.visitBinary(.f32Div) - case .f32_min: return try v.visitBinary(.f32Min) - case .f32_max: return try v.visitBinary(.f32Max) - case .f32_copysign: return try v.visitBinary(.f32Copysign) - - case .f64_abs: return try v.visitUnary(.f64Abs) - case .f64_neg: return try v.visitUnary(.f64Neg) - case .f64_ceil: return try v.visitUnary(.f64Ceil) - case .f64_floor: return try v.visitUnary(.f64Floor) - case .f64_trunc: return try v.visitUnary(.f64Trunc) - case .f64_nearest: return try v.visitUnary(.f64Nearest) - case .f64_sqrt: return try v.visitUnary(.f64Sqrt) - - case .f64_add: return try v.visitBinary(.f64Add) - case .f64_sub: return try v.visitBinary(.f64Sub) - case .f64_mul: return try v.visitBinary(.f64Mul) - case .f64_div: return try v.visitBinary(.f64Div) - case .f64_min: return try v.visitBinary(.f64Min) - case .f64_max: return try v.visitBinary(.f64Max) - case .f64_copysign: return try v.visitBinary(.f64Copysign) - - case .i32_wrap_i64: return try v.visitConversion(.i32WrapI64) - case .i32_trunc_f32_s: return try v.visitConversion(.i32TruncF32S) - case .i32_trunc_f32_u: return try v.visitConversion(.i32TruncF32U) - case .i32_trunc_f64_s: return try v.visitConversion(.i32TruncF64S) - case .i32_trunc_f64_u: return try v.visitConversion(.i32TruncF64U) - case .i64_extend_i32_s: return try v.visitConversion(.i64ExtendI32S) - case .i64_extend_i32_u: return try v.visitConversion(.i64ExtendI32U) - case .i64_trunc_f32_s: return try v.visitConversion(.i64TruncF32S) - case .i64_trunc_f32_u: return try v.visitConversion(.i64TruncF32U) - case .i64_trunc_f64_s: return try v.visitConversion(.i64TruncF64S) - case .i64_trunc_f64_u: return try v.visitConversion(.i64TruncF64U) - case .f32_convert_i32_s: return try v.visitConversion(.f32ConvertI32S) - case .f32_convert_i32_u: return try v.visitConversion(.f32ConvertI32U) - case .f32_convert_i64_s: return try v.visitConversion(.f32ConvertI64S) - case .f32_convert_i64_u: return try v.visitConversion(.f32ConvertI64U) - case .f32_demote_f64: return try v.visitConversion(.f32DemoteF64) - case .f64_convert_i32_s: return try v.visitConversion(.f64ConvertI32S) - case .f64_convert_i32_u: return try v.visitConversion(.f64ConvertI32U) - case .f64_convert_i64_s: return try v.visitConversion(.f64ConvertI64S) - case .f64_convert_i64_u: return try v.visitConversion(.f64ConvertI64U) - case .f64_promote_f32: return try v.visitConversion(.f64PromoteF32) - case .i32_reinterpret_f32: return try v.visitConversion(.i32ReinterpretF32) - case .i64_reinterpret_f64: return try v.visitConversion(.i64ReinterpretF64) - case .f32_reinterpret_i32: return try v.visitConversion(.f32ReinterpretI32) - case .f64_reinterpret_i64: return try v.visitConversion(.f64ReinterpretI64) - case .i32_extend8_s: return try v.visitUnary(.i32Extend8S) - case .i32_extend16_s: return try v.visitUnary(.i32Extend16S) - case .i64_extend8_s: return try v.visitUnary(.i64Extend8S) - case .i64_extend16_s: return try v.visitUnary(.i64Extend16S) - case .i64_extend32_s: return try v.visitUnary(.i64Extend32S) - - case .ref_null: - let type = try parseValueType() - - guard case let .ref(refType) = type else { - throw makeError(.expectedRefType(actual: type)) - } - - return try v.visitRefNull(type: refType) + @inlinable func visitUnknown(_ opcode: [UInt8]) throws { + throw makeError(.illegalOpcode(opcode)) + } - case .ref_is_null: return try v.visitRefIsNull() + @inlinable mutating func visitBlock() throws -> BlockType { try parseResultType() } + @inlinable mutating func visitLoop() throws -> BlockType { try parseResultType() } + @inlinable mutating func visitIf() throws -> BlockType { try parseResultType() } + @inlinable mutating func visitBr() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitBrIf() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitBrTable() throws -> BrTable { + let labelIndices: [UInt32] = try parseVector { try parseUnsigned() } + let labelIndex: UInt32 = try parseUnsigned() + return BrTable(labelIndices: labelIndices, defaultIndex: labelIndex) + } + @inlinable mutating func visitCall() throws -> UInt32 { try parseUnsigned() } - case .ref_func: return try v.visitRefFunc(functionIndex: try parseUnsigned()) + @inlinable mutating func visitCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) { + let typeIndex: TypeIndex = try parseUnsigned() + if try !features.contains(.referenceTypes) && stream.peek() != 0 { + // Check that reserved byte is zero when reference-types is disabled + throw makeError(.malformedIndirectCall) + } + let tableIndex: TableIndex = try parseUnsigned() + return (typeIndex, tableIndex) + } - case .table_get: return try v.visitTableGet(table: try parseUnsigned()) + @inlinable mutating func visitTypedSelect() throws -> WasmTypes.ValueType { + let results = try parseVector { try parseValueType() } + guard results.count == 1 else { + throw makeError(.invalidResultArity(expected: 1, actual: results.count)) + } + return results[0] + } + + @inlinable mutating func visitLocalGet() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitLocalSet() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitLocalTee() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitGlobalGet() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitGlobalSet() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitLoad(_: Instruction.Load) throws -> MemArg { try parseMemarg() } + @inlinable mutating func visitStore(_: Instruction.Store) throws -> MemArg { try parseMemarg() } + @inlinable mutating func visitMemorySize() throws -> UInt32 { + try parseMemoryIndex() + } + @inlinable mutating func visitMemoryGrow() throws -> UInt32 { + try parseMemoryIndex() + } + @inlinable mutating func visitI32Const() throws -> Int32 { + let n: UInt32 = try parseInteger() + return Int32(bitPattern: n) + } + @inlinable mutating func visitI64Const() throws -> Int64 { + let n: UInt64 = try parseInteger() + return Int64(bitPattern: n) + } + @inlinable mutating func visitF32Const() throws -> IEEE754.Float32 { + let n = try parseFloat() + return IEEE754.Float32(bitPattern: n) + } + @inlinable mutating func visitF64Const() throws -> IEEE754.Float64 { + let n = try parseDouble() + return IEEE754.Float64(bitPattern: n) + } + @inlinable mutating func visitRefNull() throws -> WasmTypes.ReferenceType { + let type = try parseValueType() + guard case let .ref(refType) = type else { + throw makeError(.expectedRefType(actual: type)) + } + return refType + } - case .table_set: return try v.visitTableSet(table: try parseUnsigned()) + @inlinable mutating func visitRefFunc() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitMemoryInit() throws -> UInt32 { + let dataIndex: DataIndex = try parseUnsigned() + _ = try parseMemoryIndex() + return dataIndex + } - case .wasm2InstructionPrefix: - let codeSuffix: UInt32 = try parseUnsigned() - switch codeSuffix { - case 0: return try v.visitConversion(.i32TruncSatF32S) - case 1: return try v.visitConversion(.i32TruncSatF32U) - case 2: return try v.visitConversion(.i32TruncSatF64S) - case 3: return try v.visitConversion(.i32TruncSatF64U) - case 4: return try v.visitConversion(.i64TruncSatF32S) - case 5: return try v.visitConversion(.i64TruncSatF32U) - case 6: return try v.visitConversion(.i64TruncSatF64S) - case 7: return try v.visitConversion(.i64TruncSatF64U) - case 8: - let dataIndex: DataIndex = try parseUnsigned() - let zero = try stream.consumeAny() - guard zero == 0x00 else { - throw makeError(.zeroExpected(actual: zero)) - } + @inlinable mutating func visitDataDrop() throws -> UInt32 { + try parseUnsigned() + } - return try v.visitMemoryInit(dataIndex: dataIndex) - case 9: - return try v.visitDataDrop(dataIndex: try parseUnsigned()) - case 10: - let (zero1, zero2) = try (stream.consumeAny(), stream.consumeAny()) - guard zero1 == 0x00 else { - throw makeError(.zeroExpected(actual: zero1)) - } - guard zero2 == 0x00 else { - throw makeError(.zeroExpected(actual: zero2)) - } - return try v.visitMemoryCopy(dstMem: 0, srcMem: 0) - case 11: - let zero = try stream.consumeAny() - guard zero == 0x00 else { - throw makeError(.zeroExpected(actual: zero)) - } + @inlinable mutating func visitMemoryCopy() throws -> (dstMem: UInt32, srcMem: UInt32) { + _ = try parseMemoryIndex() + _ = try parseMemoryIndex() + return (0, 0) + } - return try v.visitMemoryFill(memory: 0) - case 12: - let elementIndex: ElementIndex = try parseUnsigned() - let tableIndex: TableIndex = try parseUnsigned() - return try v.visitTableInit(elemIndex: elementIndex, table: tableIndex) - case 13: return try v.visitElemDrop(elemIndex: try parseUnsigned()) - case 14: - let destinationTableIndex: TableIndex = try parseUnsigned() - let sourceTableIndex: TableIndex = try parseUnsigned() - return try v.visitTableCopy(dstTable: destinationTableIndex, srcTable: sourceTableIndex) - case 15: return try v.visitTableGrow(table: try parseUnsigned()) - case 16: return try v.visitTableSize(table: try parseUnsigned()) - case 17: return try v.visitTableFill(table: try parseUnsigned()) - default: - throw makeError(.unimplementedInstruction(code.rawValue, suffix: codeSuffix)) - } + @inlinable mutating func visitMemoryFill() throws -> UInt32 { + let zero = try stream.consumeAny() + guard zero == 0x00 else { + throw makeError(.zeroExpected(actual: zero)) } + return 0 + } + + @inlinable mutating func visitTableInit() throws -> (elemIndex: UInt32, table: UInt32) { + let elementIndex: ElementIndex = try parseUnsigned() + let tableIndex: TableIndex = try parseUnsigned() + return (elementIndex, tableIndex) + } + @inlinable mutating func visitElemDrop() throws -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableCopy() throws -> (dstTable: UInt32, srcTable: UInt32) { + let destination: TableIndex = try parseUnsigned() + let source: TableIndex = try parseUnsigned() + return (destination, source) + } + @inlinable mutating func visitTableFill() throws -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableGet() throws -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableSet() throws -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableGrow() throws -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableSize() throws -> UInt32 { + try parseUnsigned() + } + @inlinable func claimNextByte() throws -> UInt8 { + return try stream.consumeAny() + } + + @inline(__always) + @inlinable + mutating func parseInstruction(visitor v: inout V) throws -> Bool { + return try parseBinaryInstruction(visitor: &v, decoder: &self) } @usableFromInline @@ -928,12 +736,12 @@ extension Parser { } @usableFromInline - func parseConstExpression() throws -> ConstExpression { + mutating func parseConstExpression() throws -> ConstExpression { var factory = InstructionFactory() - var inst: InstructionCode + var isEnd: Bool repeat { - inst = try self.parseInstruction(visitor: &factory) - } while inst != .end + isEnd = try self.parseInstruction(visitor: &factory) + } while !isEnd return factory.insts } } @@ -1016,7 +824,7 @@ extension Parser { /// > Note: /// @usableFromInline - func parseGlobalSection() throws -> [Global] { + mutating func parseGlobalSection() throws -> [Global] { return try parseVector { let type = try parseGlobalType() let expression = try parseConstExpression() @@ -1059,7 +867,7 @@ extension Parser { /// > Note: /// @inlinable - func parseElementSection() throws -> [ElementSegment] { + mutating func parseElementSection() throws -> [ElementSegment] { return try parseVector { let flag = try ElementSegment.Flag(rawValue: parseUnsigned()) @@ -1152,7 +960,7 @@ extension Parser { /// > Note: /// @inlinable - func parseDataSection() throws -> [DataSegment] { + mutating func parseDataSection() throws -> [DataSegment] { return try parseVector { let kind: UInt32 = try parseUnsigned() switch kind { diff --git a/Tests/WasmKitTests/SpectestTests.swift b/Tests/WasmKitTests/SpectestTests.swift index 5a5bec48..b174edac 100644 --- a/Tests/WasmKitTests/SpectestTests.swift +++ b/Tests/WasmKitTests/SpectestTests.swift @@ -21,7 +21,7 @@ final class SpectestTests: XCTestCase { let defaultConfig = EngineConfiguration() let ok = try await spectest( path: Self.testPaths, - include: [], + include: ["bulk.wast"], exclude: [], parallel: true, configuration: defaultConfig diff --git a/Utilities/Instructions.json b/Utilities/Instructions.json index 6816b73a..ce43a2d0 100644 --- a/Utilities/Instructions.json +++ b/Utilities/Instructions.json @@ -1,203 +1,203 @@ [ - ["mvp" , "unreachable" , null , "0x00", [] , null ], - ["mvp" , "nop" , null , "0x01", [] , null ], - ["mvp" , "block" , null , "0x02", [["blockType", "BlockType"]] , null ], - ["mvp" , "loop" , null , "0x03", [["blockType", "BlockType"]] , null ], - ["mvp" , "if" , null , "0x04", [["blockType", "BlockType"]] , null ], - ["mvp" , "else" , null , "0x05", [] , null ], - ["mvp" , "end" , null , "0x0B", [] , null ], - ["mvp" , "br" , null , "0x0C", [["relativeDepth", "UInt32"]] , null ], - ["mvp" , "br_if" , null , "0x0D", [["relativeDepth", "UInt32"]] , null ], - ["mvp" , "br_table" , null , "0x0E", [["targets", "BrTable"]] , null ], - ["mvp" , "return" , null , "0x0F", [] , null ], - ["mvp" , "call" , null , "0x10", [["functionIndex", "UInt32"]] , null ], - ["mvp" , "call_indirect" , null , "0x11", [["typeIndex", "UInt32"], ["tableIndex", "UInt32"]], null ], - ["mvp" , "drop" , null , "0x1A", [] , null ], - ["mvp" , "select" , null , "0x1B", [] , null ], - ["referenceTypes" , {"enumCase": "typedSelect"}, null , "0x1C", [["type", "ValueType"]] , null ], - ["mvp" , "local.get" , null , "0x20", [["localIndex", "UInt32"]] , null ], - ["mvp" , "local.set" , null , "0x21", [["localIndex", "UInt32"]] , null ], - ["mvp" , "local.tee" , null , "0x22", [["localIndex", "UInt32"]] , null ], - ["mvp" , "global.get" , null , "0x23", [["globalIndex", "UInt32"]] , null ], - ["mvp" , "global.set" , null , "0x24", [["globalIndex", "UInt32"]] , null ], - ["mvp" , "i32.load" , null , "0x28", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i64.load" , null , "0x29", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "f32.load" , null , "0x2A", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "f64.load" , null , "0x2B", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i32.load8_s" , null , "0x2C", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i32.load8_u" , null , "0x2D", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i32.load16_s" , null , "0x2E", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i32.load16_u" , null , "0x2F", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i64.load8_s" , null , "0x30", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i64.load8_u" , null , "0x31", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i64.load16_s" , null , "0x32", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i64.load16_u" , null , "0x33", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i64.load32_s" , null , "0x34", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i64.load32_u" , null , "0x35", [["memarg", "MemArg"]] , "load" ], - ["mvp" , "i32.store" , null , "0x36", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "i64.store" , null , "0x37", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "f32.store" , null , "0x38", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "f64.store" , null , "0x39", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "i32.store8" , null , "0x3A", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "i32.store16" , null , "0x3B", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "i64.store8" , null , "0x3C", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "i64.store16" , null , "0x3D", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "i64.store32" , null , "0x3E", [["memarg", "MemArg"]] , "store" ], - ["mvp" , "memory.size" , null , "0x3F", [["memory", "UInt32"]] , null ], - ["mvp" , "memory.grow" , null , "0x40", [["memory", "UInt32"]] , null ], - ["mvp" , "i32.const" , null , "0x41", [["value", "Int32"]] , null ], - ["mvp" , "i64.const" , null , "0x42", [["value", "Int64"]] , null ], - ["mvp" , "f32.const" , null , "0x43", [["value", "IEEE754.Float32"]] , null ], - ["mvp" , "f64.const" , null , "0x44", [["value", "IEEE754.Float64"]] , null ], - ["referenceTypes" , "ref.null" , null , "0xD0", [["type", "ReferenceType"]] , null ], - ["referenceTypes" , "ref.is_null" , null , "0xD1", [] , null ], - ["referenceTypes" , "ref.func" , null , "0xD2", [["functionIndex", "UInt32"]] , null ], - ["mvp" , "i32.eqz" , null , "0x45", [] , null ], - ["mvp" , "i32.eq" , null , "0x46", [] , "cmp" ], - ["mvp" , "i32.ne" , null , "0x47", [] , "cmp" ], - ["mvp" , "i32.lt_s" , null , "0x48", [] , "cmp" ], - ["mvp" , "i32.lt_u" , null , "0x49", [] , "cmp" ], - ["mvp" , "i32.gt_s" , null , "0x4A", [] , "cmp" ], - ["mvp" , "i32.gt_u" , null , "0x4B", [] , "cmp" ], - ["mvp" , "i32.le_s" , null , "0x4C", [] , "cmp" ], - ["mvp" , "i32.le_u" , null , "0x4D", [] , "cmp" ], - ["mvp" , "i32.ge_s" , null , "0x4E", [] , "cmp" ], - ["mvp" , "i32.ge_u" , null , "0x4F", [] , "cmp" ], - ["mvp" , "i64.eqz" , null , "0x50", [] , null ], - ["mvp" , "i64.eq" , null , "0x51", [] , "cmp" ], - ["mvp" , "i64.ne" , null , "0x52", [] , "cmp" ], - ["mvp" , "i64.lt_s" , null , "0x53", [] , "cmp" ], - ["mvp" , "i64.lt_u" , null , "0x54", [] , "cmp" ], - ["mvp" , "i64.gt_s" , null , "0x55", [] , "cmp" ], - ["mvp" , "i64.gt_u" , null , "0x56", [] , "cmp" ], - ["mvp" , "i64.le_s" , null , "0x57", [] , "cmp" ], - ["mvp" , "i64.le_u" , null , "0x58", [] , "cmp" ], - ["mvp" , "i64.ge_s" , null , "0x59", [] , "cmp" ], - ["mvp" , "i64.ge_u" , null , "0x5A", [] , "cmp" ], - ["mvp" , "f32.eq" , null , "0x5B", [] , "cmp" ], - ["mvp" , "f32.ne" , null , "0x5C", [] , "cmp" ], - ["mvp" , "f32.lt" , null , "0x5D", [] , "cmp" ], - ["mvp" , "f32.gt" , null , "0x5E", [] , "cmp" ], - ["mvp" , "f32.le" , null , "0x5F", [] , "cmp" ], - ["mvp" , "f32.ge" , null , "0x60", [] , "cmp" ], - ["mvp" , "f64.eq" , null , "0x61", [] , "cmp" ], - ["mvp" , "f64.ne" , null , "0x62", [] , "cmp" ], - ["mvp" , "f64.lt" , null , "0x63", [] , "cmp" ], - ["mvp" , "f64.gt" , null , "0x64", [] , "cmp" ], - ["mvp" , "f64.le" , null , "0x65", [] , "cmp" ], - ["mvp" , "f64.ge" , null , "0x66", [] , "cmp" ], - ["mvp" , "i32.clz" , null , "0x67", [] , "unary" ], - ["mvp" , "i32.ctz" , null , "0x68", [] , "unary" ], - ["mvp" , "i32.popcnt" , null , "0x69", [] , "unary" ], - ["mvp" , "i32.add" , null , "0x6A", [] , "binary"], - ["mvp" , "i32.sub" , null , "0x6B", [] , "binary"], - ["mvp" , "i32.mul" , null , "0x6C", [] , "binary"], - ["mvp" , "i32.div_s" , null , "0x6D", [] , "binary"], - ["mvp" , "i32.div_u" , null , "0x6E", [] , "binary"], - ["mvp" , "i32.rem_s" , null , "0x6F", [] , "binary"], - ["mvp" , "i32.rem_u" , null , "0x70", [] , "binary"], - ["mvp" , "i32.and" , null , "0x71", [] , "binary"], - ["mvp" , "i32.or" , null , "0x72", [] , "binary"], - ["mvp" , "i32.xor" , null , "0x73", [] , "binary"], - ["mvp" , "i32.shl" , null , "0x74", [] , "binary"], - ["mvp" , "i32.shr_s" , null , "0x75", [] , "binary"], - ["mvp" , "i32.shr_u" , null , "0x76", [] , "binary"], - ["mvp" , "i32.rotl" , null , "0x77", [] , "binary"], - ["mvp" , "i32.rotr" , null , "0x78", [] , "binary"], - ["mvp" , "i64.clz" , null , "0x79", [] , "unary" ], - ["mvp" , "i64.ctz" , null , "0x7A", [] , "unary" ], - ["mvp" , "i64.popcnt" , null , "0x7B", [] , "unary" ], - ["mvp" , "i64.add" , null , "0x7C", [] , "binary"], - ["mvp" , "i64.sub" , null , "0x7D", [] , "binary"], - ["mvp" , "i64.mul" , null , "0x7E", [] , "binary"], - ["mvp" , "i64.div_s" , null , "0x7F", [] , "binary"], - ["mvp" , "i64.div_u" , null , "0x80", [] , "binary"], - ["mvp" , "i64.rem_s" , null , "0x81", [] , "binary"], - ["mvp" , "i64.rem_u" , null , "0x82", [] , "binary"], - ["mvp" , "i64.and" , null , "0x83", [] , "binary"], - ["mvp" , "i64.or" , null , "0x84", [] , "binary"], - ["mvp" , "i64.xor" , null , "0x85", [] , "binary"], - ["mvp" , "i64.shl" , null , "0x86", [] , "binary"], - ["mvp" , "i64.shr_s" , null , "0x87", [] , "binary"], - ["mvp" , "i64.shr_u" , null , "0x88", [] , "binary"], - ["mvp" , "i64.rotl" , null , "0x89", [] , "binary"], - ["mvp" , "i64.rotr" , null , "0x8A", [] , "binary"], - ["mvp" , "f32.abs" , null , "0x8B", [] , "unary" ], - ["mvp" , "f32.neg" , null , "0x8C", [] , "unary" ], - ["mvp" , "f32.ceil" , null , "0x8D", [] , "unary" ], - ["mvp" , "f32.floor" , null , "0x8E", [] , "unary" ], - ["mvp" , "f32.trunc" , null , "0x8F", [] , "unary" ], - ["mvp" , "f32.nearest" , null , "0x90", [] , "unary" ], - ["mvp" , "f32.sqrt" , null , "0x91", [] , "unary" ], - ["mvp" , "f32.add" , null , "0x92", [] , "binary"], - ["mvp" , "f32.sub" , null , "0x93", [] , "binary"], - ["mvp" , "f32.mul" , null , "0x94", [] , "binary"], - ["mvp" , "f32.div" , null , "0x95", [] , "binary"], - ["mvp" , "f32.min" , null , "0x96", [] , "binary"], - ["mvp" , "f32.max" , null , "0x97", [] , "binary"], - ["mvp" , "f32.copysign" , null , "0x98", [] , "binary"], - ["mvp" , "f64.abs" , null , "0x99", [] , "unary" ], - ["mvp" , "f64.neg" , null , "0x9A", [] , "unary" ], - ["mvp" , "f64.ceil" , null , "0x9B", [] , "unary" ], - ["mvp" , "f64.floor" , null , "0x9C", [] , "unary" ], - ["mvp" , "f64.trunc" , null , "0x9D", [] , "unary" ], - ["mvp" , "f64.nearest" , null , "0x9E", [] , "unary" ], - ["mvp" , "f64.sqrt" , null , "0x9F", [] , "unary" ], - ["mvp" , "f64.add" , null , "0xA0", [] , "binary"], - ["mvp" , "f64.sub" , null , "0xA1", [] , "binary"], - ["mvp" , "f64.mul" , null , "0xA2", [] , "binary"], - ["mvp" , "f64.div" , null , "0xA3", [] , "binary"], - ["mvp" , "f64.min" , null , "0xA4", [] , "binary"], - ["mvp" , "f64.max" , null , "0xA5", [] , "binary"], - ["mvp" , "f64.copysign" , null , "0xA6", [] , "binary"], - ["mvp" , "i32.wrap_i64" , null , "0xA7", [] , "conversion"], - ["mvp" , "i32.trunc_f32_s" , null , "0xA8", [] , "conversion"], - ["mvp" , "i32.trunc_f32_u" , null , "0xA9", [] , "conversion"], - ["mvp" , "i32.trunc_f64_s" , null , "0xAA", [] , "conversion"], - ["mvp" , "i32.trunc_f64_u" , null , "0xAB", [] , "conversion"], - ["mvp" , "i64.extend_i32_s" , null , "0xAC", [] , "conversion"], - ["mvp" , "i64.extend_i32_u" , null , "0xAD", [] , "conversion"], - ["mvp" , "i64.trunc_f32_s" , null , "0xAE", [] , "conversion"], - ["mvp" , "i64.trunc_f32_u" , null , "0xAF", [] , "conversion"], - ["mvp" , "i64.trunc_f64_s" , null , "0xB0", [] , "conversion"], - ["mvp" , "i64.trunc_f64_u" , null , "0xB1", [] , "conversion"], - ["mvp" , "f32.convert_i32_s" , null , "0xB2", [] , "conversion"], - ["mvp" , "f32.convert_i32_u" , null , "0xB3", [] , "conversion"], - ["mvp" , "f32.convert_i64_s" , null , "0xB4", [] , "conversion"], - ["mvp" , "f32.convert_i64_u" , null , "0xB5", [] , "conversion"], - ["mvp" , "f32.demote_f64" , null , "0xB6", [] , "conversion"], - ["mvp" , "f64.convert_i32_s" , null , "0xB7", [] , "conversion"], - ["mvp" , "f64.convert_i32_u" , null , "0xB8", [] , "conversion"], - ["mvp" , "f64.convert_i64_s" , null , "0xB9", [] , "conversion"], - ["mvp" , "f64.convert_i64_u" , null , "0xBA", [] , "conversion"], - ["mvp" , "f64.promote_f32" , null , "0xBB", [] , "conversion"], - ["mvp" , "i32.reinterpret_f32" , null , "0xBC", [] , "conversion"], - ["mvp" , "i64.reinterpret_f64" , null , "0xBD", [] , "conversion"], - ["mvp" , "f32.reinterpret_i32" , null , "0xBE", [] , "conversion"], - ["mvp" , "f64.reinterpret_i64" , null , "0xBF", [] , "conversion"], - ["signExtension" , "i32.extend8_s" , null , "0xC0", [] , "unary" ], - ["signExtension" , "i32.extend16_s" , null , "0xC1", [] , "unary" ], - ["signExtension" , "i64.extend8_s" , null , "0xC2", [] , "unary" ], - ["signExtension" , "i64.extend16_s" , null , "0xC3", [] , "unary" ], - ["signExtension" , "i64.extend32_s" , null , "0xC4", [] , "unary" ], - ["bulkMemory" , "memory.init" , "0xFC", "0x08", [["dataIndex", "UInt32"]] , null ], - ["bulkMemory" , "data.drop" , "0xFC", "0x09", [["dataIndex", "UInt32"]] , null ], - ["bulkMemory" , "memory.copy" , "0xFC", "0x0A", [["dstMem", "UInt32"], ["srcMem", "UInt32"]] , null ], - ["bulkMemory" , "memory.fill" , "0xFC", "0x0B", [["memory", "UInt32"]] , null ], - ["bulkMemory" , "table.init" , "0xFC", "0x0C", [["elemIndex", "UInt32"], ["table", "UInt32"]] , null ], - ["bulkMemory" , "elem.drop" , "0xFC", "0x0D", [["elemIndex", "UInt32"]] , null ], - ["bulkMemory" , "table.copy" , "0xFC", "0x0E", [["dstTable", "UInt32"], ["srcTable", "UInt32"]] , null ], - ["referenceTypes" , "table.fill" , "0xFC", "0x11", [["table", "UInt32"]] , null ], - ["referenceTypes" , "table.get" , null , "0x25", [["table", "UInt32"]] , null ], - ["referenceTypes" , "table.set" , null , "0x26", [["table", "UInt32"]] , null ], - ["referenceTypes" , "table.grow" , "0xFC", "0x0F", [["table", "UInt32"]] , null ], - ["referenceTypes" , "table.size" , "0xFC", "0x10", [["table", "UInt32"]] , null ], - ["saturatingFloatToInt", "i32.trunc_sat_f32_s" , "0xFC", "0x00", [] , "conversion" ], - ["saturatingFloatToInt", "i32.trunc_sat_f32_u" , "0xFC", "0x01", [] , "conversion" ], - ["saturatingFloatToInt", "i32.trunc_sat_f64_s" , "0xFC", "0x02", [] , "conversion" ], - ["saturatingFloatToInt", "i32.trunc_sat_f64_u" , "0xFC", "0x03", [] , "conversion" ], - ["saturatingFloatToInt", "i64.trunc_sat_f32_s" , "0xFC", "0x04", [] , "conversion" ], - ["saturatingFloatToInt", "i64.trunc_sat_f32_u" , "0xFC", "0x05", [] , "conversion" ], - ["saturatingFloatToInt", "i64.trunc_sat_f64_s" , "0xFC", "0x06", [] , "conversion" ], - ["saturatingFloatToInt", "i64.trunc_sat_f64_u" , "0xFC", "0x07", [] , "conversion" ] + ["mvp" , "unreachable" , ["0x00"] , [] , null ], + ["mvp" , "nop" , ["0x01"] , [] , null ], + ["mvp" , "block" , ["0x02"] , [["blockType", "BlockType"]] , null ], + ["mvp" , "loop" , ["0x03"] , [["blockType", "BlockType"]] , null ], + ["mvp" , "if" , ["0x04"] , [["blockType", "BlockType"]] , null ], + ["mvp" , "else" , ["0x05"] , [] , null ], + ["mvp" , "end" , ["0x0B"] , [] , null ], + ["mvp" , "br" , ["0x0C"] , [["relativeDepth", "UInt32"]] , null ], + ["mvp" , "br_if" , ["0x0D"] , [["relativeDepth", "UInt32"]] , null ], + ["mvp" , "br_table" , ["0x0E"] , [["targets", "BrTable"]] , null ], + ["mvp" , "return" , ["0x0F"] , [] , null ], + ["mvp" , "call" , ["0x10"] , [["functionIndex", "UInt32"]] , null ], + ["mvp" , "call_indirect" , ["0x11"] , [["typeIndex", "UInt32"], ["tableIndex", "UInt32"]], null ], + ["mvp" , "drop" , ["0x1A"] , [] , null ], + ["mvp" , "select" , ["0x1B"] , [] , null ], + ["referenceTypes" , {"enumCase": "typedSelect"}, ["0x1C"] , [["type", "ValueType"]] , null ], + ["mvp" , "local.get" , ["0x20"] , [["localIndex", "UInt32"]] , null ], + ["mvp" , "local.set" , ["0x21"] , [["localIndex", "UInt32"]] , null ], + ["mvp" , "local.tee" , ["0x22"] , [["localIndex", "UInt32"]] , null ], + ["mvp" , "global.get" , ["0x23"] , [["globalIndex", "UInt32"]] , null ], + ["mvp" , "global.set" , ["0x24"] , [["globalIndex", "UInt32"]] , null ], + ["mvp" , "i32.load" , ["0x28"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i64.load" , ["0x29"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "f32.load" , ["0x2A"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "f64.load" , ["0x2B"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i32.load8_s" , ["0x2C"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i32.load8_u" , ["0x2D"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i32.load16_s" , ["0x2E"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i32.load16_u" , ["0x2F"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i64.load8_s" , ["0x30"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i64.load8_u" , ["0x31"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i64.load16_s" , ["0x32"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i64.load16_u" , ["0x33"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i64.load32_s" , ["0x34"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i64.load32_u" , ["0x35"] , [["memarg", "MemArg"]] , "load" ], + ["mvp" , "i32.store" , ["0x36"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "i64.store" , ["0x37"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "f32.store" , ["0x38"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "f64.store" , ["0x39"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "i32.store8" , ["0x3A"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "i32.store16" , ["0x3B"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "i64.store8" , ["0x3C"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "i64.store16" , ["0x3D"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "i64.store32" , ["0x3E"] , [["memarg", "MemArg"]] , "store" ], + ["mvp" , "memory.size" , ["0x3F"] , [["memory", "UInt32"]] , null ], + ["mvp" , "memory.grow" , ["0x40"] , [["memory", "UInt32"]] , null ], + ["mvp" , "i32.const" , ["0x41"] , [["value", "Int32"]] , null ], + ["mvp" , "i64.const" , ["0x42"] , [["value", "Int64"]] , null ], + ["mvp" , "f32.const" , ["0x43"] , [["value", "IEEE754.Float32"]] , null ], + ["mvp" , "f64.const" , ["0x44"] , [["value", "IEEE754.Float64"]] , null ], + ["referenceTypes" , "ref.null" , ["0xD0"] , [["type", "ReferenceType"]] , null ], + ["referenceTypes" , "ref.is_null" , ["0xD1"] , [] , null ], + ["referenceTypes" , "ref.func" , ["0xD2"] , [["functionIndex", "UInt32"]] , null ], + ["mvp" , "i32.eqz" , ["0x45"] , [] , null ], + ["mvp" , "i32.eq" , ["0x46"] , [] , "cmp" ], + ["mvp" , "i32.ne" , ["0x47"] , [] , "cmp" ], + ["mvp" , "i32.lt_s" , ["0x48"] , [] , "cmp" ], + ["mvp" , "i32.lt_u" , ["0x49"] , [] , "cmp" ], + ["mvp" , "i32.gt_s" , ["0x4A"] , [] , "cmp" ], + ["mvp" , "i32.gt_u" , ["0x4B"] , [] , "cmp" ], + ["mvp" , "i32.le_s" , ["0x4C"] , [] , "cmp" ], + ["mvp" , "i32.le_u" , ["0x4D"] , [] , "cmp" ], + ["mvp" , "i32.ge_s" , ["0x4E"] , [] , "cmp" ], + ["mvp" , "i32.ge_u" , ["0x4F"] , [] , "cmp" ], + ["mvp" , "i64.eqz" , ["0x50"] , [] , null ], + ["mvp" , "i64.eq" , ["0x51"] , [] , "cmp" ], + ["mvp" , "i64.ne" , ["0x52"] , [] , "cmp" ], + ["mvp" , "i64.lt_s" , ["0x53"] , [] , "cmp" ], + ["mvp" , "i64.lt_u" , ["0x54"] , [] , "cmp" ], + ["mvp" , "i64.gt_s" , ["0x55"] , [] , "cmp" ], + ["mvp" , "i64.gt_u" , ["0x56"] , [] , "cmp" ], + ["mvp" , "i64.le_s" , ["0x57"] , [] , "cmp" ], + ["mvp" , "i64.le_u" , ["0x58"] , [] , "cmp" ], + ["mvp" , "i64.ge_s" , ["0x59"] , [] , "cmp" ], + ["mvp" , "i64.ge_u" , ["0x5A"] , [] , "cmp" ], + ["mvp" , "f32.eq" , ["0x5B"] , [] , "cmp" ], + ["mvp" , "f32.ne" , ["0x5C"] , [] , "cmp" ], + ["mvp" , "f32.lt" , ["0x5D"] , [] , "cmp" ], + ["mvp" , "f32.gt" , ["0x5E"] , [] , "cmp" ], + ["mvp" , "f32.le" , ["0x5F"] , [] , "cmp" ], + ["mvp" , "f32.ge" , ["0x60"] , [] , "cmp" ], + ["mvp" , "f64.eq" , ["0x61"] , [] , "cmp" ], + ["mvp" , "f64.ne" , ["0x62"] , [] , "cmp" ], + ["mvp" , "f64.lt" , ["0x63"] , [] , "cmp" ], + ["mvp" , "f64.gt" , ["0x64"] , [] , "cmp" ], + ["mvp" , "f64.le" , ["0x65"] , [] , "cmp" ], + ["mvp" , "f64.ge" , ["0x66"] , [] , "cmp" ], + ["mvp" , "i32.clz" , ["0x67"] , [] , "unary" ], + ["mvp" , "i32.ctz" , ["0x68"] , [] , "unary" ], + ["mvp" , "i32.popcnt" , ["0x69"] , [] , "unary" ], + ["mvp" , "i32.add" , ["0x6A"] , [] , "binary" ], + ["mvp" , "i32.sub" , ["0x6B"] , [] , "binary" ], + ["mvp" , "i32.mul" , ["0x6C"] , [] , "binary" ], + ["mvp" , "i32.div_s" , ["0x6D"] , [] , "binary" ], + ["mvp" , "i32.div_u" , ["0x6E"] , [] , "binary" ], + ["mvp" , "i32.rem_s" , ["0x6F"] , [] , "binary" ], + ["mvp" , "i32.rem_u" , ["0x70"] , [] , "binary" ], + ["mvp" , "i32.and" , ["0x71"] , [] , "binary" ], + ["mvp" , "i32.or" , ["0x72"] , [] , "binary" ], + ["mvp" , "i32.xor" , ["0x73"] , [] , "binary" ], + ["mvp" , "i32.shl" , ["0x74"] , [] , "binary" ], + ["mvp" , "i32.shr_s" , ["0x75"] , [] , "binary" ], + ["mvp" , "i32.shr_u" , ["0x76"] , [] , "binary" ], + ["mvp" , "i32.rotl" , ["0x77"] , [] , "binary" ], + ["mvp" , "i32.rotr" , ["0x78"] , [] , "binary" ], + ["mvp" , "i64.clz" , ["0x79"] , [] , "unary" ], + ["mvp" , "i64.ctz" , ["0x7A"] , [] , "unary" ], + ["mvp" , "i64.popcnt" , ["0x7B"] , [] , "unary" ], + ["mvp" , "i64.add" , ["0x7C"] , [] , "binary" ], + ["mvp" , "i64.sub" , ["0x7D"] , [] , "binary" ], + ["mvp" , "i64.mul" , ["0x7E"] , [] , "binary" ], + ["mvp" , "i64.div_s" , ["0x7F"] , [] , "binary" ], + ["mvp" , "i64.div_u" , ["0x80"] , [] , "binary" ], + ["mvp" , "i64.rem_s" , ["0x81"] , [] , "binary" ], + ["mvp" , "i64.rem_u" , ["0x82"] , [] , "binary" ], + ["mvp" , "i64.and" , ["0x83"] , [] , "binary" ], + ["mvp" , "i64.or" , ["0x84"] , [] , "binary" ], + ["mvp" , "i64.xor" , ["0x85"] , [] , "binary" ], + ["mvp" , "i64.shl" , ["0x86"] , [] , "binary" ], + ["mvp" , "i64.shr_s" , ["0x87"] , [] , "binary" ], + ["mvp" , "i64.shr_u" , ["0x88"] , [] , "binary" ], + ["mvp" , "i64.rotl" , ["0x89"] , [] , "binary" ], + ["mvp" , "i64.rotr" , ["0x8A"] , [] , "binary" ], + ["mvp" , "f32.abs" , ["0x8B"] , [] , "unary" ], + ["mvp" , "f32.neg" , ["0x8C"] , [] , "unary" ], + ["mvp" , "f32.ceil" , ["0x8D"] , [] , "unary" ], + ["mvp" , "f32.floor" , ["0x8E"] , [] , "unary" ], + ["mvp" , "f32.trunc" , ["0x8F"] , [] , "unary" ], + ["mvp" , "f32.nearest" , ["0x90"] , [] , "unary" ], + ["mvp" , "f32.sqrt" , ["0x91"] , [] , "unary" ], + ["mvp" , "f32.add" , ["0x92"] , [] , "binary" ], + ["mvp" , "f32.sub" , ["0x93"] , [] , "binary" ], + ["mvp" , "f32.mul" , ["0x94"] , [] , "binary" ], + ["mvp" , "f32.div" , ["0x95"] , [] , "binary" ], + ["mvp" , "f32.min" , ["0x96"] , [] , "binary" ], + ["mvp" , "f32.max" , ["0x97"] , [] , "binary" ], + ["mvp" , "f32.copysign" , ["0x98"] , [] , "binary" ], + ["mvp" , "f64.abs" , ["0x99"] , [] , "unary" ], + ["mvp" , "f64.neg" , ["0x9A"] , [] , "unary" ], + ["mvp" , "f64.ceil" , ["0x9B"] , [] , "unary" ], + ["mvp" , "f64.floor" , ["0x9C"] , [] , "unary" ], + ["mvp" , "f64.trunc" , ["0x9D"] , [] , "unary" ], + ["mvp" , "f64.nearest" , ["0x9E"] , [] , "unary" ], + ["mvp" , "f64.sqrt" , ["0x9F"] , [] , "unary" ], + ["mvp" , "f64.add" , ["0xA0"] , [] , "binary" ], + ["mvp" , "f64.sub" , ["0xA1"] , [] , "binary" ], + ["mvp" , "f64.mul" , ["0xA2"] , [] , "binary" ], + ["mvp" , "f64.div" , ["0xA3"] , [] , "binary" ], + ["mvp" , "f64.min" , ["0xA4"] , [] , "binary" ], + ["mvp" , "f64.max" , ["0xA5"] , [] , "binary" ], + ["mvp" , "f64.copysign" , ["0xA6"] , [] , "binary" ], + ["mvp" , "i32.wrap_i64" , ["0xA7"] , [] , "conversion"], + ["mvp" , "i32.trunc_f32_s" , ["0xA8"] , [] , "conversion"], + ["mvp" , "i32.trunc_f32_u" , ["0xA9"] , [] , "conversion"], + ["mvp" , "i32.trunc_f64_s" , ["0xAA"] , [] , "conversion"], + ["mvp" , "i32.trunc_f64_u" , ["0xAB"] , [] , "conversion"], + ["mvp" , "i64.extend_i32_s" , ["0xAC"] , [] , "conversion"], + ["mvp" , "i64.extend_i32_u" , ["0xAD"] , [] , "conversion"], + ["mvp" , "i64.trunc_f32_s" , ["0xAE"] , [] , "conversion"], + ["mvp" , "i64.trunc_f32_u" , ["0xAF"] , [] , "conversion"], + ["mvp" , "i64.trunc_f64_s" , ["0xB0"] , [] , "conversion"], + ["mvp" , "i64.trunc_f64_u" , ["0xB1"] , [] , "conversion"], + ["mvp" , "f32.convert_i32_s" , ["0xB2"] , [] , "conversion"], + ["mvp" , "f32.convert_i32_u" , ["0xB3"] , [] , "conversion"], + ["mvp" , "f32.convert_i64_s" , ["0xB4"] , [] , "conversion"], + ["mvp" , "f32.convert_i64_u" , ["0xB5"] , [] , "conversion"], + ["mvp" , "f32.demote_f64" , ["0xB6"] , [] , "conversion"], + ["mvp" , "f64.convert_i32_s" , ["0xB7"] , [] , "conversion"], + ["mvp" , "f64.convert_i32_u" , ["0xB8"] , [] , "conversion"], + ["mvp" , "f64.convert_i64_s" , ["0xB9"] , [] , "conversion"], + ["mvp" , "f64.convert_i64_u" , ["0xBA"] , [] , "conversion"], + ["mvp" , "f64.promote_f32" , ["0xBB"] , [] , "conversion"], + ["mvp" , "i32.reinterpret_f32" , ["0xBC"] , [] , "conversion"], + ["mvp" , "i64.reinterpret_f64" , ["0xBD"] , [] , "conversion"], + ["mvp" , "f32.reinterpret_i32" , ["0xBE"] , [] , "conversion"], + ["mvp" , "f64.reinterpret_i64" , ["0xBF"] , [] , "conversion"], + ["signExtension" , "i32.extend8_s" , ["0xC0"] , [] , "unary" ], + ["signExtension" , "i32.extend16_s" , ["0xC1"] , [] , "unary" ], + ["signExtension" , "i64.extend8_s" , ["0xC2"] , [] , "unary" ], + ["signExtension" , "i64.extend16_s" , ["0xC3"] , [] , "unary" ], + ["signExtension" , "i64.extend32_s" , ["0xC4"] , [] , "unary" ], + ["bulkMemory" , "memory.init" , ["0xFC", "0x08"], [["dataIndex", "UInt32"]] , null ], + ["bulkMemory" , "data.drop" , ["0xFC", "0x09"], [["dataIndex", "UInt32"]] , null ], + ["bulkMemory" , "memory.copy" , ["0xFC", "0x0A"], [["dstMem", "UInt32"], ["srcMem", "UInt32"]] , null ], + ["bulkMemory" , "memory.fill" , ["0xFC", "0x0B"], [["memory", "UInt32"]] , null ], + ["bulkMemory" , "table.init" , ["0xFC", "0x0C"], [["elemIndex", "UInt32"], ["table", "UInt32"]] , null ], + ["bulkMemory" , "elem.drop" , ["0xFC", "0x0D"], [["elemIndex", "UInt32"]] , null ], + ["bulkMemory" , "table.copy" , ["0xFC", "0x0E"], [["dstTable", "UInt32"], ["srcTable", "UInt32"]] , null ], + ["referenceTypes" , "table.fill" , ["0xFC", "0x11"], [["table", "UInt32"]] , null ], + ["referenceTypes" , "table.get" , ["0x25"] , [["table", "UInt32"]] , null ], + ["referenceTypes" , "table.set" , ["0x26"] , [["table", "UInt32"]] , null ], + ["referenceTypes" , "table.grow" , ["0xFC", "0x0F"], [["table", "UInt32"]] , null ], + ["referenceTypes" , "table.size" , ["0xFC", "0x10"], [["table", "UInt32"]] , null ], + ["saturatingFloatToInt", "i32.trunc_sat_f32_s" , ["0xFC", "0x00"], [] , "conversion"], + ["saturatingFloatToInt", "i32.trunc_sat_f32_u" , ["0xFC", "0x01"], [] , "conversion"], + ["saturatingFloatToInt", "i32.trunc_sat_f64_s" , ["0xFC", "0x02"], [] , "conversion"], + ["saturatingFloatToInt", "i32.trunc_sat_f64_u" , ["0xFC", "0x03"], [] , "conversion"], + ["saturatingFloatToInt", "i64.trunc_sat_f32_s" , ["0xFC", "0x04"], [] , "conversion"], + ["saturatingFloatToInt", "i64.trunc_sat_f32_u" , ["0xFC", "0x05"], [] , "conversion"], + ["saturatingFloatToInt", "i64.trunc_sat_f64_s" , ["0xFC", "0x06"], [] , "conversion"], + ["saturatingFloatToInt", "i64.trunc_sat_f64_u" , ["0xFC", "0x07"], [] , "conversion"] ] diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index 65524663..60b5275f 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -10,8 +10,7 @@ enum WasmGen { struct Instruction: Decodable { let feature: String let name: Name - let prefix: UInt8? - let opcode: UInt8 + let opcode: [UInt8] let immediates: [Immediate] let category: String? @@ -75,18 +74,13 @@ enum WasmGen { init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() - func decodeHex() throws -> UInt8 { - let hexString = try container.decode(String.self) - return UInt8(hexString.dropFirst(2), radix: 16)! + func decodeHexArray() throws -> [UInt8] { + let hexStrings = try container.decode([String].self) + return hexStrings.map { UInt8($0.dropFirst(2), radix: 16)! } } feature = try container.decode(String.self) name = try container.decode(Name.self) - if (try? container.decodeNil()) == true { - prefix = nil - } else { - prefix = try decodeHex() - } - opcode = try decodeHex() + opcode = try decodeHexArray() let rawImmediates = try container.decode([[String]].self) immediates = rawImmediates.map { Immediate(label: $0[0], type: $0[1]) } category = try? container.decode(String.self) @@ -314,7 +308,7 @@ enum WasmGen { return code } - static func generateTextParser(_ instructions: InstructionSet) -> String { + static func generateTextInstructionParser(_ instructions: InstructionSet) -> String { var code = """ import WasmParser import WasmTypes @@ -399,15 +393,16 @@ enum WasmGen { return code } - static func generateInstructionEncoder(_ instructions: InstructionSet) -> String { + static func generateBinaryInstructionEncoder(_ instructions: InstructionSet) -> String { var code = """ import WasmParser import WasmTypes - /// An instruction encoder that is responsible for encoding opcodes and immediates. - protocol InstructionEncoder: InstructionVisitor { + /// An instruction encoder that is responsible for encoding opcodes and immediates + /// in Wasm binary format. + protocol BinaryInstructionEncoder: InstructionVisitor { /// Encodes an instruction opcode. - mutating func encodeInstruction(_ opcode: UInt8, _ prefix: UInt8?) throws + mutating func encodeInstruction(_ opcode: [UInt8]) throws // MARK: - Immediates encoding @@ -443,8 +438,8 @@ enum WasmGen { code += """ } - // InstructionEncoder implements the InstructionVisitor protocol to call the corresponding encode method. - extension InstructionEncoder { + // BinaryInstructionEncoder implements the InstructionVisitor protocol to call the corresponding encode method. + extension BinaryInstructionEncoder { """ @@ -462,25 +457,20 @@ enum WasmGen { var encodeInstrCall: String if let category = instruction.explicitCategory { code += "\n" - code += " let (prefix, opcode): (UInt8?, UInt8)\n" + code += " let opcode: [UInt8]\n" code += " switch \(category) {\n" for sourceInstruction in instruction.sourceInstructions { - code += " case .\(sourceInstruction.name.enumCase): (prefix, opcode) = (" - code += sourceInstruction.prefix.map { String(format: "0x%02X", $0) } ?? "nil" - code += ", " - code += String(format: "0x%02X", sourceInstruction.opcode) - code += ")\n" + code += " case .\(sourceInstruction.name.enumCase): opcode = [" + code += sourceInstruction.opcode.map { String(format: "0x%02X", $0) }.joined(separator: ", ") + code += "]\n" } code += " }\n" - encodeInstrCall = "try encodeInstruction(opcode, prefix)" + encodeInstrCall = "try encodeInstruction(opcode)" } else { let instruction = instruction.sourceInstructions[0] - encodeInstrCall = "try encodeInstruction(" - encodeInstrCall += [ - String(format: "0x%02X", instruction.opcode), - instruction.prefix.map { String(format: "0x%02X", $0) } ?? "nil", - ].joined(separator: ", ") - encodeInstrCall += ")" + encodeInstrCall = "try encodeInstruction([" + encodeInstrCall += instruction.opcode.map { String(format: "0x%02X", $0) }.joined(separator: ", ") + encodeInstrCall += "])" } if instruction.immediates.isEmpty, instruction.explicitCategory == nil { @@ -504,6 +494,127 @@ enum WasmGen { return code } + static func generateBinaryInstructionDecoder(_ instructions: InstructionSet) -> String { + struct Trie { + var children: [UInt8: Trie] = [:] + /// An instruction corresponding to this terminal trie node + let instruction: Instruction? + + init(instruction: Instruction? = nil) { + self.instruction = instruction + } + + mutating func insert(_ opcode: S, instruction: Instruction) where S.Element == UInt8 { + guard let first = opcode.first else { return } + let isTermination = opcode.count == 1 + if isTermination { + assert(children[first] == nil) + children[first] = Trie(instruction: instruction) + } else { + children[first, default: Trie(instruction: nil)].insert(opcode.dropFirst(), instruction: instruction) + } + } + } + + var root = Trie() + for instruction in instructions { + root.insert(instruction.opcode, instruction: instruction) + } + var code = """ + import WasmTypes + + @usableFromInline + protocol BinaryInstructionDecoder { + /// Claim the next byte to be decoded + @inlinable func claimNextByte() throws -> UInt8 + /// Visit unknown instruction + @inlinable func visitUnknown(_ opcode: [UInt8]) throws + + """ + for instruction in instructions.categorized { + guard !instruction.immediates.isEmpty else { continue } + code += " /// Decode \(instruction.description) immediates\n" + code += " @inlinable mutating func \(instruction.visitMethodName)(" + if let categoryType = instruction.categoryTypeName { + code += "_: Instruction.\(categoryType)" + } + code += ") throws -> " + if instruction.immediates.count == 1 { + code += "\(instruction.immediates[0].type)" + } else { + code += "(" + instruction.immediates.map { "\($0.label): \($0.type)" }.joined(separator: ", ") + ")" + } + code += "\n" + } + code += """ + } + + """ + + code += """ + @inlinable + func parseBinaryInstruction(visitor: inout V, decoder: inout D) throws -> Bool { + """ + + func renderSwitchCase(_ root: Trie, depth: Int = 0) { + let indent = String(repeating: " ", count: (depth + 1) * 4) + func opcodeByteName(_ depth: Int) -> String { "opcode\(depth)" } + let opcodeByte = opcodeByteName(depth) + code += """ + + \(indent)let \(opcodeByte) = try decoder.claimNextByte() + \(indent)switch \(opcodeByte) { + + """ + for (opcode, trie) in root.children.sorted(by: { $0.key < $1.key }) { + code += "\(indent)case \(String(format: "0x%02X", opcode)):\n" + if let instruction = trie.instruction { + if !instruction.immediates.isEmpty { + code += "\(indent) let (" + code += instruction.immediates.map(\.label).joined(separator: ", ") + code += ") = try decoder.\(instruction.visitMethodName)(" + if instruction.category != nil { + code += ".\(instruction.name.enumCase)" + } + code += ")\n" + } + + code += "\(indent) try visitor.\(instruction.visitMethodName)(" + var arguments: [(label: String?, value: String)] = [] + if instruction.category != nil { + arguments.append((label: nil, value: ".\(instruction.name.enumCase)")) + } + for immediate in instruction.immediates { + arguments.append((label: immediate.label, value: immediate.label)) + } + code += arguments.map { i in + if let label = i.label { + return "\(label): \(i.value)" + } else { + return i.value + } + }.joined(separator: ", ") + code += ")\n" + if instruction.name.text == "end" { + code += "\(indent) return true\n" + } + } else { + renderSwitchCase(trie, depth: depth + 1) + } + } + code += "\(indent)default:\n" + code += "\(indent) try decoder.visitUnknown(" + code += "[" + (0...depth).map { opcodeByteName($0) }.joined(separator: ", ") + "]" + code += ")\n" + code += "\(indent)}\n" + } + + renderSwitchCase(root) + code += " return false\n" + code += "}\n" + return code + } + static func formatInstructionSet(_ instructions: InstructionSet) -> String { var json = "" json += "[\n" @@ -524,16 +635,9 @@ enum WasmGen { case .withEnumCase(let name): return "{\"enumCase\": \"\(name.enumCase)\"}" } }), - ColumnInfo( - header: "Prefix", - value: { i in - if let prefix = i.prefix { - return "\"" + String(format: "0x%02X", prefix) + "\"" - } else { - return "null" - } - }), - ColumnInfo(header: "Opcode", value: { "\"" + String(format: "0x%02X", $0.opcode) + "\"" }), + ColumnInfo(header: "Opcode", value: { + "[" + $0.opcode.map { "\"" + String(format: "0x%02X", $0) + "\"" }.joined(separator: ", ") + "]" + }), ColumnInfo( header: "Immediates", value: { i in @@ -613,12 +717,16 @@ enum WasmGen { + "\n" ), GeneratedFile( - projectSources + ["WAT", "ParseInstruction.swift"], - header + generateTextParser(instructions) + projectSources + ["WasmParser", "BinaryInstructionDecoder.swift"], + header + generateBinaryInstructionDecoder(instructions) + ), + GeneratedFile( + projectSources + ["WAT", "ParseTextInstruction.swift"], + header + generateTextInstructionParser(instructions) ), GeneratedFile( - projectSources + ["WAT", "InstructionEncoder.swift"], - header + generateInstructionEncoder(instructions) + projectSources + ["WAT", "BinaryInstructionEncoder.swift"], + header + generateBinaryInstructionEncoder(instructions) ), ] diff --git a/Vendor/dependencies.json b/Vendor/dependencies.json index ad2d4192..247c19ec 100644 --- a/Vendor/dependencies.json +++ b/Vendor/dependencies.json @@ -16,7 +16,7 @@ }, "swift-format": { "repository": "https://github.com/swiftlang/swift-format.git", - "revision": "b268009b0d1182f9a573311c1a69eee9a7fd3d3f", + "revision": "c7a8b752e35d96577d1e9191d27cd9ea57dce2f2", "categories": ["default"] }, "wish-you-were-fast": {