From f19b613fc05a0cac61f7a3098eeb7fd45d7593ae Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 7 Oct 2025 13:10:09 +0100 Subject: [PATCH 1/8] Use `package` access control for `BinaryInstructionDecoder` This is a preparation for a future internal breakpoint instruction, for which we need `visitUnknown` of `BinaryInstructionDecoder` to be available in the `WasmKit` module. Bumped `swift-tools-version` to 6.0 to get proper support for `package` in SwiftPM enabled. --- Package.swift | 2 +- Sources/WasmKit/Execution/Function.swift | 8 +- .../WasmParser/BinaryInstructionDecoder.swift | 2 +- Sources/WasmParser/WasmParser.swift | 80 +++++++++---------- Utilities/Sources/WasmGen.swift | 2 +- 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/Package.swift b/Package.swift index 720f3b4f..9e37db0a 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.8 +// swift-tools-version:6.0 import PackageDescription diff --git a/Sources/WasmKit/Execution/Function.swift b/Sources/WasmKit/Execution/Function.swift index 52fc06f2..0395ad55 100644 --- a/Sources/WasmKit/Execution/Function.swift +++ b/Sources/WasmKit/Execution/Function.swift @@ -124,6 +124,8 @@ struct InternalFunction: Equatable, Hashable { _storage = bitPattern } + /// Returns `true` if the function is defined as a Wasm function in its original module. + /// Returns `false` if the function is implemented by the host. var isWasm: Bool { _storage & 0b1 == 0 } @@ -241,7 +243,7 @@ struct WasmFunctionEntity { switch code { case .uncompiled(let code): return try compile(store: store, code: code) - case .compiled(let iseq): + case .compiled(let iseq), .compiledAndPatchable(_, let iseq): return iseq } } @@ -281,7 +283,8 @@ extension EntityHandle { $0.code = .compiled(iseq) return iseq } - case .compiled(let iseq): return iseq + case .compiled(let iseq), .compiledAndPatchable(_, let iseq): + return iseq } } } @@ -313,6 +316,7 @@ struct InstructionSequence { enum CodeBody { case uncompiled(InternalUncompiledCode) case compiled(InstructionSequence) + case compiledAndPatchable(InternalUncompiledCode, InstructionSequence) } extension Reference { diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift index a89443c2..6a16276e 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -5,7 +5,7 @@ import WasmTypes @usableFromInline -protocol BinaryInstructionDecoder { +package protocol BinaryInstructionDecoder { /// Claim the next byte to be decoded @inlinable func claimNextByte() throws -> UInt8 /// Visit unknown instruction diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 2f8374b2..6f666823 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -606,23 +606,23 @@ extension Parser: BinaryInstructionDecoder { return 0 } - @inlinable func visitUnknown(_ opcode: [UInt8]) throws { + @inlinable package func visitUnknown(_ opcode: [UInt8]) throws { throw makeError(.illegalOpcode(opcode)) } - @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 { + @inlinable package mutating func visitBlock() throws -> BlockType { try parseResultType() } + @inlinable package mutating func visitLoop() throws -> BlockType { try parseResultType() } + @inlinable package mutating func visitIf() throws -> BlockType { try parseResultType() } + @inlinable package mutating func visitBr() throws -> UInt32 { try parseUnsigned() } + @inlinable package mutating func visitBrIf() throws -> UInt32 { try parseUnsigned() } + @inlinable package 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() } + @inlinable package mutating func visitCall() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) { + @inlinable package 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 @@ -632,17 +632,17 @@ extension Parser: BinaryInstructionDecoder { return (typeIndex, tableIndex) } - @inlinable mutating func visitReturnCall() throws -> UInt32 { + @inlinable package mutating func visitReturnCall() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitReturnCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) { + @inlinable package mutating func visitReturnCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) { let typeIndex: TypeIndex = try parseUnsigned() let tableIndex: TableIndex = try parseUnsigned() return (typeIndex, tableIndex) } - @inlinable mutating func visitTypedSelect() throws -> WasmTypes.ValueType { + @inlinable package 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)) @@ -650,36 +650,36 @@ extension Parser: BinaryInstructionDecoder { 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 { + @inlinable package mutating func visitLocalGet() throws -> UInt32 { try parseUnsigned() } + @inlinable package mutating func visitLocalSet() throws -> UInt32 { try parseUnsigned() } + @inlinable package mutating func visitLocalTee() throws -> UInt32 { try parseUnsigned() } + @inlinable package mutating func visitGlobalGet() throws -> UInt32 { try parseUnsigned() } + @inlinable package mutating func visitGlobalSet() throws -> UInt32 { try parseUnsigned() } + @inlinable package mutating func visitLoad(_: Instruction.Load) throws -> MemArg { try parseMemarg() } + @inlinable package mutating func visitStore(_: Instruction.Store) throws -> MemArg { try parseMemarg() } + @inlinable package mutating func visitMemorySize() throws -> UInt32 { try parseMemoryIndex() } - @inlinable mutating func visitMemoryGrow() throws -> UInt32 { + @inlinable package mutating func visitMemoryGrow() throws -> UInt32 { try parseMemoryIndex() } - @inlinable mutating func visitI32Const() throws -> Int32 { + @inlinable package mutating func visitI32Const() throws -> Int32 { let n: UInt32 = try parseInteger() return Int32(bitPattern: n) } - @inlinable mutating func visitI64Const() throws -> Int64 { + @inlinable package mutating func visitI64Const() throws -> Int64 { let n: UInt64 = try parseInteger() return Int64(bitPattern: n) } - @inlinable mutating func visitF32Const() throws -> IEEE754.Float32 { + @inlinable package mutating func visitF32Const() throws -> IEEE754.Float32 { let n = try parseFloat() return IEEE754.Float32(bitPattern: n) } - @inlinable mutating func visitF64Const() throws -> IEEE754.Float64 { + @inlinable package mutating func visitF64Const() throws -> IEEE754.Float64 { let n = try parseDouble() return IEEE754.Float64(bitPattern: n) } - @inlinable mutating func visitRefNull() throws -> WasmTypes.ReferenceType { + @inlinable package mutating func visitRefNull() throws -> WasmTypes.ReferenceType { let type = try parseValueType() guard case let .ref(refType) = type else { throw makeError(.expectedRefType(actual: type)) @@ -687,24 +687,24 @@ extension Parser: BinaryInstructionDecoder { return refType } - @inlinable mutating func visitRefFunc() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitMemoryInit() throws -> UInt32 { + @inlinable package mutating func visitRefFunc() throws -> UInt32 { try parseUnsigned() } + @inlinable package mutating func visitMemoryInit() throws -> UInt32 { let dataIndex: DataIndex = try parseUnsigned() _ = try parseMemoryIndex() return dataIndex } - @inlinable mutating func visitDataDrop() throws -> UInt32 { + @inlinable package mutating func visitDataDrop() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitMemoryCopy() throws -> (dstMem: UInt32, srcMem: UInt32) { + @inlinable package mutating func visitMemoryCopy() throws -> (dstMem: UInt32, srcMem: UInt32) { _ = try parseMemoryIndex() _ = try parseMemoryIndex() return (0, 0) } - @inlinable mutating func visitMemoryFill() throws -> UInt32 { + @inlinable package mutating func visitMemoryFill() throws -> UInt32 { let zero = try stream.consumeAny() guard zero == 0x00 else { throw makeError(.zeroExpected(actual: zero)) @@ -712,35 +712,35 @@ extension Parser: BinaryInstructionDecoder { return 0 } - @inlinable mutating func visitTableInit() throws -> (elemIndex: UInt32, table: UInt32) { + @inlinable package 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 { + @inlinable package mutating func visitElemDrop() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitTableCopy() throws -> (dstTable: UInt32, srcTable: UInt32) { + @inlinable package 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 { + @inlinable package mutating func visitTableFill() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitTableGet() throws -> UInt32 { + @inlinable package mutating func visitTableGet() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitTableSet() throws -> UInt32 { + @inlinable package mutating func visitTableSet() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitTableGrow() throws -> UInt32 { + @inlinable package mutating func visitTableGrow() throws -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitTableSize() throws -> UInt32 { + @inlinable package mutating func visitTableSize() throws -> UInt32 { try parseUnsigned() } - @inlinable func claimNextByte() throws -> UInt8 { + @inlinable package func claimNextByte() throws -> UInt8 { return try stream.consumeAny() } diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index 60b5275f..d5b055a5 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -524,7 +524,7 @@ enum WasmGen { import WasmTypes @usableFromInline - protocol BinaryInstructionDecoder { + package protocol BinaryInstructionDecoder { /// Claim the next byte to be decoded @inlinable func claimNextByte() throws -> UInt8 /// Visit unknown instruction From 4394e5659b4caa5372b81bb3909801fcf5414ed0 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 7 Oct 2025 13:11:43 +0100 Subject: [PATCH 2/8] Remove 5.10 GHA jobs from `main.yml` --- .github/workflows/main.yml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 701a47cf..653d9d26 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,14 +14,6 @@ jobs: strategy: matrix: include: - # Swift 5.10 - - os: macos-14 - xcode: Xcode_15.4 - development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a - wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" - wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi - wasi-swift-sdk-checksum: "37516de837411ea46e4f9e75d52bd742f6941febac49981aac0c4f20f02b8b54" - test-args: "" # Swift 6.0 - os: macos-14 xcode: Xcode_16.2 @@ -97,16 +89,6 @@ jobs: strategy: matrix: include: - - swift: "swift:5.10-focal" - development-toolchain-download: "https://download.swift.org/development/ubuntu2004/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a-ubuntu20.04.tar.gz" - wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" - wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi - wasi-swift-sdk-checksum: "37516de837411ea46e4f9e75d52bd742f6941febac49981aac0c4f20f02b8b54" - - swift: "swift:5.10-amazonlinux2" - development-toolchain-download: "https://download.swift.org/development/amazonlinux2/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a-amazonlinux2.tar.gz" - wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" - wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi - wasi-swift-sdk-checksum: "37516de837411ea46e4f9e75d52bd742f6941febac49981aac0c4f20f02b8b54" - swift: "swift:6.0-focal" development-toolchain-download: "https://download.swift.org/development/ubuntu2004/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a-ubuntu20.04.tar.gz" wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" From 7260f501c1adc3807dbf5bb4159ec90646c5f945 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 7 Oct 2025 18:16:33 +0100 Subject: [PATCH 3/8] Add internal VM breakpoint instruction, clean up `visitUnknown` --- .../Execution/DispatchInstruction.swift | 7 ++ Sources/WasmKit/Execution/Execution.swift | 5 +- .../Execution/Instructions/Control.swift | 4 + .../Execution/Instructions/Instruction.swift | 7 ++ Sources/WasmKit/Translator.swift | 10 +++ .../WasmParser/BinaryInstructionDecoder.swift | 13 +-- Sources/WasmParser/InstructionVisitor.swift | 3 + Sources/WasmParser/WasmParser.swift | 83 ++++++++++--------- .../_CWasmKit/include/DirectThreadedCode.inc | 8 ++ Utilities/Sources/VMSpec/Instruction.swift | 10 +++ Utilities/Sources/WasmGen.swift | 28 +++++-- 11 files changed, 123 insertions(+), 55 deletions(-) diff --git a/Sources/WasmKit/Execution/DispatchInstruction.swift b/Sources/WasmKit/Execution/DispatchInstruction.swift index 4d79e822..741a1eae 100644 --- a/Sources/WasmKit/Execution/DispatchInstruction.swift +++ b/Sources/WasmKit/Execution/DispatchInstruction.swift @@ -212,6 +212,7 @@ extension Execution { case 196: return self.execute_tableElementDrop(sp: &sp, pc: &pc, md: &md, ms: &ms) case 197: return self.execute_onEnter(sp: &sp, pc: &pc, md: &md, ms: &ms) case 198: return self.execute_onExit(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 199: return try self.execute_breakpoint(sp: &sp, pc: &pc, md: &md, ms: &ms) default: preconditionFailure("Unknown instruction!?") } @@ -1795,6 +1796,12 @@ extension Execution { pc.pointee = pc.pointee.advanced(by: 1) return next } + @_silgen_name("wasmkit_execute_breakpoint") @inline(__always) + mutating func execute_breakpoint(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + let next: CodeSlot + (pc.pointee, next) = try self.breakpoint(sp: &sp.pointee, pc: pc.pointee) + return next + } } extension Instruction { diff --git a/Sources/WasmKit/Execution/Execution.swift b/Sources/WasmKit/Execution/Execution.swift index 7431d20f..3702ba72 100644 --- a/Sources/WasmKit/Execution/Execution.swift +++ b/Sources/WasmKit/Execution/Execution.swift @@ -361,9 +361,12 @@ extension Execution { } } - /// A ``Error`` thrown when the execution normally ends. + /// An ``Error`` thrown when the execution normally ends. struct EndOfExecution: Error {} + /// An ``Error`` thrown when a breakpoint is triggered. + struct Breakpoint: Error {} + /// The entry point for the execution of the WebAssembly function. @inline(never) mutating func execute( diff --git a/Sources/WasmKit/Execution/Instructions/Control.swift b/Sources/WasmKit/Execution/Instructions/Control.swift index 47dbbb49..93291b7b 100644 --- a/Sources/WasmKit/Execution/Instructions/Control.swift +++ b/Sources/WasmKit/Execution/Instructions/Control.swift @@ -223,4 +223,8 @@ extension Execution { Function(handle: function, store: store.value) ) } + + mutating func breakpoint(sp: inout Sp, pc: Pc) throws -> (Pc, CodeSlot) { + throw Breakpoint() + } } diff --git a/Sources/WasmKit/Execution/Instructions/Instruction.swift b/Sources/WasmKit/Execution/Instructions/Instruction.swift index 65b4028c..4c4dd969 100644 --- a/Sources/WasmKit/Execution/Instructions/Instruction.swift +++ b/Sources/WasmKit/Execution/Instructions/Instruction.swift @@ -413,6 +413,10 @@ enum Instruction: Equatable { case onEnter(Instruction.OnEnterOperand) /// Intercept the exit of a function case onExit(Instruction.OnExitOperand) + /// Stop the VM on this instruction as a breakpoint + /// + /// This instruction is used in debugging scenarios. + case breakpoint } extension Instruction { @@ -1271,6 +1275,7 @@ extension Instruction { case .tableElementDrop: return 196 case .onEnter: return 197 case .onExit: return 198 + case .breakpoint: return 199 } } } @@ -1481,6 +1486,7 @@ extension Instruction { case 196: return .tableElementDrop(Instruction.TableElementDropOperand.load(from: &pc)) case 197: return .onEnter(Instruction.OnEnterOperand.load(from: &pc)) case 198: return .onExit(Instruction.OnExitOperand.load(from: &pc)) + case 199: return .breakpoint default: fatalError("Unknown instruction opcode: \(opcode)") } } @@ -1694,6 +1700,7 @@ extension Instruction { case 196: return "tableElementDrop" case 197: return "onEnter" case 198: return "onExit" + case 199: return "breakpoint" default: fatalError("Unknown instruction index: \(opcode)") } } diff --git a/Sources/WasmKit/Translator.swift b/Sources/WasmKit/Translator.swift index 7e6ed95a..8c0da7de 100644 --- a/Sources/WasmKit/Translator.swift +++ b/Sources/WasmKit/Translator.swift @@ -2239,6 +2239,16 @@ struct InstructionTranslator: InstructionVisitor { return .tableSize(Instruction.TableSizeOperand(tableIndex: table, result: LVReg(result))) } } + + mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool { + guard opcode.count == 1 && opcode[0] == 0xFF else { + return false + } + + emit(.breakpoint) + + return true + } } struct TranslationError: Error, CustomStringConvertible { diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift index 6a16276e..1111b67d 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -5,11 +5,11 @@ import WasmTypes @usableFromInline -package protocol BinaryInstructionDecoder { +protocol BinaryInstructionDecoder { /// Claim the next byte to be decoded @inlinable func claimNextByte() throws -> UInt8 - /// Visit unknown instruction - @inlinable func visitUnknown(_ opcode: [UInt8]) throws + + func throwUnknown(_ opcode: [UInt8]) throws -> Never /// Decode `block` immediates @inlinable mutating func visitBlock() throws -> BlockType /// Decode `loop` immediates @@ -87,8 +87,9 @@ package protocol BinaryInstructionDecoder { /// Decode `table.size` immediates @inlinable mutating func visitTableSize() throws -> UInt32 } + @inlinable -func parseBinaryInstruction(visitor: inout V, decoder: inout D) throws -> Bool { +func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { let opcode0 = try decoder.claimNextByte() switch opcode0 { case 0x00: @@ -562,10 +563,10 @@ func parseBinaryInstruction( let (table) = try decoder.visitTableFill() try visitor.visitTableFill(table: table) default: - try decoder.visitUnknown([opcode0, opcode1]) + if try !visitor.visitUnknown([opcode0, opcode1]) { try decoder.throwUnknown([opcode0, opcode1]) } } default: - try decoder.visitUnknown([opcode0]) + if try !visitor.visitUnknown([opcode0]) { try decoder.throwUnknown([opcode0]) } } return false } diff --git a/Sources/WasmParser/InstructionVisitor.swift b/Sources/WasmParser/InstructionVisitor.swift index 230ba132..2b4f3c7f 100644 --- a/Sources/WasmParser/InstructionVisitor.swift +++ b/Sources/WasmParser/InstructionVisitor.swift @@ -398,6 +398,8 @@ public protocol InstructionVisitor { mutating func visitTableGrow(table: UInt32) throws /// Visiting `table.size` instruction. mutating func visitTableSize(table: UInt32) throws + /// Returns: `true` if the parser should silently proceed parsing. + mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool } extension InstructionVisitor { @@ -514,5 +516,6 @@ extension InstructionVisitor { public mutating func visitTableSet(table: UInt32) throws {} public mutating func visitTableGrow(table: UInt32) throws {} public mutating func visitTableSize(table: UInt32) throws {} + public mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool { false } } diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 6f666823..35eeb4bf 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -606,23 +606,27 @@ extension Parser: BinaryInstructionDecoder { return 0 } - @inlinable package func visitUnknown(_ opcode: [UInt8]) throws { + @inlinable func throwUnknown(_ opcode: [UInt8]) throws -> Never { throw makeError(.illegalOpcode(opcode)) } - @inlinable package mutating func visitBlock() throws -> BlockType { try parseResultType() } - @inlinable package mutating func visitLoop() throws -> BlockType { try parseResultType() } - @inlinable package mutating func visitIf() throws -> BlockType { try parseResultType() } - @inlinable package mutating func visitBr() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitBrIf() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitBrTable() throws -> BrTable { + @inlinable func visitUnknown(_ opcode: [UInt8]) throws -> Bool { + try throwUnknown(opcode) + } + + @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 package mutating func visitCall() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitCall() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) { + @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 @@ -632,17 +636,17 @@ extension Parser: BinaryInstructionDecoder { return (typeIndex, tableIndex) } - @inlinable package mutating func visitReturnCall() throws -> UInt32 { + @inlinable mutating func visitReturnCall() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitReturnCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) { + @inlinable mutating func visitReturnCallIndirect() throws -> (typeIndex: UInt32, tableIndex: UInt32) { let typeIndex: TypeIndex = try parseUnsigned() let tableIndex: TableIndex = try parseUnsigned() return (typeIndex, tableIndex) } - @inlinable package mutating func visitTypedSelect() throws -> WasmTypes.ValueType { + @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)) @@ -650,36 +654,36 @@ extension Parser: BinaryInstructionDecoder { return results[0] } - @inlinable package mutating func visitLocalGet() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitLocalSet() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitLocalTee() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitGlobalGet() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitGlobalSet() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitLoad(_: Instruction.Load) throws -> MemArg { try parseMemarg() } - @inlinable package mutating func visitStore(_: Instruction.Store) throws -> MemArg { try parseMemarg() } - @inlinable package mutating func visitMemorySize() throws -> UInt32 { + @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 package mutating func visitMemoryGrow() throws -> UInt32 { + @inlinable mutating func visitMemoryGrow() throws -> UInt32 { try parseMemoryIndex() } - @inlinable package mutating func visitI32Const() throws -> Int32 { + @inlinable mutating func visitI32Const() throws -> Int32 { let n: UInt32 = try parseInteger() return Int32(bitPattern: n) } - @inlinable package mutating func visitI64Const() throws -> Int64 { + @inlinable mutating func visitI64Const() throws -> Int64 { let n: UInt64 = try parseInteger() return Int64(bitPattern: n) } - @inlinable package mutating func visitF32Const() throws -> IEEE754.Float32 { + @inlinable mutating func visitF32Const() throws -> IEEE754.Float32 { let n = try parseFloat() return IEEE754.Float32(bitPattern: n) } - @inlinable package mutating func visitF64Const() throws -> IEEE754.Float64 { + @inlinable mutating func visitF64Const() throws -> IEEE754.Float64 { let n = try parseDouble() return IEEE754.Float64(bitPattern: n) } - @inlinable package mutating func visitRefNull() throws -> WasmTypes.ReferenceType { + @inlinable mutating func visitRefNull() throws -> WasmTypes.ReferenceType { let type = try parseValueType() guard case let .ref(refType) = type else { throw makeError(.expectedRefType(actual: type)) @@ -687,24 +691,24 @@ extension Parser: BinaryInstructionDecoder { return refType } - @inlinable package mutating func visitRefFunc() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitMemoryInit() throws -> UInt32 { + @inlinable mutating func visitRefFunc() throws -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitMemoryInit() throws -> UInt32 { let dataIndex: DataIndex = try parseUnsigned() _ = try parseMemoryIndex() return dataIndex } - @inlinable package mutating func visitDataDrop() throws -> UInt32 { + @inlinable mutating func visitDataDrop() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitMemoryCopy() throws -> (dstMem: UInt32, srcMem: UInt32) { + @inlinable mutating func visitMemoryCopy() throws -> (dstMem: UInt32, srcMem: UInt32) { _ = try parseMemoryIndex() _ = try parseMemoryIndex() return (0, 0) } - @inlinable package mutating func visitMemoryFill() throws -> UInt32 { + @inlinable mutating func visitMemoryFill() throws -> UInt32 { let zero = try stream.consumeAny() guard zero == 0x00 else { throw makeError(.zeroExpected(actual: zero)) @@ -712,38 +716,39 @@ extension Parser: BinaryInstructionDecoder { return 0 } - @inlinable package mutating func visitTableInit() throws -> (elemIndex: UInt32, table: UInt32) { + @inlinable mutating func visitTableInit() throws -> (elemIndex: UInt32, table: UInt32) { let elementIndex: ElementIndex = try parseUnsigned() let tableIndex: TableIndex = try parseUnsigned() return (elementIndex, tableIndex) } - @inlinable package mutating func visitElemDrop() throws -> UInt32 { + @inlinable mutating func visitElemDrop() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitTableCopy() throws -> (dstTable: UInt32, srcTable: UInt32) { + @inlinable mutating func visitTableCopy() throws -> (dstTable: UInt32, srcTable: UInt32) { let destination: TableIndex = try parseUnsigned() let source: TableIndex = try parseUnsigned() return (destination, source) } - @inlinable package mutating func visitTableFill() throws -> UInt32 { + @inlinable mutating func visitTableFill() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitTableGet() throws -> UInt32 { + @inlinable mutating func visitTableGet() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitTableSet() throws -> UInt32 { + @inlinable mutating func visitTableSet() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitTableGrow() throws -> UInt32 { + @inlinable mutating func visitTableGrow() throws -> UInt32 { try parseUnsigned() } - @inlinable package mutating func visitTableSize() throws -> UInt32 { + @inlinable mutating func visitTableSize() throws -> UInt32 { try parseUnsigned() } @inlinable package func claimNextByte() throws -> UInt8 { return try stream.consumeAny() } + /// Returns: `true` if the parsed instruction is the block end instruction. @inline(__always) @inlinable mutating func parseInstruction(visitor v: inout V) throws -> Bool { diff --git a/Sources/_CWasmKit/include/DirectThreadedCode.inc b/Sources/_CWasmKit/include/DirectThreadedCode.inc index e52f81c1..71eb00a6 100644 --- a/Sources/_CWasmKit/include/DirectThreadedCode.inc +++ b/Sources/_CWasmKit/include/DirectThreadedCode.inc @@ -1262,6 +1262,13 @@ SWIFT_CC(swiftasync) static inline void wasmkit_tc_onExit(Sp sp, Pc pc, Md md, M INLINE_CALL next = wasmkit_execute_onExit(&sp, &pc, &md, &ms, state, &error); return ((wasmkit_tc_exec)next)(sp, pc, md, ms, state); } +SWIFT_CC(swiftasync) static inline void wasmkit_tc_breakpoint(Sp sp, Pc pc, Md md, Ms ms, SWIFT_CONTEXT void *state) { + SWIFT_CC(swift) uint64_t wasmkit_execute_breakpoint(Sp *sp, Pc *pc, Md *md, Ms *ms, SWIFT_CONTEXT void *state, SWIFT_ERROR_RESULT void **error); + void * _Nullable error = NULL; uint64_t next; + INLINE_CALL next = wasmkit_execute_breakpoint(&sp, &pc, &md, &ms, state, &error); + if (error) return wasmkit_execution_state_set_error(error, sp, state); + return ((wasmkit_tc_exec)next)(sp, pc, md, ms, state); +} static const uintptr_t wasmkit_tc_exec_handlers[] = { (uintptr_t)((wasmkit_tc_exec)&wasmkit_tc_copyStack), (uintptr_t)((wasmkit_tc_exec)&wasmkit_tc_globalGet), @@ -1462,4 +1469,5 @@ static const uintptr_t wasmkit_tc_exec_handlers[] = { (uintptr_t)((wasmkit_tc_exec)&wasmkit_tc_tableElementDrop), (uintptr_t)((wasmkit_tc_exec)&wasmkit_tc_onEnter), (uintptr_t)((wasmkit_tc_exec)&wasmkit_tc_onExit), + (uintptr_t)((wasmkit_tc_exec)&wasmkit_tc_breakpoint), }; diff --git a/Utilities/Sources/VMSpec/Instruction.swift b/Utilities/Sources/VMSpec/Instruction.swift index 0243ed79..dcff3f95 100644 --- a/Utilities/Sources/VMSpec/Instruction.swift +++ b/Utilities/Sources/VMSpec/Instruction.swift @@ -502,6 +502,16 @@ extension VMGen { // Profiling Instruction(name: "onEnter", documentation: "Intercept the entry of a function", immediate: "OnEnterOperand"), Instruction(name: "onExit", documentation: "Intercept the exit of a function", immediate: "OnExitOperand"), + + // Debugging + Instruction(name: "breakpoint", + documentation: """ + Stop the VM on this instruction as a breakpoint + + This instruction is used in debugging scenarios. + """, + isControl: true, mayThrow: true, mayUpdateFrame: true + ), ] // MARK: - Instruction generation diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index d5b055a5..6d16192f 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -110,6 +110,8 @@ enum WasmGen { code += """ + /// Returns: `true` if the parser should silently proceed parsing. + mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool } """ @@ -162,7 +164,11 @@ enum WasmGen { }.joined(separator: ", ") code += ") throws {}\n" } - code += "}\n" + code += """ + public mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool { false } + } + + """ return code } @@ -252,7 +258,9 @@ enum WasmGen { code += " }\n" } - code += "}" + code += """ + } + """ return code } @@ -524,11 +532,11 @@ enum WasmGen { import WasmTypes @usableFromInline - package protocol BinaryInstructionDecoder { + protocol BinaryInstructionDecoder { /// Claim the next byte to be decoded @inlinable func claimNextByte() throws -> UInt8 - /// Visit unknown instruction - @inlinable func visitUnknown(_ opcode: [UInt8]) throws + + func throwUnknown(_ opcode: [UInt8]) throws -> Never """ for instruction in instructions.categorized { @@ -552,8 +560,9 @@ enum WasmGen { """ code += """ + @inlinable - func parseBinaryInstruction(visitor: inout V, decoder: inout D) throws -> Bool { + func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { """ func renderSwitchCase(_ root: Trie, depth: Int = 0) { @@ -603,9 +612,10 @@ enum WasmGen { } } code += "\(indent)default:\n" - code += "\(indent) try decoder.visitUnknown(" - code += "[" + (0...depth).map { opcodeByteName($0) }.joined(separator: ", ") + "]" - code += ")\n" + code += "\(indent) if try !visitor.visitUnknown(" + let opcode = "[" + (0...depth).map { opcodeByteName($0) }.joined(separator: ", ") + "]" + code += opcode + code += ") { try decoder.throwUnknown(\(opcode)) }\n" code += "\(indent)}\n" } From 95eaf1d0f86a6dfd4e902be66a1a97c2df193a51 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 7 Oct 2025 21:03:01 +0100 Subject: [PATCH 4/8] Remove use of `package` in `WasmParser.swift` --- Sources/WasmParser/WasmParser.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 35eeb4bf..4b653337 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -744,7 +744,7 @@ extension Parser: BinaryInstructionDecoder { @inlinable mutating func visitTableSize() throws -> UInt32 { try parseUnsigned() } - @inlinable package func claimNextByte() throws -> UInt8 { + @inlinable func claimNextByte() throws -> UInt8 { return try stream.consumeAny() } From b1b6ef9e72f98969b03f3893b937f949656327d3 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 7 Oct 2025 21:05:32 +0100 Subject: [PATCH 5/8] Lower `swift-tools-version` back to 5.8 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 9e37db0a..720f3b4f 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:6.0 +// swift-tools-version:5.8 import PackageDescription From 593c8375f2a5b4344e564f6f5d2214daf9bad57c Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 7 Oct 2025 21:05:38 +0100 Subject: [PATCH 6/8] Revert "Remove 5.10 GHA jobs from `main.yml`" This reverts commit ab876e6e63564299d96ac78ce3c4b8c42b8f17b0. --- .github/workflows/main.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 653d9d26..701a47cf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,14 @@ jobs: strategy: matrix: include: + # Swift 5.10 + - os: macos-14 + xcode: Xcode_15.4 + development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a + wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" + wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi + wasi-swift-sdk-checksum: "37516de837411ea46e4f9e75d52bd742f6941febac49981aac0c4f20f02b8b54" + test-args: "" # Swift 6.0 - os: macos-14 xcode: Xcode_16.2 @@ -89,6 +97,16 @@ jobs: strategy: matrix: include: + - swift: "swift:5.10-focal" + development-toolchain-download: "https://download.swift.org/development/ubuntu2004/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a-ubuntu20.04.tar.gz" + wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" + wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi + wasi-swift-sdk-checksum: "37516de837411ea46e4f9e75d52bd742f6941febac49981aac0c4f20f02b8b54" + - swift: "swift:5.10-amazonlinux2" + development-toolchain-download: "https://download.swift.org/development/amazonlinux2/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a-amazonlinux2.tar.gz" + wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" + wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi + wasi-swift-sdk-checksum: "37516de837411ea46e4f9e75d52bd742f6941febac49981aac0c4f20f02b8b54" - swift: "swift:6.0-focal" development-toolchain-download: "https://download.swift.org/development/ubuntu2004/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-DEVELOPMENT-SNAPSHOT-2025-06-22-a-ubuntu20.04.tar.gz" wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2025-06-22-a-wasm32-unknown-wasi.artifactbundle.zip" From 76019bfada1aeaa5b7a0fc4424cfe7d7350de6e5 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 7 Oct 2025 21:08:56 +0100 Subject: [PATCH 7/8] Apply suggestions from code review --- Utilities/Sources/WasmGen.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index 6d16192f..af354614 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -258,9 +258,7 @@ enum WasmGen { code += " }\n" } - code += """ - } - """ + code += "}" return code } @@ -536,6 +534,7 @@ enum WasmGen { /// Claim the next byte to be decoded @inlinable func claimNextByte() throws -> UInt8 + /// Throw an error due to unknown opcode. func throwUnknown(_ opcode: [UInt8]) throws -> Never """ From 665ae2aaa9d5f3dee820e7111e6206049a12babb Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 8 Oct 2025 09:59:50 +0100 Subject: [PATCH 8/8] Add `isDebugging` flag to `InstructionTranslator` --- Sources/WasmKit/Execution/Function.swift | 2 +- Sources/WasmKit/Translator.swift | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Sources/WasmKit/Execution/Function.swift b/Sources/WasmKit/Execution/Function.swift index 0395ad55..d79eb1db 100644 --- a/Sources/WasmKit/Execution/Function.swift +++ b/Sources/WasmKit/Execution/Function.swift @@ -262,7 +262,7 @@ struct WasmFunctionEntity { locals: code.locals, functionIndex: index, codeSize: code.expression.count, - intercepting: engine.interceptor != nil + isIntercepting: engine.interceptor != nil ) let iseq = try code.withValue { code in try translator.translate(code: code) diff --git a/Sources/WasmKit/Translator.swift b/Sources/WasmKit/Translator.swift index 8c0da7de..8b8c6188 100644 --- a/Sources/WasmKit/Translator.swift +++ b/Sources/WasmKit/Translator.swift @@ -820,7 +820,9 @@ struct InstructionTranslator: InstructionVisitor { /// The index of the function in the module let functionIndex: FunctionIndex /// Whether a call to this function should be intercepted - let intercepting: Bool + let isIntercepting: Bool + /// Whether Wasm debugging facilities are currently enabled. + let isDebugging: Bool var constantSlots: ConstSlots let validator: InstructionValidator @@ -833,7 +835,8 @@ struct InstructionTranslator: InstructionVisitor { locals: [WasmTypes.ValueType], functionIndex: FunctionIndex, codeSize: Int, - intercepting: Bool + isIntercepting: Bool, + isDebugging: Bool = false ) throws { self.allocator = allocator self.funcTypeInterner = funcTypeInterner @@ -849,7 +852,8 @@ struct InstructionTranslator: InstructionVisitor { self.valueStack = ValueStack(stackLayout: stackLayout) self.locals = Locals(types: type.parameters + locals) self.functionIndex = functionIndex - self.intercepting = intercepting + self.isIntercepting = isIntercepting + self.isDebugging = isDebugging self.constantSlots = ConstSlots(stackLayout: stackLayout) self.validator = InstructionValidator(context: module) @@ -1059,7 +1063,7 @@ struct InstructionTranslator: InstructionVisitor { return emittedCopy } private mutating func translateReturn() throws { - if intercepting { + if isIntercepting { // Emit `onExit` instruction before every `return` instruction emit(.onExit(functionIndex)) } @@ -1098,7 +1102,7 @@ struct InstructionTranslator: InstructionVisitor { /// Translate a Wasm expression into a sequence of instructions. mutating func translate(code: Code) throws -> InstructionSequence { - if intercepting { + if isIntercepting { // Emit `onEnter` instruction at the beginning of the function emit(.onEnter(functionIndex)) } @@ -2241,7 +2245,7 @@ struct InstructionTranslator: InstructionVisitor { } mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool { - guard opcode.count == 1 && opcode[0] == 0xFF else { + guard self.isDebugging && opcode.count == 1 && opcode[0] == 0xFF else { return false }