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 diff --git a/README.md b/README.md index b8f78b60..5e18c092 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # WasmKit -**WasmKit** is a standalone and embeddable [WebAssembly](https://webassembly.org) runtime (virtual machine) implementation and related tooling written in Swift. Starting with Swift 6.2, WasmKit CLI executable is included in [Swift toolchains distributed at swift.org](https://swift.org/install) for Linux and macOS. +**WasmKit** is a standalone and embeddable [WebAssembly](https://webassembly.org) runtime (virtual machine) implementation and related tooling written in Swift. Starting with Swift 6.2, WasmKit CLI executable is included in [Swift toolchains distributed at swift.org](https://swift.org/install) for Linux and macOS. ## Usage diff --git a/Sources/WasmKit/Execution/Function.swift b/Sources/WasmKit/Execution/Function.swift index c552d15e..d586812a 100644 --- a/Sources/WasmKit/Execution/Function.swift +++ b/Sources/WasmKit/Execution/Function.swift @@ -254,19 +254,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 2731927d..4a08d1de 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 @@ -1086,7 +1086,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)) } @@ -1129,7 +1129,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 a6a4ac6d..88a37e24 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -93,7 +93,10 @@ 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 { visitor.binaryOffset = decoder.offset let opcode0 = try decoder.claimNextByte() switch opcode0 { diff --git a/Sources/WasmParser/InstructionVisitor.swift b/Sources/WasmParser/InstructionVisitor.swift index b44d39a8..9c12a1e1 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 { /// Current offset in visitor's instruction stream. var binaryOffset: Int { get set } @@ -423,7 +423,7 @@ public protocol InstructionVisitor { 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 { @@ -485,7 +485,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 0b7c7199..e7c7e2a3 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) } diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index 1e217bda..9354bc36 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 { /// Current offset in visitor's instruction stream. var binaryOffset: Int { get set } @@ -121,7 +121,7 @@ enum WasmGen { code += """ - extension InstructionVisitor { + extension InstructionVisitor where Self: ~Copyable { /// Visits an instruction. public mutating func visit(_ instruction: Instruction) throws { switch instruction { @@ -153,7 +153,7 @@ enum WasmGen { code += """ // MARK: - Placeholder implementations - extension InstructionVisitor { + extension InstructionVisitor where Self: ~Copyable { """ for instruction in instructions.categorized { @@ -567,7 +567,10 @@ 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 { visitor.binaryOffset = decoder.offset """