From 1ea8c2eef7441ed4e191ded0be1c53812cffa87a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 20 Oct 2025 14:36:53 +0100 Subject: [PATCH 1/7] Make `InstructionTranslator` non-copyable This avoids unintentional possible ARC traffic if `InstructionTranslator` is accidentally copied, as it stores references to classes like `ISeqAllocator`. --- Sources/WasmKit/Execution/Function.swift | 23 +++++++++---------- Sources/WasmKit/Translator.swift | 16 ++++++------- .../WasmParser/BinaryInstructionDecoder.swift | 2 +- Sources/WasmParser/InstructionVisitor.swift | 4 ++-- Sources/WasmParser/WasmParser.swift | 4 ++-- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/Sources/WasmKit/Execution/Function.swift b/Sources/WasmKit/Execution/Function.swift index 3786cf16..a2d57d86 100644 --- a/Sources/WasmKit/Execution/Function.swift +++ b/Sources/WasmKit/Execution/Function.swift @@ -253,19 +253,18 @@ struct WasmFunctionEntity { let store = store.value let engine = store.engine let type = self.type - var translator = try InstructionTranslator( - allocator: store.allocator.iseqAllocator, - engineConfiguration: engine.configuration, - funcTypeInterner: engine.funcTypeInterner, - module: instance, - type: engine.resolveType(type), - locals: code.locals, - functionIndex: index, - codeSize: code.expression.count, - isIntercepting: engine.interceptor != nil - ) let iseq = try code.withValue { code in - try translator.translate(code: code) + try InstructionTranslator( + allocator: store.allocator.iseqAllocator, + engineConfiguration: engine.configuration, + funcTypeInterner: engine.funcTypeInterner, + module: instance, + type: engine.resolveType(type), + locals: code.locals, + functionIndex: index, + codeSize: code.expression.count, + isIntercepting: engine.interceptor != nil + ).translate(code: code) } self.code = .compiled(iseq) return iseq diff --git a/Sources/WasmKit/Translator.swift b/Sources/WasmKit/Translator.swift index 6f3e1116..b7544472 100644 --- a/Sources/WasmKit/Translator.swift +++ b/Sources/WasmKit/Translator.swift @@ -293,7 +293,7 @@ struct StackLayout { } } -struct InstructionTranslator: InstructionVisitor { +struct InstructionTranslator: ~Copyable, InstructionVisitor { typealias Output = Void typealias LabelRef = Int @@ -526,15 +526,15 @@ struct InstructionTranslator: InstructionVisitor { } } - fileprivate struct ISeqBuilder { + fileprivate struct ISeqBuilder: ~Copyable { typealias InstructionFactoryWithLabel = ( - ISeqBuilder, + borrowing ISeqBuilder, // The position of the next slot of the creating instruction _ source: MetaProgramCounter, // The position of the resolved label _ target: MetaProgramCounter ) -> (WasmKit.Instruction) - typealias BrTableEntryFactory = (ISeqBuilder, MetaProgramCounter) -> Instruction.BrTableOperand.Entry + typealias BrTableEntryFactory = (borrowing ISeqBuilder, MetaProgramCounter) -> Instruction.BrTableOperand.Entry typealias BuildingBrTable = UnsafeMutableBufferPointer enum OnPinAction { @@ -639,7 +639,7 @@ struct InstructionTranslator: InstructionVisitor { } } - func finalize() -> [UInt64] { + consuming func finalize() -> [UInt64] { return instructions } @@ -707,7 +707,7 @@ struct InstructionTranslator: InstructionVisitor { line: UInt = #line, make: @escaping ( - ISeqBuilder, + borrowing ISeqBuilder, // The position of the next slot of the creating instruction _ source: MetaProgramCounter, // The position of the resolved label @@ -1077,7 +1077,7 @@ struct InstructionTranslator: InstructionVisitor { try valueStack.truncate(height: currentFrame.stackHeight) } - private mutating func finalize() throws -> InstructionSequence { + private consuming func finalize() throws -> InstructionSequence { if controlStack.numberOfFrames > 1 { throw ValidationError(.expectedMoreEndInstructions(count: controlStack.numberOfFrames - 1)) } @@ -1102,7 +1102,7 @@ struct InstructionTranslator: InstructionVisitor { // MARK: Main entry point /// Translate a Wasm expression into a sequence of instructions. - mutating func translate(code: Code) throws -> InstructionSequence { + consuming func translate(code: Code) throws -> InstructionSequence { if isIntercepting { // Emit `onEnter` instruction at the beginning of the function emit(.onEnter(functionIndex)) diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift index 5cc84908..4ea7a0d7 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -90,7 +90,7 @@ protocol BinaryInstructionDecoder { } @inlinable -func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { +func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { let opcode0 = try decoder.claimNextByte() switch opcode0 { case 0x00: diff --git a/Sources/WasmParser/InstructionVisitor.swift b/Sources/WasmParser/InstructionVisitor.swift index 2a6b0271..e236890c 100644 --- a/Sources/WasmParser/InstructionVisitor.swift +++ b/Sources/WasmParser/InstructionVisitor.swift @@ -309,7 +309,7 @@ extension AnyInstructionVisitor { /// /// The visitor pattern is used while parsing WebAssembly expressions to allow for easy extensibility. /// See the expression parsing method ``Code/parseExpression(visitor:)`` -public protocol InstructionVisitor { +public protocol InstructionVisitor: ~Copyable { /// Visiting `unreachable` instruction. mutating func visitUnreachable() throws /// Visiting `nop` instruction. @@ -482,7 +482,7 @@ extension InstructionVisitor { } // MARK: - Placeholder implementations -extension InstructionVisitor { +extension InstructionVisitor where Self: ~Copyable { public mutating func visitUnreachable() throws {} public mutating func visitNop() throws {} public mutating func visitBlock(blockType: BlockType) throws {} diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 0bca6049..791b0712 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -160,7 +160,7 @@ public struct ExpressionParser { } @inlinable - public mutating func visit(visitor: inout V) throws -> Bool { + public mutating func visit(visitor: inout some InstructionVisitor & ~Copyable) throws -> Bool { isLastEnd = try parser.parseInstruction(visitor: &visitor) let shouldContinue = try !parser.stream.hasReachedEnd() if !shouldContinue { @@ -751,7 +751,7 @@ extension Parser: BinaryInstructionDecoder { /// Returns: `true` if the parsed instruction is the block end instruction. @inline(__always) @inlinable - mutating func parseInstruction(visitor v: inout V) throws -> Bool { + mutating func parseInstruction(visitor v: inout some InstructionVisitor & ~Copyable) throws -> Bool { return try parseBinaryInstruction(visitor: &v, decoder: &self) } From a544abedab03671a811f91678b4a4edac1dcaac4 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 20 Oct 2025 15:04:08 +0100 Subject: [PATCH 2/7] Fix missing atomic `store` instructions --- Sources/WasmParser/BinaryInstructionDecoder.swift | 2 +- Sources/WasmParser/InstructionVisitor.swift | 2 +- Utilities/Sources/WasmGen.swift | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift index 4ea7a0d7..5cc84908 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -90,7 +90,7 @@ protocol BinaryInstructionDecoder { } @inlinable -func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { +func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { let opcode0 = try decoder.claimNextByte() switch opcode0 { case 0x00: diff --git a/Sources/WasmParser/InstructionVisitor.swift b/Sources/WasmParser/InstructionVisitor.swift index e236890c..cd7d9fb6 100644 --- a/Sources/WasmParser/InstructionVisitor.swift +++ b/Sources/WasmParser/InstructionVisitor.swift @@ -420,7 +420,7 @@ public protocol InstructionVisitor: ~Copyable { mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool } -extension InstructionVisitor { +extension InstructionVisitor where Self: ~Copyable { /// Visits an instruction. public mutating func visit(_ instruction: Instruction) throws { switch instruction { diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index af354614..f03b2dc4 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -95,7 +95,7 @@ enum WasmGen { /// /// The visitor pattern is used while parsing WebAssembly expressions to allow for easy extensibility. /// See the expression parsing method ``Code/parseExpression(visitor:)`` - public protocol InstructionVisitor { + public protocol InstructionVisitor: ~Copyable { """ for instruction in instructions.categorized { @@ -118,7 +118,7 @@ enum WasmGen { code += """ - extension InstructionVisitor { + extension InstructionVisitor where Self: ~Copyable { /// Visits an instruction. public mutating func visit(_ instruction: Instruction) throws { switch instruction { @@ -150,7 +150,7 @@ enum WasmGen { code += """ // MARK: - Placeholder implementations - extension InstructionVisitor { + extension InstructionVisitor where Self: ~Copyable { """ for instruction in instructions.categorized { From f7023390d47a82e0a15b51c322ba53da920f5463 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 20 Oct 2025 15:04:54 +0100 Subject: [PATCH 3/7] Add missing `~Copyable` constraint to `WasmGen.swift` --- Sources/WasmParser/BinaryInstructionDecoder.swift | 2 +- Utilities/Sources/WasmGen.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift index 5cc84908..4ea7a0d7 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -90,7 +90,7 @@ protocol BinaryInstructionDecoder { } @inlinable -func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { +func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { let opcode0 = try decoder.claimNextByte() switch opcode0 { case 0x00: diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index f03b2dc4..732559c1 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -561,7 +561,7 @@ enum WasmGen { code += """ @inlinable - func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { + func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { """ func renderSwitchCase(_ root: Trie, depth: Int = 0) { From c6a99f88ba598062ec8fd15295118a050a8f6e72 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 20 Oct 2025 15:07:08 +0100 Subject: [PATCH 4/7] Clean up formatting --- Sources/WasmParser/BinaryInstructionDecoder.swift | 5 ++++- Utilities/Sources/WasmGen.swift | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift index 4ea7a0d7..cc1337af 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -90,7 +90,10 @@ protocol BinaryInstructionDecoder { } @inlinable -func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { +func parseBinaryInstruction( + visitor: inout some InstructionVisitor & ~Copyable, + decoder: inout some BinaryInstructionDecoder +) throws -> Bool { let opcode0 = try decoder.claimNextByte() switch opcode0 { case 0x00: diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index 732559c1..a1addda2 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -561,7 +561,10 @@ enum WasmGen { code += """ @inlinable - func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { + func parseBinaryInstruction( + visitor: inout some InstructionVisitor & ~Copyable, + decoder: inout some BinaryInstructionDecoder + ) throws -> Bool { """ func renderSwitchCase(_ root: Trie, depth: Int = 0) { From db4647ef0e712b83efe815c599d3f03fe309c16d Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 13 Nov 2025 20:07:21 +0000 Subject: [PATCH 5/7] Disable Windows build steps in main.yml Comment out the Windows build steps in the CI workflow. --- .github/workflows/main.yml | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3adac501..0d4a9a23 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -254,27 +254,27 @@ jobs: android-api-level: 30 swift-version: "${{ matrix.swift-version }}" - build-windows: - runs-on: windows-latest - steps: - - uses: compnerd/gha-setup-swift@main - with: - swift-version: swift-6.2-release - swift-build: 6.2-RELEASE - - uses: actions/checkout@v4 - - run: python3 ./Vendor/checkout-dependency - # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error - # # Check Windows build with CMake - # - uses: Cyberboss/install-winget@v1 - # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements - # - run: | - # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # - run: cmake -G Ninja -B .build/cmake - # - run: cmake --build .build/cmake - # Run tests with SwiftPM - - name: Run tests with SwiftPM - run: swift test + # build-windows: + # runs-on: windows-latest + # steps: + # - uses: compnerd/gha-setup-swift@main + # with: + # swift-version: swift-6.2-release + # swift-build: 6.2-RELEASE + # - uses: actions/checkout@v4 + # - run: python3 ./Vendor/checkout-dependency + # # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error + # # # Check Windows build with CMake + # # - uses: Cyberboss/install-winget@v1 + # # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements + # # - run: | + # # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # # - run: cmake -G Ninja -B .build/cmake + # # - run: cmake --build .build/cmake + # # Run tests with SwiftPM + # - name: Run tests with SwiftPM + # run: swift test build-cmake: runs-on: ubuntu-24.04 From d903348fb1788704f872d2691f46ce7c18c42c1a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sun, 7 Dec 2025 14:14:12 +0000 Subject: [PATCH 6/7] Restore and update Windows build workflow Re-enable Windows build workflow with latest `main` development snapshots. --- .github/workflows/main.yml | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0d4a9a23..ab68454f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -254,27 +254,27 @@ jobs: android-api-level: 30 swift-version: "${{ matrix.swift-version }}" - # build-windows: - # runs-on: windows-latest - # steps: - # - uses: compnerd/gha-setup-swift@main - # with: - # swift-version: swift-6.2-release - # swift-build: 6.2-RELEASE - # - uses: actions/checkout@v4 - # - run: python3 ./Vendor/checkout-dependency - # # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error - # # # Check Windows build with CMake - # # - uses: Cyberboss/install-winget@v1 - # # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements - # # - run: | - # # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # # - run: cmake -G Ninja -B .build/cmake - # # - run: cmake --build .build/cmake - # # Run tests with SwiftPM - # - name: Run tests with SwiftPM - # run: swift test + build-windows: + runs-on: windows-latest + steps: + - uses: compnerd/gha-setup-swift@main + with: + swift-version: development + swift-build: swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a + - uses: actions/checkout@v4 + - run: python3 ./Vendor/checkout-dependency + # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error + # # Check Windows build with CMake + # - uses: Cyberboss/install-winget@v1 + # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements + # - run: | + # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # - run: cmake -G Ninja -B .build/cmake + # - run: cmake --build .build/cmake + # Run tests with SwiftPM + - name: Run tests with SwiftPM + run: swift test build-cmake: runs-on: ubuntu-24.04 From 0b43e0354dacc82ceb7e76c31a31da02988dc733 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sun, 7 Dec 2025 14:15:29 +0000 Subject: [PATCH 7/7] Fix swift-build version format in Windows job --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ab68454f..ffdc928d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -260,7 +260,7 @@ jobs: - uses: compnerd/gha-setup-swift@main with: swift-version: development - swift-build: swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a + swift-build: DEVELOPMENT-SNAPSHOT-2025-12-01-a - uses: actions/checkout@v4 - run: python3 ./Vendor/checkout-dependency # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error