diff --git a/Package.swift b/Package.swift index bee01306..58a2f250 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,6 @@ // swift-tools-version:6.3 +// Note: swift-tools-version is kept at 6.3 for compatibility; the embedded Swift +// build uses WasmParserCore and WasmKit directly with -enable-experimental-feature Embedded. import PackageDescription @@ -33,6 +35,9 @@ let package = Package( .library(name: "WasmKitWASI", targets: ["WasmKitWASI"]), .library(name: "WASI", targets: ["WASI"]), .library(name: "WasmParser", targets: ["WasmParser"]), + // WasmParserCore is the embedded-Swift-compatible subset of WasmParser + // (no file I/O, no SystemPackage dependency). + .library(name: "WasmParserCore", targets: ["WasmParserCore"]), .library(name: "WAT", targets: ["WAT"]), .library(name: "WIT", targets: ["WIT"]), .library(name: "_CabiShims", targets: ["_CabiShims"]), @@ -54,10 +59,14 @@ let package = Package( name: "WasmKit", dependencies: [ "_CWasmKit", - "WasmParser", + "WasmParserCore", "WasmTypes", - "SystemExtras", - .product(name: "SystemPackage", package: "swift-system"), + // WasmParser (file I/O), SystemExtras, and SystemPackage are only available on + // OS-bearing platforms. Bare-metal / embedded targets skip these deps, which + // allows WasmKit to compile with -enable-experimental-feature Embedded. + .target(name: "WasmParser", condition: .when(platforms: [.macOS, .iOS, .watchOS, .tvOS, .visionOS, .linux, .android, .windows, .wasi])), + .target(name: "SystemExtras", condition: .when(platforms: [.macOS, .iOS, .watchOS, .tvOS, .visionOS, .linux, .android, .windows, .wasi])), + .product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.macOS, .iOS, .watchOS, .tvOS, .visionOS, .linux, .android, .windows, .wasi])), .target( name: "ComponentModel", condition: .when(traits: ["ComponentModel"]) @@ -109,15 +118,21 @@ let package = Package( ), .target( - name: "WasmParser", + name: "WasmParserCore", dependencies: [ "SystemExtras", "WasmTypes", - .product(name: "SystemPackage", package: "swift-system"), .target( name: "ComponentModel", condition: .when(traits: ["ComponentModel"]) ), + ] + ), + .target( + name: "WasmParser", + dependencies: [ + "WasmParserCore", + .product(name: "SystemPackage", package: "swift-system"), ], exclude: ["CMakeLists.txt"], swiftSettings: swiftSettings @@ -126,6 +141,7 @@ let package = Package( name: "WasmParserTests", dependencies: [ "WasmParser", + "WasmParserCore", .target( name: "ComponentModel", condition: .when(traits: ["ComponentModel"]) diff --git a/Sources/WasmKit/Engine.swift b/Sources/WasmKit/Engine.swift index 858e4293..e0439393 100644 --- a/Sources/WasmKit/Engine.swift +++ b/Sources/WasmKit/Engine.swift @@ -1,6 +1,6 @@ import _CWasmKit.Platform -import struct WasmParser.WasmFeatureSet +import WasmParserCore /// A WebAssembly execution engine. /// @@ -12,7 +12,9 @@ public final class Engine { /// The engine configuration. public let configuration: EngineConfiguration + #if !$Embedded let interceptor: EngineInterceptor? + #endif let funcTypeInterner: Interner /// Create a new execution engine. @@ -20,6 +22,7 @@ public final class Engine { /// - Parameters: /// - configuration: The engine configuration. /// - interceptor: An optional runtime interceptor to intercept execution of instructions. + #if !$Embedded public init( configuration: EngineConfiguration = EngineConfiguration(), interceptor: EngineInterceptor? = nil @@ -40,6 +43,21 @@ public final class Engine { self.interceptor = interceptor self.funcTypeInterner = Interner() } + #else + public init(configuration: EngineConfiguration = EngineConfiguration()) { + var configuration = configuration + + if WASMKIT_MPROTECT_BOUND_CHECKING == 0 + || Engine.isAddressSanitizerEnabled + || (configuration.memoryBoundsChecking == .mprotect && configuration.threadingModel == .token) + { + configuration.memoryBoundsChecking = .software + } + + self.configuration = configuration + self.funcTypeInterner = Interner() + } + #endif /// Migration aid for the old ``Runtime/instantiate(module:)`` @available(*, unavailable, message: "Use ``Module/instantiate(store:imports:)`` instead") diff --git a/Sources/WasmKit/Execution/AtomicParkingLot.swift b/Sources/WasmKit/Execution/AtomicParkingLot.swift index 49c70058..d9daf3b6 100644 --- a/Sources/WasmKit/Execution/AtomicParkingLot.swift +++ b/Sources/WasmKit/Execution/AtomicParkingLot.swift @@ -1,3 +1,6 @@ +// Embedded Swift does not support the Synchronization framework; this entire file +// is excluded from embedded builds. +#if !$Embedded /// Synchronization primitives for atomic memory wait and notify operations. /// /// Provides thread-safe waiting and notification mechanisms for shared memory @@ -174,3 +177,4 @@ enum WaitOutcome { case mismatch // 1 - value didn't match expected case timedOut // 2 - deadline expired } +#endif // !$Embedded diff --git a/Sources/WasmKit/Execution/ConstEvaluation.swift b/Sources/WasmKit/Execution/ConstEvaluation.swift index d8df0a68..13b1d2e0 100644 --- a/Sources/WasmKit/Execution/ConstEvaluation.swift +++ b/Sources/WasmKit/Execution/ConstEvaluation.swift @@ -1,8 +1,8 @@ -import WasmParser +import WasmParserCore protocol ConstEvaluationContextProtocol { - func functionRef(_ index: FunctionIndex) throws -> Reference - func globalValue(_ index: GlobalIndex) throws -> Value + func functionRef(_ index: FunctionIndex) throws(WasmKitError) -> Reference + func globalValue(_ index: GlobalIndex) throws(WasmKitError) -> Value } struct ConstEvaluationContext: ConstEvaluationContextProtocol { @@ -28,12 +28,12 @@ struct ConstEvaluationContext: ConstEvaluationContextProtocol { self.init(functions: instance.functions, globals: Array(externalGlobals)) } - func functionRef(_ index: FunctionIndex) throws -> Reference { + func functionRef(_ index: FunctionIndex) throws(WasmKitError) -> Reference { let function = try self.functions[validating: Int(index)] self.onFunctionReferenced?(function) return .function(from: function) } - func globalValue(_ index: GlobalIndex) throws -> Value { + func globalValue(_ index: GlobalIndex) throws(WasmKitError) -> Value { guard index < globals.count else { throw GlobalEntity.createOutOfBoundsError(index: Int(index), count: globals.count) } @@ -42,13 +42,13 @@ struct ConstEvaluationContext: ConstEvaluationContextProtocol { } extension ConstExpression { - func evaluate(context: C, expectedType: WasmTypes.ValueType) throws -> Value { + func evaluate(context: C, expectedType: WasmTypes.ValueType) throws(WasmKitError) -> Value { let result = try self._evaluate(context: context) try result.checkType(expectedType) return result } - private func _evaluate(context: C) throws -> Value { + private func _evaluate(context: C) throws(WasmKitError) -> Value { guard self.last == .end, self.count == 2 else { throw WasmKitError(message: .expectedEndAtOffsetExpression) } @@ -77,17 +77,19 @@ extension ConstExpression { } } -extension WasmParser.ElementSegment { - func evaluateInits(context: C) throws -> [Reference] { - return try self.initializer.map { expression -> Reference in +extension WasmParserCore.ElementSegment { + func evaluateInits(context: C) throws(WasmKitError) -> [Reference] { + var results: [Reference] = [] + for expression in self.initializer { let result = try Self._evaluateInits(context: context, expression: expression) try result.checkType(self.type) - return result + results.append(result) } + return results } static func _evaluateInits( context: C, expression: ConstExpression - ) throws -> Reference { + ) throws(WasmKitError) -> Reference { switch expression[0] { case .refFunc(let index): return try context.functionRef(index) diff --git a/Sources/WasmKit/Execution/Debugger.swift b/Sources/WasmKit/Execution/Debugger.swift index 211317f0..faea2b5a 100644 --- a/Sources/WasmKit/Execution/Debugger.swift +++ b/Sources/WasmKit/Execution/Debugger.swift @@ -1,8 +1,10 @@ #if WasmDebuggingSupport +import WasmParserCore /// Debugger state owner, driven by a debugger host. This implementation has no knowledge of the exact /// debugger protocol, which allows any protocol implementation or direct API users to be layered on top if needed. - package struct Debugger: ~Copyable { +#if !$Embedded + package struct Debugger: ~Copyable { package struct BreakpointState { let iseq: Execution.Breakpoint package let wasmPc: Int @@ -25,8 +27,21 @@ case notStoppedAtBreakpoint case linearMemoryNotInitialized case linearMemoryOOB(Range) + #if $Embedded + case wasmKitError(WasmKitError) + case trap(Trap) + #endif } + #if $Embedded + private static func wrap(_ body: () throws(WasmKitError) -> T) throws(Debugger.Error) -> T { + do throws(WasmKitError) { return try body() } catch let e { throw .wasmKitError(e) } + } + private static func wrapTrap(_ body: () throws(Trap) -> T) throws(Debugger.Error) -> T { + do throws(Trap) { return try body() } catch let e { throw .trap(e) } + } + #endif + private let valueStack: Sp private var execution: Execution private let store: Store @@ -230,6 +245,7 @@ ) } case .instantiated: + #if !$Embedded let result = try self.execution.executeWasm( threadingModel: self.threadingModel, function: self.entrypointFunction.handle, @@ -238,6 +254,22 @@ sp: self.valueStack, pc: &self.endOfExecution ) + #else + var rootSlot: CodeSlot = Instruction.endOfExecution.headSlot(threadingModel: self.threadingModel) + var thrownTrap: Trap? = nil + withUnsafeMutablePointer(to: &rootSlot) { rootPtr in + do throws(Trap) { + try self.execution.executeEmbedded( + rootSp: self.valueStack, + rootISQ: rootPtr, + handle: self.entrypointFunction.handle, + type: self.entrypointFunction.type + ) + } catch let trap { thrownTrap = trap } + } + if let trap = thrownTrap { throw trap } + let result: [Value] = [] // embedded doesn't return values via debugger path + #endif self.state = .entrypointReturned(result) case .trapped, .entrypointReturned: @@ -389,6 +421,425 @@ self.valueStack.deallocate() } } +#else // $Embedded + package struct Debugger: ~Copyable { + package struct BreakpointState { + let iseq: Execution.Breakpoint + package let wasmPc: Int + } + + package enum State { + case instantiated + case stoppedAtBreakpoint(BreakpointState) + case trapped(String) + case entrypointReturned([Value]) + } + + package enum Error: Swift.Error, @unchecked Sendable { + case entrypointFunctionNotFound + case unknownCurrentFunctionForResumedBreakpoint(UnsafeMutablePointer) + case noInstructionMappingAvailable(Int) + case noReverseInstructionMappingAvailable(UnsafeMutablePointer) + case stackFrameIndexOOB(UInt) + case stackLocalIndexOOB(UInt) + case notStoppedAtBreakpoint + case linearMemoryNotInitialized + case linearMemoryOOB(Range) + #if $Embedded + case wasmKitError(WasmKitError) + case trap(Trap) + #endif + } + + #if $Embedded + private static func wrap(_ body: () throws(WasmKitError) -> T) throws(Debugger.Error) -> T { + do throws(WasmKitError) { return try body() } catch let e { throw .wasmKitError(e) } + } + private static func wrapTrap(_ body: () throws(Trap) -> T) throws(Debugger.Error) -> T { + do throws(Trap) { return try body() } catch let e { throw .trap(e) } + } + #endif + + private let valueStack: Sp + private var execution: Execution + private let store: Store + + /// Parsed in-memory representation of a Wasm module instantiated for debugging. + private let module: Module + + /// Instance of parsed Wasm ``module``. + private let instance: Instance + + /// Reference to the entrypoint function of the currently debugged module, for use in ``stopAtEntrypoint``. + /// Currently assumed to be the WASI command `_start` entrypoint. + private let entrypointFunction: Function + + /// Threading model of the Wasm engine configuration, cached for a potentially hot path. + private let threadingModel: EngineConfiguration.ThreadingModel + + /// Mapping from a Wasm address of a breakpoint to a corresponding iseq code slot. + package private(set) var breakpoints = [Int: UInt64]() + + package private(set) var state: State + + /// Pc of the final instruction that a successful program will execute, initialized with `Instruction.endofExecution` + private var endOfExecution: CodeSlot + + private var md: Md = nil + private var ms: Ms = 0 + + /// Addresses of functions in the original Wasm binary, used for looking up functions when a breakpoint + /// is enabled at an arbitrary address if it isn't present in ``InstructionMapping`` yet (i.e. the + /// was not compiled yet in lazy compilation mode). + private let functionAddresses: [(address: Int, instanceFunctionIndex: Int)] + + /// Reverse map from a head code slot to its opcode ID, used for resolving + /// which control-flow instruction is at a breakpoint site. + /// For token threading the head slot is the opcode ID itself; for direct + /// threading it is a function pointer that we map back. + private let headSlotToOpcodeID: [CodeSlot: OpcodeID] + + /// Initializes a new debugger state instance. + /// - Parameters: + /// - module: Wasm module to instantiate. + /// - store: Store that instantiates the module. + /// - imports: Imports required by `module` for instantiation. + package init(module: Module, store: Store, imports: Imports) throws(Debugger.Error) { + let limit = store.engine.configuration.stackSize / MemoryLayout.stride + let instance = try Debugger.wrap { () throws(WasmKitError) -> Instance in try module.instantiate(store: store, imports: imports, isDebuggable: true) } + + guard case .function(let entrypointFunction) = instance.exports["_start"] else { + throw Error.entrypointFunctionNotFound + } + + self.instance = instance + self.functionAddresses = instance.handle.functions.enumerated().filter { $0.element.isWasm }.lazy.map { + switch $0.element.wasm.code { + case .uncompiled(let wasm), .debuggable(let wasm, _): + return (address: wasm.originalAddress, instanceFunctionIndex: $0.offset) + case .compiled: + fatalError() + } + } + self.module = module + self.entrypointFunction = entrypointFunction + self.valueStack = UnsafeMutablePointer.allocate(capacity: limit) + self.store = store + self.execution = Execution( + store: StoreRef(store), + stackEnd: valueStack.advanced(by: limit) + ) + self.threadingModel = store.engine.configuration.threadingModel + self.endOfExecution = Instruction.endOfExecution.headSlot(threadingModel: threadingModel) + + self.headSlotToOpcodeID = Instruction.buildControlHeadSlotMap( + threadingModel: self.threadingModel + ) + + self.state = .instantiated + } + + /// Sets a breakpoint at the first instruction in the entrypoint function of the module instantiated by + /// this debugger. + package mutating func stopAtEntrypoint() throws(Debugger.Error) { + try self.enableBreakpoint(address: self.originalAddress(function: entrypointFunction)) + } + + /// Finds a Wasm address for the first instruction in a given function. + /// - Parameter function: the Wasm function to find the first Wasm instruction address for. + /// - Returns: byte offset of the first Wasm instruction of given function in the module it was parsed from. + package func originalAddress(function: Function) throws(Debugger.Error) -> Int { + precondition(function.handle.isWasm) + + switch function.handle.wasm.code { + case .debuggable(let wasm, _): + return wasm.originalAddress + case .uncompiled: + try Debugger.wrapTrap { () throws(Trap) in try function.handle.wasm.ensureCompiled(store: StoreRef(self.store)) } + return try self.originalAddress(function: function) + case .compiled: + fatalError() + } + } + + private func findIseq(forWasmAddress address: Int) throws(Debugger.Error) -> (iseq: Pc, wasm: Int) { + if let (iseq, wasm) = self.instance.handle.instructionMapping.findIseq(forWasmAddress: address) { + return (iseq, wasm) + } + + let followingIndex = self.functionAddresses.firstIndex(where: { $0.address > address }) ?? self.functionAddresses.endIndex + let functionIndex = self.functionAddresses[followingIndex - 1].instanceFunctionIndex + let function = instance.handle.functions[functionIndex] + try Debugger.wrapTrap { () throws(Trap) in try function.wasm.ensureCompiled(store: StoreRef(self.store)) } + + if let (iseq, wasm) = self.instance.handle.instructionMapping.findIseq(forWasmAddress: address) { + return (iseq, wasm) + } + + throw Error.noInstructionMappingAvailable(address) + } + + /// Enables a breakpoint at a given Wasm address. + /// - Parameter address: byte offset of the Wasm instruction that will be replaced with a breakpoint. If no + /// direct internal bytecode matching instruction is found, the next closest internal bytecode instruction + /// is replaced with a breakpoint. The original instruction to be restored is preserved in debugger state + /// represented by `self`. + /// See also ``Debugger/disableBreakpoint(address:)``. + @discardableResult + package mutating func enableBreakpoint(address: Int) throws(Debugger.Error) -> Int { + guard self.breakpoints[address] == nil else { + return address + } + + let (iseq, wasm) = try self.findIseq(forWasmAddress: address) + self.breakpoints[wasm] = iseq.pointee + iseq.pointee = Instruction.breakpoint.headSlot(threadingModel: self.threadingModel) + return wasm + } + + package mutating func enableBreakpoint( + module: Module, + function: Int, + offsetWithinFunction: Int = 0 + ) throws(Debugger.Error) -> Int { + try self.enableBreakpoint(address: module.functions[function].code.originalAddress + offsetWithinFunction) + } + + /// Disables a breakpoint at a given Wasm address. If no breakpoint at a given address was previously set with + /// `self.enableBreakpoint(address:), this function immediately returns. + /// - Parameter address: byte offset of the Wasm instruction that was replaced with a breakpoint. The original + /// instruction is restored from debugger state and replaces the breakpoint instruction. + /// See also ``Debugger/enableBreakpoint(address:)``. + package mutating func disableBreakpoint(address: Int) throws(Debugger.Error) { + guard let oldCodeSlot = self.breakpoints[address] else { + return + } + + let (iseq, wasm) = try self.findIseq(forWasmAddress: address) + + self.breakpoints[wasm] = nil + iseq.pointee = oldCodeSlot + } + + /// Resumes the module instantiated by the debugger stopped at a breakpoint. The breakpoint is disabled + /// and execution is resumed until the next breakpoint is triggered or all remaining instructions are + /// executed. If the module is not stopped at a breakpoint, this function returns immediately. + package mutating func run() throws(Debugger.Error) { + do { + switch self.state { + case .stoppedAtBreakpoint(let breakpoint): + // Remove the breakpoint before resuming + try self.disableBreakpoint(address: breakpoint.wasmPc) + self.execution.resetError() + + let iseq = breakpoint.iseq + var sp = iseq.sp + var pc = iseq.pc + + guard let currentFunction = sp.currentFunction else { + throw Error.unknownCurrentFunctionForResumedBreakpoint(sp) + } + + Execution.CurrentMemory.mayUpdateCurrentInstance( + instance: currentFunction.instance, + md: &md, + ms: &ms + ) + + do { + switch self.threadingModel { + case .direct: + try self.execution.runDirectThreaded(sp: sp, pc: pc, md: md, ms: ms) + case .token: + try self.execution.runTokenThreaded(sp: &sp, pc: &pc, md: &md, ms: &ms) + } + } catch let end as Execution.EndOfExecution { + // The module successfully executed till the "end of execution" instruction. + let type = self.entrypointFunction.type + self.state = .entrypointReturned( + type.results.enumerated().map { (i, type) in + end.sp[VReg(i)].cast(to: type) + } + ) + } + case .instantiated: + #if !$Embedded + let result = try self.execution.executeWasm( + threadingModel: self.threadingModel, + function: self.entrypointFunction.handle, + type: self.entrypointFunction.type, + arguments: [], + sp: self.valueStack, + pc: &self.endOfExecution + ) + #else + var rootSlot: CodeSlot = Instruction.endOfExecution.headSlot(threadingModel: self.threadingModel) + var thrownTrap: Trap? = nil + withUnsafeMutablePointer(to: &rootSlot) { rootPtr in + do throws(Trap) { + try self.execution.executeEmbedded( + rootSp: self.valueStack, + rootISQ: rootPtr, + handle: self.entrypointFunction.handle, + type: self.entrypointFunction.type + ) + } catch let trap { thrownTrap = trap } + } + if let trap = thrownTrap { throw trap } + let result: [Value] = [] // embedded doesn't return values via debugger path + #endif + self.state = .entrypointReturned(result) + + case .trapped, .entrypointReturned: + fatalError("Restarting a Wasm module from the debugger is not implemented yet.") + } + } catch let breakpoint as Execution.Breakpoint { + let pc = breakpoint.pc + guard let wasmPc = self.instance.handle.instructionMapping.findWasm(forIseqAddress: pc) else { + throw Error.noReverseInstructionMappingAvailable(pc) + } + + self.state = .stoppedAtBreakpoint(.init(iseq: breakpoint, wasmPc: wasmPc)) + } + } + + /// Steps by a single Wasm instruction in the module instantiated by the debugger stopped at a breakpoint. + /// The current breakpoint is disabled and new breakpoints are put on the next instruction (or instructions in case + /// of multiple possible execution branches). After breakpoints setup, execution is resumed until suspension. + /// If the module is not stopped at a breakpoint, this function returns immediately. + package mutating func step() throws(Debugger.Error) { + guard case .stoppedAtBreakpoint(let breakpoint) = self.state else { + return + } + + try self.setNextInstructionBreakpoints(breakpoint: breakpoint) + try self.run() + } + + /// Resumes the module instantiated by the debugger stopped at a breakpoint. The breakpoint from which + /// the debugger resumes is preserved. If the module is current not stopped at a breakpoint, this function + /// returns immediately. + package mutating func runPreservingCurrentBreakpoint() throws(Debugger.Error) { + guard case .stoppedAtBreakpoint(let breakpoint) = self.state else { + return + } + + try self.setNextInstructionBreakpoints(breakpoint: breakpoint) + try self.run() + try self.enableBreakpoint(address: breakpoint.wasmPc) + try self.run() + } + + package func getLocal(frameIndex: UInt, localIndex: UInt) throws(Debugger.Error) -> UInt64 { + guard case .stoppedAtBreakpoint(let breakpoint) = self.state else { + throw Error.notStoppedAtBreakpoint + } + + var i = 0 + for frame in Execution.CallStack(sp: breakpoint.iseq.sp) { + guard frameIndex == i else { + i += 1 + continue + } + + guard let currentFunction = frame.sp.currentFunction else { + throw Debugger.Error.unknownCurrentFunctionForResumedBreakpoint(frame.sp) + } + + try currentFunction.ensureCompiled(store: StoreRef(store)) + + guard case .debuggable(let wasm, _) = currentFunction.code else { + fatalError() + } + + // Wasm function arguments are also addressed as locals. + let functionType = store.engine.funcTypeInterner.resolve(currentFunction.type) + + let localsCount = functionType.parameters.count + wasm.locals.count + + guard localIndex < localsCount else { + throw Debugger.Error.stackLocalIndexOOB(localIndex) + } + + if localIndex < functionType.parameters.count { + let localIndex = Int(localIndex) - 4 + return frame.sp[localIndex].storage + } else { + let localIndex = Int(localIndex) - functionType.parameters.count + return frame.sp[localIndex].storage + } + } + + throw Error.stackFrameIndexOOB(frameIndex) + } + + package func readLinearMemory(address: UInt, length: UInt, reader: (UnsafeRawBufferPointer) -> T) throws(Error) -> T { + guard let md, ms > 0 else { + throw Error.linearMemoryNotInitialized + } + + let upperBound = address + length + let range = Int(address).. [Pc] { diff --git a/Sources/WasmKit/Execution/DispatchInstruction.swift b/Sources/WasmKit/Execution/DispatchInstruction.swift index af2168fa..f9091e7e 100644 --- a/Sources/WasmKit/Execution/DispatchInstruction.swift +++ b/Sources/WasmKit/Execution/DispatchInstruction.swift @@ -30,7 +30,11 @@ extension Execution { case 14: return self.execute_brIfNot(sp: &sp, pc: &pc, md: &md, ms: &ms) case 15: return self.execute_brTable(sp: &sp, pc: &pc, md: &md, ms: &ms) case 16: return self.execute__return(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded case 17: return try self.execute_endOfExecution(sp: &sp, pc: &pc, md: &md, ms: &ms) + #else + case 17: return try self.execute_endOfExecutionEmbedded(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif case 18: return try self.execute_i32Load(sp: &sp, pc: &pc, md: &md, ms: &ms) case 19: return try self.execute_i64Load(sp: &sp, pc: &pc, md: &md, ms: &ms) case 20: return try self.execute_f32Load(sp: &sp, pc: &pc, md: &md, ms: &ms) @@ -215,7 +219,9 @@ extension Execution { case 199: return self.execute_tableElementDrop(sp: &sp, pc: &pc, md: &md, ms: &ms) case 200: return self.execute_onEnter(sp: &sp, pc: &pc, md: &md, ms: &ms) case 201: return self.execute_onExit(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded case 202: return try self.execute_breakpoint(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif case 203: return try self.execute_i32AtomicLoad(sp: &sp, pc: &pc, md: &md, ms: &ms) case 204: return try self.execute_i64AtomicLoad(sp: &sp, pc: &pc, md: &md, ms: &ms) case 205: return try self.execute_i32AtomicLoad8U(sp: &sp, pc: &pc, md: &md, ms: &ms) @@ -279,19 +285,321 @@ extension Execution { case 263: return try self.execute_i64AtomicRmw8CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) case 264: return try self.execute_i64AtomicRmw16CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) case 265: return try self.execute_i64AtomicRmw32CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded case 266: return try self.execute_memoryAtomicWait32(sp: &sp, pc: &pc, md: &md, ms: &ms) case 267: return try self.execute_memoryAtomicWait64(sp: &sp, pc: &pc, md: &md, ms: &ms) case 268: return try self.execute_memoryAtomicNotify(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif // !$Embedded case 269: return self.execute_atomicFence(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded case 270: return try self.execute_throwTag(sp: &sp, pc: &pc, md: &md, ms: &ms) case 271: return try self.execute_throwRef(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif + #if !$Embedded case 272: return self.execute_catchHandlers(sp: &sp, pc: &pc, md: &md, ms: &ms) case 273: return self.execute_catchHandlersEnd(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif default: preconditionFailure("Unknown instruction!?") } - } -} + } // closes doExecute + + #if $Embedded + @inline(__always) + mutating func doExecuteEmbedded(_ opcode: OpcodeID, sp: inout Sp, pc: inout Pc, md: inout Md, ms: inout Ms) throws(Trap) -> CodeSlot { + switch opcode { + case 0: return self.execute_copyStack(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 1: return self.execute_globalGet(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 2: return self.execute_globalSet(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 3: return try self.execute_call(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 4: return try self.execute_compilingCall(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 5: return try self.execute_internalCall(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 6: return try self.execute_callIndirect(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 7: return try self.execute_resizeFrameHeader(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 8: return try self.execute_returnCall(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 9: return try self.execute_returnCallIndirect(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 10: return try self.execute_unreachable(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 11: return self.execute_nop(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 12: return self.execute_br(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 13: return self.execute_brIf(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 14: return self.execute_brIfNot(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 15: return self.execute_brTable(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 16: return self.execute__return(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded + case 17: return try self.execute_endOfExecution(sp: &sp, pc: &pc, md: &md, ms: &ms) + #else + case 17: return try self.execute_endOfExecutionEmbedded(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif + case 18: return try self.execute_i32Load(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 19: return try self.execute_i64Load(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 20: return try self.execute_f32Load(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 21: return try self.execute_f64Load(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 22: return try self.execute_i32Load8S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 23: return try self.execute_i32Load8U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 24: return try self.execute_i32Load16S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 25: return try self.execute_i32Load16U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 26: return try self.execute_i64Load8S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 27: return try self.execute_i64Load8U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 28: return try self.execute_i64Load16S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 29: return try self.execute_i64Load16U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 30: return try self.execute_i64Load32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 31: return try self.execute_i64Load32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 32: return try self.execute_i32Store(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 33: return try self.execute_i64Store(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 34: return try self.execute_f32Store(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 35: return try self.execute_f64Store(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 36: return try self.execute_i32Store8(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 37: return try self.execute_i32Store16(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 38: return try self.execute_i64Store8(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 39: return try self.execute_i64Store16(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 40: return try self.execute_i64Store32(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 41: return self.execute_memorySize(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 42: return try self.execute_memoryGrow(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 43: return try self.execute_memoryInit(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 44: return self.execute_memoryDataDrop(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 45: return try self.execute_memoryCopy(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 46: return try self.execute_memoryFill(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 47: return self.execute_v128Const(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 48: return self.execute_i8x16Shuffle(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 49: return try self.execute_simd(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 50: return self.execute_const32(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 51: return self.execute_const64(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 52: return self.execute_i32Add(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 53: return self.execute_i64Add(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 54: return self.execute_i32Sub(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 55: return self.execute_i64Sub(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 56: return self.execute_i32Mul(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 57: return self.execute_i64Mul(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 58: return self.execute_i32And(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 59: return self.execute_i64And(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 60: return self.execute_i32Or(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 61: return self.execute_i64Or(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 62: return self.execute_i32Xor(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 63: return self.execute_i64Xor(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 64: return self.execute_i32Shl(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 65: return self.execute_i64Shl(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 66: return self.execute_i32ShrS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 67: return self.execute_i64ShrS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 68: return self.execute_i32ShrU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 69: return self.execute_i64ShrU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 70: return self.execute_i32Rotl(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 71: return self.execute_i64Rotl(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 72: return self.execute_i32Rotr(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 73: return self.execute_i64Rotr(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 74: return try self.execute_i32DivS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 75: return try self.execute_i64DivS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 76: return try self.execute_i32DivU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 77: return try self.execute_i64DivU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 78: return try self.execute_i32RemS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 79: return try self.execute_i64RemS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 80: return try self.execute_i32RemU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 81: return try self.execute_i64RemU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 82: return self.execute_i32Eq(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 83: return self.execute_i64Eq(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 84: return self.execute_i32Ne(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 85: return self.execute_i64Ne(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 86: return self.execute_i32LtS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 87: return self.execute_i64LtS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 88: return self.execute_i32LtU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 89: return self.execute_i64LtU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 90: return self.execute_i32GtS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 91: return self.execute_i64GtS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 92: return self.execute_i32GtU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 93: return self.execute_i64GtU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 94: return self.execute_i32LeS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 95: return self.execute_i64LeS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 96: return self.execute_i32LeU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 97: return self.execute_i64LeU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 98: return self.execute_i32GeS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 99: return self.execute_i64GeS(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 100: return self.execute_i32GeU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 101: return self.execute_i64GeU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 102: return self.execute_i32Clz(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 103: return self.execute_i64Clz(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 104: return self.execute_i32Ctz(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 105: return self.execute_i64Ctz(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 106: return self.execute_i32Popcnt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 107: return self.execute_i64Popcnt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 108: return self.execute_i32Eqz(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 109: return self.execute_i64Eqz(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 110: return self.execute_i32WrapI64(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 111: return self.execute_i64ExtendI32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 112: return self.execute_i64ExtendI32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 113: return self.execute_i32Extend8S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 114: return self.execute_i64Extend8S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 115: return self.execute_i32Extend16S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 116: return self.execute_i64Extend16S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 117: return self.execute_i64Extend32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 118: return try self.execute_i32TruncF32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 119: return try self.execute_i32TruncF32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 120: return try self.execute_i32TruncSatF32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 121: return try self.execute_i32TruncSatF32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 122: return try self.execute_i32TruncF64S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 123: return try self.execute_i32TruncF64U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 124: return try self.execute_i32TruncSatF64S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 125: return try self.execute_i32TruncSatF64U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 126: return try self.execute_i64TruncF32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 127: return try self.execute_i64TruncF32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 128: return try self.execute_i64TruncSatF32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 129: return try self.execute_i64TruncSatF32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 130: return try self.execute_i64TruncF64S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 131: return try self.execute_i64TruncF64U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 132: return try self.execute_i64TruncSatF64S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 133: return try self.execute_i64TruncSatF64U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 134: return self.execute_f32ConvertI32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 135: return self.execute_f32ConvertI32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 136: return self.execute_f32ConvertI64S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 137: return self.execute_f32ConvertI64U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 138: return self.execute_f64ConvertI32S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 139: return self.execute_f64ConvertI32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 140: return self.execute_f64ConvertI64S(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 141: return self.execute_f64ConvertI64U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 142: return self.execute_f32ReinterpretI32(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 143: return self.execute_f64ReinterpretI64(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 144: return self.execute_i32ReinterpretF32(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 145: return self.execute_i64ReinterpretF64(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 146: return self.execute_f32Add(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 147: return self.execute_f64Add(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 148: return self.execute_f32Sub(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 149: return self.execute_f64Sub(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 150: return self.execute_f32Mul(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 151: return self.execute_f64Mul(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 152: return self.execute_f32Div(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 153: return self.execute_f64Div(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 154: return self.execute_f32Min(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 155: return self.execute_f64Min(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 156: return self.execute_f32Max(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 157: return self.execute_f64Max(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 158: return self.execute_f32CopySign(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 159: return self.execute_f64CopySign(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 160: return self.execute_f32Eq(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 161: return self.execute_f64Eq(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 162: return self.execute_f32Ne(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 163: return self.execute_f64Ne(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 164: return self.execute_f32Lt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 165: return self.execute_f64Lt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 166: return self.execute_f32Gt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 167: return self.execute_f64Gt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 168: return self.execute_f32Le(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 169: return self.execute_f64Le(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 170: return self.execute_f32Ge(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 171: return self.execute_f64Ge(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 172: return self.execute_f32Abs(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 173: return self.execute_f64Abs(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 174: return self.execute_f32Neg(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 175: return self.execute_f64Neg(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 176: return self.execute_f32Ceil(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 177: return self.execute_f64Ceil(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 178: return self.execute_f32Floor(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 179: return self.execute_f64Floor(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 180: return self.execute_f32Trunc(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 181: return self.execute_f64Trunc(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 182: return self.execute_f32Nearest(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 183: return self.execute_f64Nearest(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 184: return self.execute_f32Sqrt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 185: return self.execute_f64Sqrt(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 186: return self.execute_f64PromoteF32(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 187: return self.execute_f32DemoteF64(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 188: return self.execute_select(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 189: return self.execute_refNull(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 190: return self.execute_refIsNull(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 191: return self.execute_refFunc(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 192: return try self.execute_tableGet(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 193: return try self.execute_tableSet(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 194: return self.execute_tableSize(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 195: return try self.execute_tableGrow(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 196: return try self.execute_tableFill(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 197: return try self.execute_tableCopy(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 198: return try self.execute_tableInit(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 199: return self.execute_tableElementDrop(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 200: return self.execute_onEnter(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 201: return self.execute_onExit(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded + case 202: return try self.execute_breakpoint(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif + case 203: return try self.execute_i32AtomicLoad(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 204: return try self.execute_i64AtomicLoad(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 205: return try self.execute_i32AtomicLoad8U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 206: return try self.execute_i32AtomicLoad16U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 207: return try self.execute_i64AtomicLoad8U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 208: return try self.execute_i64AtomicLoad16U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 209: return try self.execute_i64AtomicLoad32U(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 210: return try self.execute_i32AtomicStore(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 211: return try self.execute_i64AtomicStore(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 212: return try self.execute_i32AtomicStore8(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 213: return try self.execute_i32AtomicStore16(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 214: return try self.execute_i64AtomicStore8(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 215: return try self.execute_i64AtomicStore16(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 216: return try self.execute_i64AtomicStore32(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 217: return try self.execute_i32AtomicRmwAdd(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 218: return try self.execute_i64AtomicRmwAdd(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 219: return try self.execute_i32AtomicRmwSub(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 220: return try self.execute_i64AtomicRmwSub(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 221: return try self.execute_i32AtomicRmwAnd(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 222: return try self.execute_i64AtomicRmwAnd(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 223: return try self.execute_i32AtomicRmwOr(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 224: return try self.execute_i64AtomicRmwOr(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 225: return try self.execute_i32AtomicRmwXor(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 226: return try self.execute_i64AtomicRmwXor(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 227: return try self.execute_i32AtomicRmwXchg(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 228: return try self.execute_i64AtomicRmwXchg(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 229: return try self.execute_i32AtomicRmw8AddU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 230: return try self.execute_i64AtomicRmw8AddU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 231: return try self.execute_i32AtomicRmw8SubU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 232: return try self.execute_i64AtomicRmw8SubU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 233: return try self.execute_i32AtomicRmw8AndU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 234: return try self.execute_i64AtomicRmw8AndU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 235: return try self.execute_i32AtomicRmw8OrU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 236: return try self.execute_i64AtomicRmw8OrU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 237: return try self.execute_i32AtomicRmw8XorU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 238: return try self.execute_i64AtomicRmw8XorU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 239: return try self.execute_i32AtomicRmw8XchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 240: return try self.execute_i64AtomicRmw8XchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 241: return try self.execute_i32AtomicRmw16AddU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 242: return try self.execute_i64AtomicRmw16AddU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 243: return try self.execute_i32AtomicRmw16SubU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 244: return try self.execute_i64AtomicRmw16SubU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 245: return try self.execute_i32AtomicRmw16AndU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 246: return try self.execute_i64AtomicRmw16AndU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 247: return try self.execute_i32AtomicRmw16OrU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 248: return try self.execute_i64AtomicRmw16OrU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 249: return try self.execute_i32AtomicRmw16XorU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 250: return try self.execute_i64AtomicRmw16XorU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 251: return try self.execute_i32AtomicRmw16XchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 252: return try self.execute_i64AtomicRmw16XchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 253: return try self.execute_i64AtomicRmw32AddU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 254: return try self.execute_i64AtomicRmw32SubU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 255: return try self.execute_i64AtomicRmw32AndU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 256: return try self.execute_i64AtomicRmw32OrU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 257: return try self.execute_i64AtomicRmw32XorU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 258: return try self.execute_i64AtomicRmw32XchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 259: return try self.execute_i32AtomicRmwCmpxchg(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 260: return try self.execute_i64AtomicRmwCmpxchg(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 261: return try self.execute_i32AtomicRmw8CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 262: return try self.execute_i32AtomicRmw16CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 263: return try self.execute_i64AtomicRmw8CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 264: return try self.execute_i64AtomicRmw16CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 265: return try self.execute_i64AtomicRmw32CmpxchgU(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded + case 266: return try self.execute_memoryAtomicWait32(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 267: return try self.execute_memoryAtomicWait64(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 268: return try self.execute_memoryAtomicNotify(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif // !$Embedded + case 269: return self.execute_atomicFence(sp: &sp, pc: &pc, md: &md, ms: &ms) + #if !$Embedded + case 270: return try self.execute_throwTag(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 271: return try self.execute_throwRef(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif + #if !$Embedded + case 272: return self.execute_catchHandlers(sp: &sp, pc: &pc, md: &md, ms: &ms) + case 273: return self.execute_catchHandlersEnd(sp: &sp, pc: &pc, md: &md, ms: &ms) + #endif + default: preconditionFailure("Unknown instruction!?") + + } + } // closes doExecuteEmbedded + #endif // $Embedded +} // closes extension Execution (token threading) // MARK: - Direct Threaded Code extension Execution { @@ -320,35 +628,35 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_call") @inline(__always) - mutating func execute_call(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_call(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CallOperand.load(from: &pc.pointee) let next: CodeSlot (pc.pointee, next) = try self.call(sp: &sp.pointee, pc: pc.pointee, md: &md.pointee, ms: &ms.pointee, immediate: immediate) return next } @_silgen_name("wasmkit_execute_compilingCall") @inline(__always) - mutating func execute_compilingCall(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_compilingCall(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CallOperand.load(from: &pc.pointee) let next: CodeSlot (pc.pointee, next) = try self.compilingCall(sp: &sp.pointee, pc: pc.pointee, immediate: immediate) return next } @_silgen_name("wasmkit_execute_internalCall") @inline(__always) - mutating func execute_internalCall(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_internalCall(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CallOperand.load(from: &pc.pointee) let next: CodeSlot (pc.pointee, next) = try self.internalCall(sp: &sp.pointee, pc: pc.pointee, immediate: immediate) return next } @_silgen_name("wasmkit_execute_callIndirect") @inline(__always) - mutating func execute_callIndirect(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_callIndirect(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CallIndirectOperand.load(from: &pc.pointee) let next: CodeSlot (pc.pointee, next) = try self.callIndirect(sp: &sp.pointee, pc: pc.pointee, md: &md.pointee, ms: &ms.pointee, immediate: immediate) return next } @_silgen_name("wasmkit_execute_resizeFrameHeader") @inline(__always) - mutating func execute_resizeFrameHeader(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_resizeFrameHeader(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.ResizeFrameHeaderOperand.load(from: &pc.pointee) try self.resizeFrameHeader(sp: &sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -356,21 +664,21 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_returnCall") @inline(__always) - mutating func execute_returnCall(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_returnCall(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.ReturnCallOperand.load(from: &pc.pointee) let next: CodeSlot (pc.pointee, next) = try self.returnCall(sp: &sp.pointee, pc: pc.pointee, md: &md.pointee, ms: &ms.pointee, immediate: immediate) return next } @_silgen_name("wasmkit_execute_returnCallIndirect") @inline(__always) - mutating func execute_returnCallIndirect(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_returnCallIndirect(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.ReturnCallIndirectOperand.load(from: &pc.pointee) let next: CodeSlot (pc.pointee, next) = try self.returnCallIndirect(sp: &sp.pointee, pc: pc.pointee, md: &md.pointee, ms: &ms.pointee, immediate: immediate) return next } @_silgen_name("wasmkit_execute_unreachable") @inline(__always) - mutating func execute_unreachable(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_unreachable(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let next: CodeSlot (pc.pointee, next) = try self.unreachable(sp: sp.pointee, pc: pc.pointee) return next @@ -416,14 +724,23 @@ extension Execution { (pc.pointee, next) = self._return(sp: &sp.pointee, pc: pc.pointee, md: &md.pointee, ms: &ms.pointee) return next } + #if !$Embedded @_silgen_name("wasmkit_execute_endOfExecution") @inline(__always) mutating func execute_endOfExecution(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { let next: CodeSlot (pc.pointee, next) = try self.endOfExecution(sp: &sp.pointee, pc: pc.pointee) return next } + #endif // !$Embedded + #if $Embedded + @inline(__always) + mutating func execute_endOfExecutionEmbedded(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { + isFinished = true + return 0 + } + #endif // $Embedded @_silgen_name("wasmkit_execute_i32Load") @inline(__always) - mutating func execute_i32Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt32.self, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -431,7 +748,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Load") @inline(__always) - mutating func execute_i64Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt64.self, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -439,7 +756,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_f32Load") @inline(__always) - mutating func execute_f32Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_f32Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt32.self, castToValue: { .rawF32($0) }) let next = pc.pointee.pointee @@ -447,7 +764,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_f64Load") @inline(__always) - mutating func execute_f64Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_f64Load(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt64.self, castToValue: { .rawF64($0) }) let next = pc.pointee.pointee @@ -455,7 +772,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32Load8S") @inline(__always) - mutating func execute_i32Load8S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Load8S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: Int8.self, castToValue: { .init(signed: Int32($0)) }) let next = pc.pointee.pointee @@ -463,7 +780,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32Load8U") @inline(__always) - mutating func execute_i32Load8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Load8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt8.self, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -471,7 +788,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32Load16S") @inline(__always) - mutating func execute_i32Load16S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Load16S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: Int16.self, castToValue: { .init(signed: Int32($0)) }) let next = pc.pointee.pointee @@ -479,7 +796,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32Load16U") @inline(__always) - mutating func execute_i32Load16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Load16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt16.self, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -487,7 +804,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Load8S") @inline(__always) - mutating func execute_i64Load8S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Load8S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: Int8.self, castToValue: { .init(signed: Int64($0)) }) let next = pc.pointee.pointee @@ -495,7 +812,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Load8U") @inline(__always) - mutating func execute_i64Load8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Load8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt8.self, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -503,7 +820,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Load16S") @inline(__always) - mutating func execute_i64Load16S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Load16S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: Int16.self, castToValue: { .init(signed: Int64($0)) }) let next = pc.pointee.pointee @@ -511,7 +828,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Load16U") @inline(__always) - mutating func execute_i64Load16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Load16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt16.self, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -519,7 +836,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Load32S") @inline(__always) - mutating func execute_i64Load32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Load32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: Int32.self, castToValue: { .init(signed: Int64($0)) }) let next = pc.pointee.pointee @@ -527,7 +844,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Load32U") @inline(__always) - mutating func execute_i64Load32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Load32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try memoryLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt32.self, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -535,7 +852,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32Store") @inline(__always) - mutating func execute_i32Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { $0.i32 }) let next = pc.pointee.pointee @@ -543,7 +860,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Store") @inline(__always) - mutating func execute_i64Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { $0.i64 }) let next = pc.pointee.pointee @@ -551,7 +868,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_f32Store") @inline(__always) - mutating func execute_f32Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_f32Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { $0.rawF32 }) let next = pc.pointee.pointee @@ -559,7 +876,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_f64Store") @inline(__always) - mutating func execute_f64Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_f64Store(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { $0.rawF64 }) let next = pc.pointee.pointee @@ -567,7 +884,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32Store8") @inline(__always) - mutating func execute_i32Store8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Store8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }) let next = pc.pointee.pointee @@ -575,7 +892,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32Store16") @inline(__always) - mutating func execute_i32Store16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32Store16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }) let next = pc.pointee.pointee @@ -583,7 +900,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Store8") @inline(__always) - mutating func execute_i64Store8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Store8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }) let next = pc.pointee.pointee @@ -591,7 +908,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Store16") @inline(__always) - mutating func execute_i64Store16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Store16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }) let next = pc.pointee.pointee @@ -599,7 +916,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64Store32") @inline(__always) - mutating func execute_i64Store32(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64Store32(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try memoryStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }) let next = pc.pointee.pointee @@ -615,7 +932,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_memoryGrow") @inline(__always) - mutating func execute_memoryGrow(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_memoryGrow(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.MemoryGrowOperand.load(from: &pc.pointee) try self.memoryGrow(sp: sp.pointee, md: &md.pointee, ms: &ms.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -623,7 +940,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_memoryInit") @inline(__always) - mutating func execute_memoryInit(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_memoryInit(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.MemoryInitOperand.load(from: &pc.pointee) try self.memoryInit(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -639,7 +956,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_memoryCopy") @inline(__always) - mutating func execute_memoryCopy(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_memoryCopy(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.MemoryCopyOperand.load(from: &pc.pointee) try self.memoryCopy(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -647,7 +964,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_memoryFill") @inline(__always) - mutating func execute_memoryFill(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_memoryFill(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.MemoryFillOperand.load(from: &pc.pointee) try self.memoryFill(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -671,7 +988,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_simd") @inline(__always) - mutating func execute_simd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_simd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.SimdOperand.load(from: &pc.pointee) try self.simd(sp: sp.pointee, md: md.pointee, ms: ms.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -871,7 +1188,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32DivS") @inline(__always) - mutating func execute_i32DivS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32DivS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[i32: immediate.lhs].divS(sp.pointee[i32: immediate.rhs]) let next = pc.pointee.pointee @@ -879,7 +1196,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64DivS") @inline(__always) - mutating func execute_i64DivS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64DivS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[i64: immediate.lhs].divS(sp.pointee[i64: immediate.rhs]) let next = pc.pointee.pointee @@ -887,7 +1204,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32DivU") @inline(__always) - mutating func execute_i32DivU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32DivU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[i32: immediate.lhs].divU(sp.pointee[i32: immediate.rhs]) let next = pc.pointee.pointee @@ -895,7 +1212,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64DivU") @inline(__always) - mutating func execute_i64DivU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64DivU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[i64: immediate.lhs].divU(sp.pointee[i64: immediate.rhs]) let next = pc.pointee.pointee @@ -903,7 +1220,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32RemS") @inline(__always) - mutating func execute_i32RemS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32RemS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[i32: immediate.lhs].remS(sp.pointee[i32: immediate.rhs]) let next = pc.pointee.pointee @@ -911,7 +1228,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64RemS") @inline(__always) - mutating func execute_i64RemS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64RemS(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[i64: immediate.lhs].remS(sp.pointee[i64: immediate.rhs]) let next = pc.pointee.pointee @@ -919,7 +1236,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32RemU") @inline(__always) - mutating func execute_i32RemU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32RemU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[i32: immediate.lhs].remU(sp.pointee[i32: immediate.rhs]) let next = pc.pointee.pointee @@ -927,7 +1244,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64RemU") @inline(__always) - mutating func execute_i64RemU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64RemU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.BinaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[i64: immediate.lhs].remU(sp.pointee[i64: immediate.rhs]) let next = pc.pointee.pointee @@ -1223,7 +1540,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncF32S") @inline(__always) - mutating func execute_i32TruncF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f32: immediate.input].truncToI32S let next = pc.pointee.pointee @@ -1231,7 +1548,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncF32U") @inline(__always) - mutating func execute_i32TruncF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f32: immediate.input].truncToI32U let next = pc.pointee.pointee @@ -1239,7 +1556,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncSatF32S") @inline(__always) - mutating func execute_i32TruncSatF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncSatF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f32: immediate.input].truncSatToI32S let next = pc.pointee.pointee @@ -1247,7 +1564,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncSatF32U") @inline(__always) - mutating func execute_i32TruncSatF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncSatF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f32: immediate.input].truncSatToI32U let next = pc.pointee.pointee @@ -1255,7 +1572,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncF64S") @inline(__always) - mutating func execute_i32TruncF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f64: immediate.input].truncToI32S let next = pc.pointee.pointee @@ -1263,7 +1580,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncF64U") @inline(__always) - mutating func execute_i32TruncF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f64: immediate.input].truncToI32U let next = pc.pointee.pointee @@ -1271,7 +1588,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncSatF64S") @inline(__always) - mutating func execute_i32TruncSatF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncSatF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f64: immediate.input].truncSatToI32S let next = pc.pointee.pointee @@ -1279,7 +1596,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32TruncSatF64U") @inline(__always) - mutating func execute_i32TruncSatF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32TruncSatF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i32: immediate.result] = try sp.pointee[f64: immediate.input].truncSatToI32U let next = pc.pointee.pointee @@ -1287,7 +1604,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncF32S") @inline(__always) - mutating func execute_i64TruncF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f32: immediate.input].truncToI64S let next = pc.pointee.pointee @@ -1295,7 +1612,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncF32U") @inline(__always) - mutating func execute_i64TruncF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f32: immediate.input].truncToI64U let next = pc.pointee.pointee @@ -1303,7 +1620,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncSatF32S") @inline(__always) - mutating func execute_i64TruncSatF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncSatF32S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f32: immediate.input].truncSatToI64S let next = pc.pointee.pointee @@ -1311,7 +1628,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncSatF32U") @inline(__always) - mutating func execute_i64TruncSatF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncSatF32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f32: immediate.input].truncSatToI64U let next = pc.pointee.pointee @@ -1319,7 +1636,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncF64S") @inline(__always) - mutating func execute_i64TruncF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f64: immediate.input].truncToI64S let next = pc.pointee.pointee @@ -1327,7 +1644,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncF64U") @inline(__always) - mutating func execute_i64TruncF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f64: immediate.input].truncToI64U let next = pc.pointee.pointee @@ -1335,7 +1652,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncSatF64S") @inline(__always) - mutating func execute_i64TruncSatF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncSatF64S(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f64: immediate.input].truncSatToI64S let next = pc.pointee.pointee @@ -1343,7 +1660,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64TruncSatF64U") @inline(__always) - mutating func execute_i64TruncSatF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64TruncSatF64U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.UnaryOperand.load(from: &pc.pointee) sp.pointee[i64: immediate.result] = try sp.pointee[f64: immediate.input].truncSatToI64U let next = pc.pointee.pointee @@ -1815,7 +2132,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_tableGet") @inline(__always) - mutating func execute_tableGet(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_tableGet(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.TableGetOperand.load(from: &pc.pointee) try self.tableGet(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -1823,7 +2140,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_tableSet") @inline(__always) - mutating func execute_tableSet(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_tableSet(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.TableSetOperand.load(from: &pc.pointee) try self.tableSet(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -1839,7 +2156,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_tableGrow") @inline(__always) - mutating func execute_tableGrow(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_tableGrow(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.TableGrowOperand.load(from: &pc.pointee) try self.tableGrow(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -1847,7 +2164,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_tableFill") @inline(__always) - mutating func execute_tableFill(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_tableFill(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.TableFillOperand.load(from: &pc.pointee) try self.tableFill(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -1855,7 +2172,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_tableCopy") @inline(__always) - mutating func execute_tableCopy(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_tableCopy(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.TableCopyOperand.load(from: &pc.pointee) try self.tableCopy(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -1863,7 +2180,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_tableInit") @inline(__always) - mutating func execute_tableInit(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_tableInit(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.TableInitOperand.load(from: &pc.pointee) try self.tableInit(sp: sp.pointee, immediate: immediate) let next = pc.pointee.pointee @@ -1894,14 +2211,16 @@ extension Execution { pc.pointee = pc.pointee.advanced(by: 1) return next } + #if !$Embedded @_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 } + #endif // !$Embedded @_silgen_name("wasmkit_execute_i32AtomicLoad") @inline(__always) - mutating func execute_i32AtomicLoad(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicLoad(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try atomicLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt32.self, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -1909,7 +2228,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicLoad") @inline(__always) - mutating func execute_i64AtomicLoad(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicLoad(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try atomicLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt64.self, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -1917,7 +2236,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicLoad8U") @inline(__always) - mutating func execute_i32AtomicLoad8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicLoad8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try atomicLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt8.self, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -1925,7 +2244,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicLoad16U") @inline(__always) - mutating func execute_i32AtomicLoad16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicLoad16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try atomicLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt16.self, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -1933,7 +2252,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicLoad8U") @inline(__always) - mutating func execute_i64AtomicLoad8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicLoad8U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try atomicLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt8.self, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -1941,7 +2260,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicLoad16U") @inline(__always) - mutating func execute_i64AtomicLoad16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicLoad16U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try atomicLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt16.self, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -1949,7 +2268,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicLoad32U") @inline(__always) - mutating func execute_i64AtomicLoad32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicLoad32U(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.LoadOperand.load(from: &pc.pointee) try atomicLoad(sp: sp.pointee, md: md.pointee, ms: ms.pointee, loadOperand: immediate, loadAs: UInt32.self, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -1957,7 +2276,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicStore") @inline(__always) - mutating func execute_i32AtomicStore(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicStore(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try atomicStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { $0.i32 }) let next = pc.pointee.pointee @@ -1965,7 +2284,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicStore") @inline(__always) - mutating func execute_i64AtomicStore(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicStore(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try atomicStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { $0.i64 }) let next = pc.pointee.pointee @@ -1973,7 +2292,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicStore8") @inline(__always) - mutating func execute_i32AtomicStore8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicStore8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try atomicStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }) let next = pc.pointee.pointee @@ -1981,7 +2300,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicStore16") @inline(__always) - mutating func execute_i32AtomicStore16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicStore16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try atomicStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }) let next = pc.pointee.pointee @@ -1989,7 +2308,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicStore8") @inline(__always) - mutating func execute_i64AtomicStore8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicStore8(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try atomicStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }) let next = pc.pointee.pointee @@ -1997,7 +2316,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicStore16") @inline(__always) - mutating func execute_i64AtomicStore16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicStore16(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try atomicStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }) let next = pc.pointee.pointee @@ -2005,7 +2324,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicStore32") @inline(__always) - mutating func execute_i64AtomicStore32(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicStore32(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.StoreOperand.load(from: &pc.pointee) try atomicStore(sp: sp.pointee, md: md.pointee, ms: ms.pointee, storeOperand: immediate, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }) let next = pc.pointee.pointee @@ -2013,7 +2332,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmwAdd") @inline(__always) - mutating func execute_i32AtomicRmwAdd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmwAdd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_add_32($0, $1) }, castFromValue: { $0.i32 }, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -2021,7 +2340,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmwAdd") @inline(__always) - mutating func execute_i64AtomicRmwAdd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmwAdd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt64.self, atomicOp: { wasmkit_atomic_rmw_add_64($0, $1) }, castFromValue: { $0.i64 }, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -2029,7 +2348,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmwSub") @inline(__always) - mutating func execute_i32AtomicRmwSub(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmwSub(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_sub_32($0, $1) }, castFromValue: { $0.i32 }, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -2037,7 +2356,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmwSub") @inline(__always) - mutating func execute_i64AtomicRmwSub(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmwSub(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt64.self, atomicOp: { wasmkit_atomic_rmw_sub_64($0, $1) }, castFromValue: { $0.i64 }, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -2045,7 +2364,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmwAnd") @inline(__always) - mutating func execute_i32AtomicRmwAnd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmwAnd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_and_32($0, $1) }, castFromValue: { $0.i32 }, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -2053,7 +2372,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmwAnd") @inline(__always) - mutating func execute_i64AtomicRmwAnd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmwAnd(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt64.self, atomicOp: { wasmkit_atomic_rmw_and_64($0, $1) }, castFromValue: { $0.i64 }, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -2061,7 +2380,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmwOr") @inline(__always) - mutating func execute_i32AtomicRmwOr(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmwOr(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_or_32($0, $1) }, castFromValue: { $0.i32 }, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -2069,7 +2388,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmwOr") @inline(__always) - mutating func execute_i64AtomicRmwOr(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmwOr(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt64.self, atomicOp: { wasmkit_atomic_rmw_or_64($0, $1) }, castFromValue: { $0.i64 }, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -2077,7 +2396,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmwXor") @inline(__always) - mutating func execute_i32AtomicRmwXor(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmwXor(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_xor_32($0, $1) }, castFromValue: { $0.i32 }, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -2085,7 +2404,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmwXor") @inline(__always) - mutating func execute_i64AtomicRmwXor(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmwXor(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt64.self, atomicOp: { wasmkit_atomic_rmw_xor_64($0, $1) }, castFromValue: { $0.i64 }, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -2093,7 +2412,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmwXchg") @inline(__always) - mutating func execute_i32AtomicRmwXchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmwXchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_xchg_32($0, $1) }, castFromValue: { $0.i32 }, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -2101,7 +2420,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmwXchg") @inline(__always) - mutating func execute_i64AtomicRmwXchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmwXchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt64.self, atomicOp: { wasmkit_atomic_rmw_xchg_64($0, $1) }, castFromValue: { $0.i64 }, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -2109,7 +2428,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw8AddU") @inline(__always) - mutating func execute_i32AtomicRmw8AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw8AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_add_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2117,7 +2436,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw8AddU") @inline(__always) - mutating func execute_i64AtomicRmw8AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw8AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_add_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2125,7 +2444,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw8SubU") @inline(__always) - mutating func execute_i32AtomicRmw8SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw8SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_sub_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2133,7 +2452,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw8SubU") @inline(__always) - mutating func execute_i64AtomicRmw8SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw8SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_sub_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2141,7 +2460,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw8AndU") @inline(__always) - mutating func execute_i32AtomicRmw8AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw8AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_and_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2149,7 +2468,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw8AndU") @inline(__always) - mutating func execute_i64AtomicRmw8AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw8AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_and_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2157,7 +2476,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw8OrU") @inline(__always) - mutating func execute_i32AtomicRmw8OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw8OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_or_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2165,7 +2484,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw8OrU") @inline(__always) - mutating func execute_i64AtomicRmw8OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw8OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_or_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2173,7 +2492,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw8XorU") @inline(__always) - mutating func execute_i32AtomicRmw8XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw8XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_xor_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2181,7 +2500,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw8XorU") @inline(__always) - mutating func execute_i64AtomicRmw8XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw8XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_xor_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2189,7 +2508,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw8XchgU") @inline(__always) - mutating func execute_i32AtomicRmw8XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw8XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_xchg_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2197,7 +2516,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw8XchgU") @inline(__always) - mutating func execute_i64AtomicRmw8XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw8XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt8.self, atomicOp: { wasmkit_atomic_rmw_xchg_8($0, $1) }, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2205,7 +2524,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw16AddU") @inline(__always) - mutating func execute_i32AtomicRmw16AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw16AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_add_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2213,7 +2532,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw16AddU") @inline(__always) - mutating func execute_i64AtomicRmw16AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw16AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_add_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2221,7 +2540,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw16SubU") @inline(__always) - mutating func execute_i32AtomicRmw16SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw16SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_sub_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2229,7 +2548,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw16SubU") @inline(__always) - mutating func execute_i64AtomicRmw16SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw16SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_sub_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2237,7 +2556,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw16AndU") @inline(__always) - mutating func execute_i32AtomicRmw16AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw16AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_and_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2245,7 +2564,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw16AndU") @inline(__always) - mutating func execute_i64AtomicRmw16AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw16AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_and_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2253,7 +2572,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw16OrU") @inline(__always) - mutating func execute_i32AtomicRmw16OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw16OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_or_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2261,7 +2580,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw16OrU") @inline(__always) - mutating func execute_i64AtomicRmw16OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw16OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_or_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2269,7 +2588,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw16XorU") @inline(__always) - mutating func execute_i32AtomicRmw16XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw16XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_xor_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2277,7 +2596,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw16XorU") @inline(__always) - mutating func execute_i64AtomicRmw16XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw16XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_xor_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2285,7 +2604,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw16XchgU") @inline(__always) - mutating func execute_i32AtomicRmw16XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw16XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_xchg_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2293,7 +2612,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw16XchgU") @inline(__always) - mutating func execute_i64AtomicRmw16XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw16XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt16.self, atomicOp: { wasmkit_atomic_rmw_xchg_16($0, $1) }, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2301,7 +2620,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw32AddU") @inline(__always) - mutating func execute_i64AtomicRmw32AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw32AddU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_add_32($0, $1) }, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2309,7 +2628,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw32SubU") @inline(__always) - mutating func execute_i64AtomicRmw32SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw32SubU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_sub_32($0, $1) }, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2317,7 +2636,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw32AndU") @inline(__always) - mutating func execute_i64AtomicRmw32AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw32AndU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_and_32($0, $1) }, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2325,7 +2644,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw32OrU") @inline(__always) - mutating func execute_i64AtomicRmw32OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw32OrU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_or_32($0, $1) }, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2333,7 +2652,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw32XorU") @inline(__always) - mutating func execute_i64AtomicRmw32XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw32XorU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_xor_32($0, $1) }, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2341,7 +2660,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw32XchgU") @inline(__always) - mutating func execute_i64AtomicRmw32XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw32XchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.RmwOperand.load(from: &pc.pointee) try atomicRmw(sp: sp.pointee, md: md.pointee, ms: ms.pointee, rmwOperand: immediate, loadAs: UInt32.self, atomicOp: { wasmkit_atomic_rmw_xchg_32($0, $1) }, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2349,7 +2668,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmwCmpxchg") @inline(__always) - mutating func execute_i32AtomicRmwCmpxchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmwCmpxchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CmpxchgOperand.load(from: &pc.pointee) try atomicCmpxchg(sp: sp.pointee, md: md.pointee, ms: ms.pointee, cmpxchgOperand: immediate, loadAs: UInt32.self, atomicCmpxchg: { ptr, expected, desired in var exp = expected; _ = wasmkit_atomic_cmpxchg_32(ptr, &exp, desired); return exp }, castFromValue: { $0.i32 }, castToValue: { .i32($0) }) let next = pc.pointee.pointee @@ -2357,7 +2676,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmwCmpxchg") @inline(__always) - mutating func execute_i64AtomicRmwCmpxchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmwCmpxchg(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CmpxchgOperand.load(from: &pc.pointee) try atomicCmpxchg(sp: sp.pointee, md: md.pointee, ms: ms.pointee, cmpxchgOperand: immediate, loadAs: UInt64.self, atomicCmpxchg: { ptr, expected, desired in var exp = expected; _ = wasmkit_atomic_cmpxchg_64(ptr, &exp, desired); return exp }, castFromValue: { $0.i64 }, castToValue: { .i64($0) }) let next = pc.pointee.pointee @@ -2365,7 +2684,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw8CmpxchgU") @inline(__always) - mutating func execute_i32AtomicRmw8CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw8CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CmpxchgOperand.load(from: &pc.pointee) try atomicCmpxchg(sp: sp.pointee, md: md.pointee, ms: ms.pointee, cmpxchgOperand: immediate, loadAs: UInt8.self, atomicCmpxchg: { ptr, expected, desired in var exp = expected; _ = wasmkit_atomic_cmpxchg_8(ptr, &exp, desired); return exp }, castFromValue: { UInt8(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2373,7 +2692,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i32AtomicRmw16CmpxchgU") @inline(__always) - mutating func execute_i32AtomicRmw16CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i32AtomicRmw16CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CmpxchgOperand.load(from: &pc.pointee) try atomicCmpxchg(sp: sp.pointee, md: md.pointee, ms: ms.pointee, cmpxchgOperand: immediate, loadAs: UInt16.self, atomicCmpxchg: { ptr, expected, desired in var exp = expected; _ = wasmkit_atomic_cmpxchg_16(ptr, &exp, desired); return exp }, castFromValue: { UInt16(truncatingIfNeeded: $0.i32) }, castToValue: { .i32(UInt32($0)) }) let next = pc.pointee.pointee @@ -2381,7 +2700,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw8CmpxchgU") @inline(__always) - mutating func execute_i64AtomicRmw8CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw8CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CmpxchgOperand.load(from: &pc.pointee) try atomicCmpxchg(sp: sp.pointee, md: md.pointee, ms: ms.pointee, cmpxchgOperand: immediate, loadAs: UInt8.self, atomicCmpxchg: { ptr, expected, desired in var exp = expected; _ = wasmkit_atomic_cmpxchg_8(ptr, &exp, desired); return exp }, castFromValue: { UInt8(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2389,7 +2708,7 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw16CmpxchgU") @inline(__always) - mutating func execute_i64AtomicRmw16CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw16CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CmpxchgOperand.load(from: &pc.pointee) try atomicCmpxchg(sp: sp.pointee, md: md.pointee, ms: ms.pointee, cmpxchgOperand: immediate, loadAs: UInt16.self, atomicCmpxchg: { ptr, expected, desired in var exp = expected; _ = wasmkit_atomic_cmpxchg_16(ptr, &exp, desired); return exp }, castFromValue: { UInt16(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee @@ -2397,13 +2716,14 @@ extension Execution { return next } @_silgen_name("wasmkit_execute_i64AtomicRmw32CmpxchgU") @inline(__always) - mutating func execute_i64AtomicRmw32CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { + mutating func execute_i64AtomicRmw32CmpxchgU(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws(Trap) -> CodeSlot { let immediate = Instruction.CmpxchgOperand.load(from: &pc.pointee) try atomicCmpxchg(sp: sp.pointee, md: md.pointee, ms: ms.pointee, cmpxchgOperand: immediate, loadAs: UInt32.self, atomicCmpxchg: { ptr, expected, desired in var exp = expected; _ = wasmkit_atomic_cmpxchg_32(ptr, &exp, desired); return exp }, castFromValue: { UInt32(truncatingIfNeeded: $0.i64) }, castToValue: { .i64(UInt64($0)) }) let next = pc.pointee.pointee pc.pointee = pc.pointee.advanced(by: 1) return next } + #if !$Embedded @_silgen_name("wasmkit_execute_memoryAtomicWait32") @inline(__always) mutating func execute_memoryAtomicWait32(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { let immediate = Instruction.AtomicWaitOperand.load(from: &pc.pointee) @@ -2428,6 +2748,7 @@ extension Execution { pc.pointee = pc.pointee.advanced(by: 1) return next } + #endif // !$Embedded @_silgen_name("wasmkit_execute_atomicFence") @inline(__always) mutating func execute_atomicFence(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) -> CodeSlot { atomicFence(sp: sp.pointee) @@ -2435,6 +2756,7 @@ extension Execution { pc.pointee = pc.pointee.advanced(by: 1) return next } + #if !$Embedded @_silgen_name("wasmkit_execute_throwTag") @inline(__always) mutating func execute_throwTag(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) throws -> CodeSlot { let immediate = Instruction.ThrowTagOperand.load(from: &pc.pointee) @@ -2449,6 +2771,8 @@ extension Execution { (pc.pointee, next) = try self.throwRef(sp: sp.pointee, pc: pc.pointee, immediate: immediate) return next } + #endif // !$Embedded + #if !$Embedded @_silgen_name("wasmkit_execute_catchHandlers") @inline(__always) mutating func execute_catchHandlers(sp: UnsafeMutablePointer, pc: UnsafeMutablePointer, md: UnsafeMutablePointer, ms: UnsafeMutablePointer) -> CodeSlot { let immediate = Instruction.CatchHandlersOperand.load(from: &pc.pointee) @@ -2464,6 +2788,7 @@ extension Execution { pc.pointee = pc.pointee.advanced(by: 1) return next } + #endif // !$Embedded } extension Instruction { diff --git a/Sources/WasmKit/Execution/EngineInterceptor.swift b/Sources/WasmKit/Execution/EngineInterceptor.swift index 2a785920..731d0186 100644 --- a/Sources/WasmKit/Execution/EngineInterceptor.swift +++ b/Sources/WasmKit/Execution/EngineInterceptor.swift @@ -1,3 +1,6 @@ +// EngineInterceptor uses existential protocol types ([EngineInterceptor]) which +// are not available in Embedded Swift. +#if !$Embedded @_documentation(visibility: internal) public protocol EngineInterceptor { func onEnterFunction(_ function: Function) @@ -27,3 +30,4 @@ public class MultiplexingInterceptor: EngineInterceptor { } } } +#endif // !$Embedded diff --git a/Sources/WasmKit/Execution/Errors.swift b/Sources/WasmKit/Execution/Errors.swift index 6478d3fc..b5fcfd12 100644 --- a/Sources/WasmKit/Execution/Errors.swift +++ b/Sources/WasmKit/Execution/Errors.swift @@ -1,20 +1,18 @@ import WasmTypes -import struct WasmParser.Import +import struct WasmParserCore.Import /// The backtrace of the trap. -public struct Backtrace: CustomStringConvertible, Sendable { - /// A symbol in the backtrace. +public struct Backtrace: Sendable { public struct Symbol: @unchecked Sendable { - /// The name of the symbol. public let name: String? let address: Pc } - - /// The symbols in the backtrace. public let symbols: [Symbol] +} - /// Textual description of the backtrace. +#if !$Embedded +extension Backtrace: CustomStringConvertible { public var description: String { symbols.enumerated().map { (index, symbol) in let name = symbol.name ?? "unknown" @@ -22,13 +20,11 @@ public struct Backtrace: CustomStringConvertible, Sendable { }.joined(separator: "\n") } } +#endif /// An error that occurs during execution of a WebAssembly module. -public struct Trap: Error, CustomStringConvertible { - /// The reason for the trap. +public struct Trap: Error { package private(set) var reason: TrapReason - - /// The backtrace of the trap. private(set) var backtrace: Backtrace? init(_ code: TrapReason, backtrace: Backtrace? = nil) { @@ -40,15 +36,6 @@ public struct Trap: Error, CustomStringConvertible { self.init(.message(message), backtrace: backtrace) } - /// The description of the trap. - public var description: String { - var desc = "Trap: \(reason)" - if let backtrace = backtrace { - desc += "\n\(backtrace)" - } - return desc - } - func withBacktrace(_ backtrace: Backtrace) -> Trap { var trap = self trap.backtrace = backtrace @@ -56,12 +43,19 @@ public struct Trap: Error, CustomStringConvertible { } } +#if !$Embedded +extension Trap: CustomStringConvertible { + public var description: String { + var desc = "Trap: \(reason)" + if let backtrace = backtrace { desc += "\n\(backtrace)" } + return desc + } +} +#endif + /// An uncaught WebAssembly exception that propagated out of a module. -public struct WasmKitException: Error, CustomStringConvertible { - /// The tag identity, stored as the bit pattern of the tag handle pointer. - /// Used only for equality comparison when matching catch clauses. +public struct WasmKitException: Error { let tagIdentity: Int - /// The exception payload values. let payload: [Value] init(tag: InternalTag, payload: [Value]) { @@ -69,69 +63,46 @@ public struct WasmKitException: Error, CustomStringConvertible { self.payload = payload } - public var description: String { - "wasm exception (payload: \(payload))" - } + func hasTag(_ tag: InternalTag) -> Bool { tagIdentity == tag.bitPattern } +} - /// Returns true if this exception's tag matches the given tag handle. - func hasTag(_ tag: InternalTag) -> Bool { - tagIdentity == tag.bitPattern - } +#if !$Embedded +extension WasmKitException: CustomStringConvertible { + public var description: String { "wasm exception (payload: \(payload))" } } +#endif /// A reason for a trap that occurred during execution of a WebAssembly module. -package enum TrapReason: Error, CustomStringConvertible { +package enum TrapReason: Error { package struct Message { let text: String - - init(_ text: String) { - self.text = text - } + init(_ text: String) { self.text = text } } - /// A trap with a string message case message(Message) - /// `unreachable` instruction executed case unreachable - /// Too deep call stack - /// - /// Note: When this trap occurs, consider extending ``EngineConfiguration/stackSize``. case callStackExhausted - /// Out of bounds table access case tableOutOfBounds(Int) - /// Out of bounds memory access case memoryOutOfBounds - /// Unaligned atomic memory access case unalignedAtomic - /// `call_indirect` instruction called an uninitialized table element. case indirectCallToNull(Int) - /// Indirect call type mismatch case typeMismatchCall(actual: FunctionType, expected: FunctionType) - /// Integer divided by zero case integerDividedByZero - /// Integer overflowed during arithmetic operation case integerOverflow - /// Invalid conversion to integer case invalidConversionToInteger +} - /// The description of the trap reason. +#if !$Embedded +extension TrapReason: CustomStringConvertible { package var description: String { switch self { - case .message(let message): - return message.text - case .unreachable: - return "unreachable" - case .callStackExhausted: - return "call stack exhausted" - case .memoryOutOfBounds: - return "out of bounds memory access" - case .unalignedAtomic: - return "unaligned atomic" - case .integerDividedByZero: - return "integer divide by zero" - case .integerOverflow: - return "integer overflow" - case .invalidConversionToInteger: - return "invalid conversion to integer" + case .message(let message): return message.text + case .unreachable: return "unreachable" + case .callStackExhausted: return "call stack exhausted" + case .memoryOutOfBounds: return "out of bounds memory access" + case .unalignedAtomic: return "unaligned atomic" + case .integerDividedByZero: return "integer divide by zero" + case .integerOverflow: return "integer overflow" + case .invalidConversionToInteger: return "invalid conversion to integer" case .indirectCallToNull(let elementIndex): return "indirect call to null element (uninitialized element \(elementIndex))" case .typeMismatchCall(let actual, let expected): @@ -141,28 +112,55 @@ package enum TrapReason: Error, CustomStringConvertible { } } } +#endif extension TrapReason.Message { static func initialTableSizeExceedsLimit(numberOfElements: Int) -> Self { + #if !$Embedded Self("initial table size exceeds the resource limit: \(numberOfElements) elements") + #else + Self("initial table size exceeds the resource limit") + #endif } static func initialMemorySizeExceedsLimit(byteSize: Int) -> Self { + #if !$Embedded Self("initial memory size exceeds the resource limit: \(byteSize) bytes") + #else + Self("initial memory size exceeds the resource limit") + #endif } + // In Embedded mode, avoid String interpolation over [ValueType]/[Value] arrays + // which pulls in collection description formatting (~4-8 KB of code). static func parameterTypesMismatch(expected: [ValueType], got: [Value]) -> Self { + #if !$Embedded Self("parameter types don't match, expected \(expected), got \(got)") + #else + Self("(cannot print value in embedded Swift)") + #endif } static func resultTypesMismatch(expected: [ValueType], got: [Value]) -> Self { + #if !$Embedded Self("result types don't match, expected \(expected), got \(got)") + #else + Self("(cannot print value in embedded Swift)") + #endif } static var cannotAssignToImmutableGlobal: Self { Self("cannot assign to an immutable global") } static func noGlobalExportWithName(globalName: String, instance: Instance) -> Self { + #if !$Embedded Self("no global export with name \(globalName) in a module instance \(instance)") + #else + Self("no global export with name found in module instance") + #endif } static func exportedFunctionNotFound(name: String, instance: Instance) -> Self { + #if !$Embedded Self("exported function \(name) not found in instance \(instance)") + #else + Self("exported function not found in instance") + #endif } static func unimplemented(feature: String) -> Self { Self("\(feature) is not implemented yet") diff --git a/Sources/WasmKit/Execution/Execution.swift b/Sources/WasmKit/Execution/Execution.swift index 75be5576..32fa0751 100644 --- a/Sources/WasmKit/Execution/Execution.swift +++ b/Sources/WasmKit/Execution/Execution.swift @@ -1,4 +1,5 @@ import _CWasmKit +import WasmParserCore /// An execution state of an invocation of exported function. /// @@ -18,6 +19,11 @@ struct Execution: ~Copyable { /// The stack of active exception handlers for `try_table` blocks. var exceptionHandlers: [ExceptionHandler] = [] + #if $Embedded + /// In embedded mode, signals end-of-execution instead of throwing EndOfExecution. + var isFinished: Bool = false + #endif + /// Storage for caught exceptions that may be referenced via `exnref`. var storedExceptions: [WasmKitException] = [] @@ -57,6 +63,19 @@ struct Execution: ~Copyable { return try body(&context, valueStack) } + static func withTyped( + store: StoreRef, + body: (inout Execution, Sp) throws(E) -> T + ) throws(E) -> T { + let limit = store.value.engine.configuration.stackSize / MemoryLayout.stride + let valueStack = UnsafeMutablePointer.allocate(capacity: limit) + defer { + valueStack.deallocate() + } + var context = Execution(store: store, stackEnd: valueStack.advanced(by: limit)) + return try body(&context, valueStack) + } + /// Gets the current instance from the stack pointer. @inline(__always) func currentInstance(sp: Sp) -> InternalInstance { @@ -132,7 +151,7 @@ struct Execution: ~Copyable { numberOfNonParameterLocalSlots: Int, sp: Sp, returnPC: Pc, spAddend: VReg - ) throws -> Sp { + ) throws(Trap) -> Sp { let newSp = sp.advanced(by: Int(spAddend)) try checkStackBoundary(newSp.advanced(by: iseq.maxStackHeight)) initializeConstSlots(sp: newSp, iseq: iseq, numberOfNonParameterLocalSlots: numberOfNonParameterLocalSlots) @@ -334,6 +353,7 @@ extension Pc { /// - arguments: The arguments to be passed to the function. /// - callerInstance: The instance that called the function. /// - Returns: The result values of the function. +#if !$Embedded @inline(never) func executeWasm( store: Store, @@ -373,9 +393,48 @@ func executeWasm( } } } +#else // $Embedded +@inline(never) +func executeWasm( + store: Store, + function handle: InternalFunction, + type: FunctionType, + arguments: [Value] +) throws(Trap) -> [Value] { + let store = StoreRef(store) + return try Execution.withTyped(store: store) { (stack: inout Execution, sp: Sp) throws(Trap) -> [Value] in + let sp = sp.advanced(by: FrameHeaderLayout.numberOfSavingSlots) + sp.previousSP = nil + sp.currentFunction = nil + let layout = FrameHeaderLayout(type: type) + for (index, argument) in arguments.enumerated() { + let reg = layout.size + layout.paramReg(index) + sp.storeValue(argument, at: reg, type: type.parameters[index]) + } + var rootISeq: (CodeSlot, CodeSlot) = ( + Instruction.endOfExecution.headSlot(threadingModel: store.value.engine.configuration.threadingModel), + 0 + ) + // Use withUnsafeMutablePointer via a do throws(Trap) block to propagate typed error + var thrownTrap: Trap? = nil + withUnsafeMutablePointer(to: &rootISeq.0) { rootPtr in + do throws(Trap) { + try stack.executeEmbedded(rootSp: sp, rootISQ: rootPtr, handle: handle, type: type) + } catch let trap { + thrownTrap = trap + } + } + if let trap = thrownTrap { throw trap } + return type.results.enumerated().map { (i, resultType) in + let reg = layout.size + layout.returnReg(i) + return sp.loadValue(at: reg, type: resultType) + } + } +} +#endif // !$Embedded extension Execution { - #if WasmDebuggingSupport + #if WasmDebuggingSupport && !$Embedded /// Counterpart to the free `executeWasm` function but implemented as a method of `Execution`, /// Useful for representation of debugger state that needs to own `Execution`'s memory. @@ -472,6 +531,7 @@ extension Execution { let pc: Pc } + #if !$Embedded /// The entry point for the execution of the WebAssembly function. @inline(never) mutating func execute( @@ -500,13 +560,49 @@ extension Execution { return } } + #endif // !$Embedded + + #if $Embedded + /// Embedded-mode entry point for execution: typed as throws(Trap) for embedded Swift. + @inline(never) + mutating func executeEmbedded( + rootSp: Sp, rootISQ: UnsafeMutablePointer, + handle: InternalFunction, + type: FunctionType + ) throws(Trap) { + var sp: Sp = rootSp + var md: Md = nil + var ms: Ms = 0 + var pc: Pc = rootISQ + (pc, sp) = try invoke( + function: handle, + callerInstance: nil, + spAddend: FrameHeaderLayout.size(of: type), + sp: sp, pc: pc, md: &md, ms: &ms + ) + isFinished = false + try runTokenThreadedEmbedded(sp: &sp, pc: &pc, md: &md, ms: &ms) + } + + @inline(__always) + mutating func runTokenThreadedEmbedded(sp: inout Sp, pc: inout Pc, md: inout Md, ms: inout Ms) throws(Trap) { + var opcode = pc.read(OpcodeID.self) + do throws(Trap) { + while !isFinished { + opcode = try doExecuteEmbedded(opcode, sp: &sp, pc: &pc, md: &md, ms: &ms) + } + } catch let trap { + throw trap.withBacktrace(Self.captureBacktrace(sp: sp, store: store.value)) + } + } + #endif // $Embedded /// Starts the main execution loop using the direct threading model. @inline(never) mutating func runDirectThreaded( sp: Sp, pc: Pc, md: Md, ms: Ms ) throws { - #if os(WASI) + #if os(WASI) || $Embedded fatalError("Direct threading is not supported on WASI") #else var sp = sp @@ -633,6 +729,7 @@ extension Execution { #endif var opcode = pc.read(OpcodeID.self) while true { + #if !$Embedded do { while true { #if EngineStats @@ -649,6 +746,7 @@ extension Execution { } catch let trap as Trap { throw trap.withBacktrace(Self.captureBacktrace(sp: sp, store: store.value)) } + #endif // !$Embedded } } @@ -669,7 +767,7 @@ extension Execution { } @inline(__always) - func checkStackBoundary(_ sp: Sp) throws { + func checkStackBoundary(_ sp: Sp) throws(Trap) { guard sp < stackEnd else { throw Trap(.callStackExhausted) } } @@ -680,14 +778,24 @@ extension Execution { callerInstance: InternalInstance?, spAddend: VReg, sp: Sp, pc: Pc, md: inout Md, ms: inout Ms - ) throws -> (Pc, Sp) { + ) throws(Trap) -> (Pc, Sp) { if function.isWasm { return try invokeWasmFunction( function: function.wasm, callerInstance: callerInstance, spAddend: spAddend, sp: sp, pc: pc, md: &md, ms: &ms ) } else { - try invokeHostFunction(function: function.host, sp: sp, spAddend: spAddend) + #if !$Embedded + do { + try invokeHostFunction(function: function.host, sp: sp, spAddend: spAddend) + } catch let trap as Trap { + throw trap + } catch { + throw Trap(.message(TrapReason.Message("host function threw an error"))) + } + #else + fatalError("Host functions are not supported in embedded Swift") + #endif return (pc, sp) } } @@ -697,14 +805,24 @@ extension Execution { function: InternalFunction, callerInstance: InternalInstance?, sp: Sp, pc: Pc, md: inout Md, ms: inout Ms - ) throws -> (Pc, Sp) { + ) throws(Trap) -> (Pc, Sp) { if function.isWasm { return try tailInvokeWasmFunction( function: function.wasm, callerInstance: callerInstance, sp: sp, md: &md, ms: &ms ) } else { - try invokeHostFunction(function: function.host, sp: sp, spAddend: 0) + #if !$Embedded + do { + try invokeHostFunction(function: function.host, sp: sp, spAddend: 0) + } catch let trap as Trap { + throw trap + } catch { + throw Trap(.message(TrapReason.Message("host function threw an error"))) + } + #else + fatalError("Host functions are not supported in embedded Swift") + #endif return (pc, sp) } } @@ -718,7 +836,7 @@ extension Execution { function: EntityHandle, callerInstance: InternalInstance?, sp: Sp, md: inout Md, ms: inout Ms - ) throws -> (Pc, Sp) { + ) throws(Trap) -> (Pc, Sp) { let iseq = try function.ensureCompiled(store: store) try checkStackBoundary(sp.advanced(by: iseq.maxStackHeight)) sp.currentFunction = function @@ -739,7 +857,7 @@ extension Execution { callerInstance: InternalInstance?, spAddend: VReg, sp: Sp, pc: Pc, md: inout Md, ms: inout Ms - ) throws -> (Pc, Sp) { + ) throws(Trap) -> (Pc, Sp) { let iseq = try function.ensureCompiled(store: store) let newSp = try pushFrame( diff --git a/Sources/WasmKit/Execution/Function.swift b/Sources/WasmKit/Execution/Function.swift index 3b2ddb3e..695effff 100644 --- a/Sources/WasmKit/Execution/Function.swift +++ b/Sources/WasmKit/Execution/Function.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore import struct WasmTypes.FunctionType @@ -85,10 +85,17 @@ public struct Function: Equatable { /// - arguments: The arguments to pass to the function. /// - Throws: A trap if the function invocation fails. /// - Returns: The results of the function invocation. + #if !$Embedded @discardableResult public func invoke(_ arguments: [Value] = []) throws -> [Value] { return try handle.invoke(arguments, store: store) } + #else + @discardableResult + public func invoke(_ arguments: [Value] = []) throws(Trap) -> [Value] { + return try handle.invoke(arguments, store: store) + } + #endif /// Invokes a function of the given address with the given parameters. /// @@ -96,10 +103,17 @@ public struct Function: Equatable { /// - arguments: The arguments to pass to the function. /// - Throws: A trap if the function invocation fails. /// - Returns: The results of the function invocation. + #if !$Embedded @discardableResult public func callAsFunction(_ arguments: [Value] = []) throws -> [Value] { return try invoke(arguments) } + #else + @discardableResult + public func callAsFunction(_ arguments: [Value] = []) throws(Trap) -> [Value] { + return try invoke(arguments) + } + #endif /// Invokes a function of the given address with the given parameters. /// @@ -108,11 +122,13 @@ public struct Function: Equatable { /// - runtime: The runtime to use for the function invocation. /// - Throws: A trap if the function invocation fails. /// - Returns: The results of the function invocation. + #if !$Embedded @available(*, deprecated, renamed: "invoke(_:)") @discardableResult public func invoke(_ arguments: [Value] = [], runtime: Runtime) throws -> [Value] { return try invoke(arguments) } + #endif } @available(*, deprecated, renamed: "Function", message: "Use Function instead") @@ -166,6 +182,7 @@ extension InternalFunction: ValidatableEntity { } extension InternalFunction { + #if !$Embedded func invoke(_ arguments: [Value], store: Store) throws -> [Value] { if isWasm { let entity = wasm @@ -187,6 +204,23 @@ extension InternalFunction { return results } } + #else + func invoke(_ arguments: [Value], store: Store) throws(Trap) -> [Value] { + if isWasm { + let entity = wasm + let resolvedType = store.engine.resolveType(entity.type) + try check(functionType: resolvedType, parameters: arguments) + return try executeWasm( + store: store, + function: self, + type: resolvedType, + arguments: arguments + ) + } else { + fatalError("Host functions are not supported in embedded Swift") + } + } + #endif private func check(expectedTypes: [ValueType], values: [Value]) -> Bool { guard expectedTypes.count == values.count else { return false } @@ -202,13 +236,13 @@ extension InternalFunction { return true } - private func check(functionType: FunctionType, parameters: [Value]) throws { + private func check(functionType: FunctionType, parameters: [Value]) throws(Trap) { guard check(expectedTypes: functionType.parameters, values: parameters) else { throw Trap(.parameterTypesMismatch(expected: functionType.parameters, got: parameters)) } } - private func check(functionType: FunctionType, results: [Value]) throws { + private func check(functionType: FunctionType, results: [Value]) throws(Trap) { guard check(expectedTypes: functionType.results, values: results) else { throw Trap(.resultTypesMismatch(expected: functionType.results, got: results)) } @@ -244,7 +278,7 @@ struct WasmFunctionEntity { self.index = index } - mutating func ensureCompiled(store: StoreRef) throws -> InstructionSequence { + mutating func ensureCompiled(store: StoreRef) throws(Trap) -> InstructionSequence { switch code { case .uncompiled(let code): return try compile(store: store, code: code) @@ -254,22 +288,32 @@ struct WasmFunctionEntity { } @inline(never) - mutating func compile(store: StoreRef, code: InternalUncompiledCode) throws -> InstructionSequence { + mutating func compile(store: StoreRef, code: InternalUncompiledCode) throws(Trap) -> InstructionSequence { let store = store.value let engine = store.engine let type = self.type - let iseq = try code.withValue { code in - 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) + #if !$Embedded + let isIntercepting = engine.interceptor != nil + #else + let isIntercepting = false + #endif + let iseq: InstructionSequence + do throws(WasmKitError) { + iseq = try code.withValue { (codeEntity: inout Code) throws(WasmKitError) -> InstructionSequence in + try InstructionTranslator( + allocator: store.allocator.iseqAllocator, + engineConfiguration: engine.configuration, + funcTypeInterner: engine.funcTypeInterner, + module: instance, + type: engine.resolveType(type), + locals: codeEntity.locals, + functionIndex: index, + codeSize: codeEntity.expression.count, + isIntercepting: isIntercepting + ).translate(code: codeEntity) + } + } catch let e { + throw Trap(.message(TrapReason.Message("trap"))) } self.code = .compiled(iseq) return iseq @@ -279,15 +323,15 @@ struct WasmFunctionEntity { extension EntityHandle { @inline(never) @discardableResult - func ensureCompiled(store: StoreRef) throws -> InstructionSequence { + func ensureCompiled(store: StoreRef) throws(Trap) -> InstructionSequence { switch self.code { case .uncompiled(let code): - return try self.withValue { - let iseq = try $0.compile(store: store, code: code) - if $0.instance.isDebuggable { - $0.code = .debuggable(code, iseq) + return try self.withValue { (fn: inout WasmFunctionEntity) throws(Trap) -> InstructionSequence in + let iseq = try fn.compile(store: store, code: code) + if fn.instance.isDebuggable { + fn.code = .debuggable(code, iseq) } else { - $0.code = .compiled(iseq) + fn.code = .compiled(iseq) } return iseq } @@ -334,3 +378,13 @@ extension Reference { return .function(value.bitPattern) } } + +#if $Embedded +extension EntityHandle { + var type: InternedFuncType { withValue { $0.type } } + var instance: InternalInstance { withValue { $0.instance } } + var index: FunctionIndex { withValue { $0.index } } + var numberOfNonParameterLocalSlots: Int { withValue { $0.numberOfNonParameterLocalSlots } } + var code: CodeBody { withValue { $0.code } } +} +#endif // $Embedded diff --git a/Sources/WasmKit/Execution/Instances.swift b/Sources/WasmKit/Execution/Instances.swift index 17ad1a97..b9fed532 100644 --- a/Sources/WasmKit/Execution/Instances.swift +++ b/Sources/WasmKit/Execution/Instances.swift @@ -1,10 +1,12 @@ +#if !$Embedded import Synchronization -import WasmParser +#endif +import WasmParserCore -@_exported import struct WasmParser.GlobalType -@_exported import struct WasmParser.Limits -@_exported import struct WasmParser.MemoryType -@_exported import struct WasmParser.TableType +@_exported import struct WasmParserCore.GlobalType +@_exported import struct WasmParserCore.Limits +@_exported import struct WasmParserCore.MemoryType +@_exported import struct WasmParserCore.TableType // This file defines the internal representation of WebAssembly entities and // their public API. @@ -39,7 +41,9 @@ import WasmParser /// /// This type is designed to eliminate ARC retain/release for entities /// known to be alive during a VM execution. +#if !$Embedded @dynamicMemberLookup +#endif package struct EntityHandle: Equatable, Hashable, Copyable { private let pointer: UnsafeMutablePointer @@ -52,12 +56,14 @@ package struct EntityHandle: Equatable, Hashable, Copyable { self.pointer = pointer } + #if !$Embedded package subscript(dynamicMember keyPath: KeyPath) -> R where T: Copyable { withValue { $0[keyPath: keyPath] } } + #endif // !$Embedded @inline(__always) - package func withValue(_ body: (inout T) throws -> R) rethrows -> R { + package func withValue(_ body: (inout T) throws(E) -> R) throws(E) -> R { return try body(&pointer.pointee) } @@ -72,6 +78,17 @@ extension EntityHandle: ValidatableEntity where T: ValidatableEntity, T: ~Copyab } } +// Type alias for the exports collection. +// In non-Embedded mode: Dictionary for O(1) lookups. +// In Embedded mode: Array to avoid String.hashValue → NFC normalization (~31 KB). +// All export lookups go through Exports.find(_:) which does linear search with +// byte comparison (Exports.findEntity in Instances.swift). +#if !$Embedded +typealias ExportsStorage = [String: InternalExternalValue] +#else +typealias ExportsStorage = [(key: String, value: InternalExternalValue)] +#endif + package struct InstanceEntity /* : ~Copyable */ { var types: [FunctionType] var functions: ImmutableArray @@ -81,7 +98,7 @@ package struct InstanceEntity /* : ~Copyable */ { var tags: ImmutableArray var elementSegments: ImmutableArray var dataSegments: ImmutableArray - var exports: [String: InternalExternalValue] + var exports: ExportsStorage var functionRefs: Set var features: WasmFeatureSet var dataCount: UInt32? @@ -99,7 +116,7 @@ package struct InstanceEntity /* : ~Copyable */ { tags: ImmutableArray(), elementSegments: ImmutableArray(), dataSegments: ImmutableArray(), - exports: [:], + exports: ExportsStorage(), functionRefs: [], features: [], dataCount: nil, @@ -108,7 +125,7 @@ package struct InstanceEntity /* : ~Copyable */ { ) } - package func compileAllFunctions(store: Store) throws { + package func compileAllFunctions(store: Store) throws(Trap) { let store = StoreRef(store) for function in functions { guard function.isWasm else { continue } @@ -122,7 +139,7 @@ package typealias InternalInstance = EntityHandle /// A map of exported entities by name. public struct Exports: Sequence { let store: Store - let items: [String: InternalExternalValue] + let items: ExportsStorage /// A collection of exported entities without their names. public var values: [ExternalValue] { @@ -131,8 +148,19 @@ public struct Exports: Sequence { /// Returns the exported entity with the given name. public subscript(_ name: String) -> ExternalValue? { + #if !$Embedded guard let entity = items[name] else { return nil } return ExternalValue(handle: entity, store: store) + #else + // Array linear search in Embedded mode using byte comparison. + // Avoids String.== and String.hashValue which pull in NFC normalization. + let nameUTF8 = name.utf8 + for (key, entity) in items { + guard key.utf8.elementsEqual(nameUTF8) else { continue } + return ExternalValue(handle: entity, store: store) + } + return nil + #endif } /// Returns the exported function with the given name. @@ -159,9 +187,47 @@ public struct Exports: Sequence { return global } + #if $Embedded + // Embedded-safe export lookup using StaticString (compile-time constant) to + // avoid String.hashValue / String.== which pull in Unicode NFC normalization. + // Uses UTF-8 byte comparison via elementsEqual — no normalization path. + private func findEntity(_ name: StaticString) -> ExternalValue? { + let nameLen = name.utf8CodeUnitCount + for (key, entity) in items { + guard key.utf8.count == nameLen else { continue } + var i = 0 + var match = true + for byte in key.utf8 { + if byte != name.utf8Start[i] { match = false; break } + i &+= 1 + } + if match { return ExternalValue(handle: entity, store: store) } + } + return nil + } + + /// Finds an exported function by compile-time ASCII name without Unicode normalization. + public func find(function name: StaticString) -> Function? { + guard case .function(let f) = findEntity(name) else { return nil } + return f // ExternalValue.function already wraps a public Function + } + + /// Finds an exported memory by compile-time ASCII name without Unicode normalization. + public func find(memory name: StaticString) -> Memory? { + guard case .memory(let m) = findEntity(name) else { return nil } + return m + } + + /// Finds an exported global by compile-time ASCII name without Unicode normalization. + public func find(global name: StaticString) -> Global? { + guard case .global(let g) = findEntity(name) else { return nil } + return g + } + #endif + public struct Iterator: IteratorProtocol { private let store: Store - private var iterator: Dictionary.Iterator + private var iterator: ExportsStorage.Iterator init(parent: Exports) { self.store = parent.store @@ -197,8 +263,17 @@ public struct Instance { /// - Parameter name: The name of the exported entity. /// - Returns: The exported entity if found, otherwise `nil`. public func export(_ name: String) -> ExternalValue? { + #if !$Embedded guard let entity = handle.exports[name] else { return nil } return ExternalValue(handle: entity, store: store) + #else + let nameUTF8 = name.utf8 + for (key, entity) in handle.exports { + guard key.utf8.elementsEqual(nameUTF8) else { continue } + return ExternalValue(handle: entity, store: store) + } + return nil + #endif } /// Finds an exported function by name. @@ -281,7 +356,7 @@ struct TableEntity /* : ~Copyable */ { return UInt64(UInt32.max) } - init(_ tableType: TableType, resourceLimiter: any ResourceLimiter) throws { + init(_ tableType: TableType, resourceLimiter: RL) throws(Trap) { let emptyElement: Reference switch tableType.elementType.heapType { case .abstract(.funcRef): @@ -304,7 +379,7 @@ struct TableEntity /* : ~Copyable */ { /// > Note: https://webassembly.github.io/spec/core/exec/modules.html#grow-table /// Returns true if gorwth succeeds, otherwise returns false - mutating func grow(by growthSize: UInt64, value: Reference, resourceLimiter: any ResourceLimiter) throws -> Bool { + mutating func grow(by growthSize: UInt64, value: Reference, resourceLimiter: RL) throws(Trap) -> Bool { let oldSize = UInt64(elements.count) guard !UInt64(elements.count).addingReportingOverflow(growthSize).overflow else { return false @@ -316,18 +391,16 @@ struct TableEntity /* : ~Copyable */ { if newSize > maxLimit { return false } - guard try resourceLimiter.limitTableGrowth(to: Int(newSize)) else { - return false - } + guard try resourceLimiter.limitTableGrowth(to: Int(newSize)) else { return false } elements.append(contentsOf: Array(repeating: value, count: Int(growthSize))) return true } - mutating func initialize(_ segment: InternalElementSegment, from source: Int, to destination: Int, count: Int) throws { + mutating func initialize(_ segment: InternalElementSegment, from source: Int, to destination: Int, count: Int) throws(Trap) { try self.initialize(segment.references, from: source, to: destination, count: count) } - mutating func initialize(_ references: [Reference], from source: Int, to destination: Int, count: Int) throws { + mutating func initialize(_ references: [Reference], from source: Int, to destination: Int, count: Int) throws(Trap) { let (destinationEnd, destinationOverflow) = destination.addingReportingOverflow(count) let (sourceEnd, sourceOverflow) = source.addingReportingOverflow(count) @@ -345,7 +418,7 @@ struct TableEntity /* : ~Copyable */ { } } - mutating func fill(repeating value: Reference, from index: Int, count: Int) throws { + mutating func fill(repeating value: Reference, from index: Int, count: Int) throws(Trap) { let (end, overflow) = index.addingReportingOverflow(count) guard !overflow, end <= elements.count else { throw Trap(.tableOutOfBounds(end)) } @@ -358,7 +431,7 @@ struct TableEntity /* : ~Copyable */ { _ sourceTable: UnsafeBufferPointer, _ destinationTable: UnsafeMutableBufferPointer, from source: Int, to destination: Int, count: Int - ) throws { + ) throws(Trap) { let (destinationEnd, destinationOverflow) = destination.addingReportingOverflow(count) let (sourceEnd, sourceOverflow) = source.addingReportingOverflow(count) @@ -389,20 +462,20 @@ extension TableEntity: ValidatableEntity { typealias InternalTable = EntityHandle extension InternalTable { - func copy(_ sourceTable: InternalTable, from source: Int, to destination: Int, count: Int) throws { + func copy(_ sourceTable: InternalTable, from source: Int, to destination: Int, count: Int) throws(Trap) { // Check if the source and destination tables are the same for dynamic exclusive // access enforcement if self == sourceTable { - try withValue { - try $0.elements.withUnsafeMutableBufferPointer { - try TableEntity.copy(UnsafeBufferPointer($0), $0, from: source, to: destination, count: count) + try withValue { (t: inout TableEntity) throws(Trap) in + try t.elements.withUnsafeMutableBufferPointer { (elems: inout UnsafeMutableBufferPointer) throws(Trap) in + try TableEntity.copy(UnsafeBufferPointer(elems), elems, from: source, to: destination, count: count) } } } else { - try withValue { destinationTable in - try sourceTable.withValue { sourceTable in - try destinationTable.elements.withUnsafeMutableBufferPointer { dest in - try sourceTable.elements.withUnsafeBufferPointer { src in + try withValue { (destinationTable: inout TableEntity) throws(Trap) in + try sourceTable.withValue { (sourceTable: inout TableEntity) throws(Trap) in + try destinationTable.elements.withUnsafeMutableBufferPointer { (dest: inout UnsafeMutableBufferPointer) throws(Trap) in + try sourceTable.elements.withUnsafeBufferPointer { (src: UnsafeBufferPointer) throws(Trap) in try TableEntity.copy(src, dest, from: source, to: destination, count: count) } } @@ -443,7 +516,7 @@ public struct Table: Equatable { /// let imports: Imports = ["env": ["table": table]] /// let instance = try module.instantiate(store: store, imports: imports) /// ``` - public init(store: Store, type: TableType) throws { + public init(store: Store, type: TableType) throws(Trap) { self.init( handle: try store.allocator.allocate(tableType: type, resourceLimiter: store.resourceLimiter), allocator: store.allocator @@ -490,7 +563,7 @@ struct MemoryEntity: ~Copyable { var trapGuardReservationSize: Int { 0 } - mutating func grow(to newByteCount: Int) throws { + mutating func grow(to newByteCount: Int) throws(Trap) { let storage = UnsafeMutableBufferPointer.allocate(capacity: newByteCount) let oldStorage = self.buffer if newByteCount > 0 { storage.initialize(repeating: 0) } @@ -506,7 +579,7 @@ struct MemoryEntity: ~Copyable { } } - #if os(macOS) || os(Linux) + #if (os(macOS) || os(Linux)) && !$Embedded private enum Storage { case mprotect(MprotectLinearMemory) case malloc(MallocStorage) @@ -563,7 +636,7 @@ struct MemoryEntity: ~Copyable { } } - mutating func grow(to newByteCount: Int) throws { + mutating func grow(to newByteCount: Int) throws(Trap) { switch self { case .mprotect(var memory): try memory.grow(to: newByteCount) @@ -589,9 +662,11 @@ struct MemoryEntity: ~Copyable { private var storage: Storage let maxPageCount: UInt64 let limit: Limits + #if !$Embedded let sharedMutex: Mutex? + #endif - init(_ memoryType: MemoryType, engineConfiguration: EngineConfiguration, resourceLimiter: any ResourceLimiter) throws { + init(_ memoryType: MemoryType, engineConfiguration: EngineConfiguration, resourceLimiter: RL) throws(Trap) { let byteSize = Int(memoryType.min) * Self.pageSize guard try resourceLimiter.limitMemoryGrowth(to: byteSize) else { throw Trap(.initialMemorySizeExceedsLimit(byteSize: byteSize)) @@ -600,7 +675,9 @@ struct MemoryEntity: ~Copyable { let defaultMaxPageCount = Self.maxPageCount(isMemory64: memoryType.isMemory64) maxPageCount = memoryType.max ?? defaultMaxPageCount limit = memoryType + #if !$Embedded sharedMutex = memoryType.shared ? Mutex(()) : nil + #endif } deinit { @@ -619,7 +696,7 @@ struct MemoryEntity: ~Copyable { /// > Note: /// - mutating func grow(by pageCount: Int, resourceLimiter: any ResourceLimiter) throws -> Value { + mutating func grow(by pageCount: Int, resourceLimiter: RL) throws(Trap) -> Value { let currentByteCount = byteCount let newPageCount = currentByteCount / Self.pageSize + pageCount @@ -637,7 +714,7 @@ struct MemoryEntity: ~Copyable { return limit.isMemory64 ? .i64(UInt64(result)) : .i32(result) } - mutating func copy(from source: UInt64, to destination: UInt64, count: UInt64) throws { + mutating func copy(from source: UInt64, to destination: UInt64, count: UInt64) throws(Trap) { let (destinationEnd, destinationOverflow) = destination.addingReportingOverflow(count) let (sourceEnd, sourceOverflow) = source.addingReportingOverflow(count) @@ -663,7 +740,7 @@ struct MemoryEntity: ~Copyable { } } - mutating func initialize(_ segment: InternalDataSegment, from source: UInt32, to destination: UInt64, count: UInt32) throws { + mutating func initialize(_ segment: InternalDataSegment, from source: UInt32, to destination: UInt64, count: UInt32) throws(Trap) { let (destinationEnd, destinationOverflow) = destination.addingReportingOverflow(UInt64(count)) let (sourceEnd, sourceOverflow) = source.addingReportingOverflow(count) @@ -684,7 +761,7 @@ struct MemoryEntity: ~Copyable { } } - mutating func write(offset: Int, bytes: ArraySlice) throws { + mutating func write(offset: Int, bytes: ArraySlice) throws(Trap) { let endOffset = offset + bytes.count guard endOffset <= byteCount else { throw Trap(.memoryOutOfBounds) @@ -695,7 +772,7 @@ struct MemoryEntity: ~Copyable { } } - mutating func fill(offset: Int, value: UInt8, count: Int) throws { + mutating func fill(offset: Int, value: UInt8, count: Int) throws(Trap) { let endOffset = offset + count guard endOffset <= byteCount else { throw Trap(.memoryOutOfBounds) @@ -747,15 +824,23 @@ public struct Memory: Equatable { /// let imports: Imports = ["env": ["memory": memory]] /// let instance = try module.instantiate(store: store, imports: imports) /// ``` + #if !$Embedded public init(store: Store, type: MemoryType) throws { // Validate the memory type because the type is not validated at instantiation time. try ModuleValidator.checkMemoryType(type, features: store.engine.configuration.features) - self.init( handle: try store.allocator.allocate(memoryType: type, engineConfiguration: store.engine.configuration, resourceLimiter: store.resourceLimiter), allocator: store.allocator ) } + #else + public init(store: Store, type: MemoryType) throws(Trap) { + self.init( + handle: try store.allocator.allocate(memoryType: type, engineConfiguration: store.engine.configuration, resourceLimiter: store.resourceLimiter), + allocator: store.allocator + ) + } + #endif /// Returns a copy of the memory data. @available(*, deprecated, message: "Use `withUnsafeBufferPointer(offset:count:_:)` or `withUnsafeMutableBufferPointer(offset:count:_:)` instead") @@ -836,7 +921,7 @@ struct GlobalEntity /* : ~Copyable */ { } let globalType: GlobalType - init(globalType: GlobalType, initialValue: Value) throws { + init(globalType: GlobalType, initialValue: Value) throws(WasmKitError) { try initialValue.checkType(globalType.valueType) switch initialValue { case .v128(let v): @@ -872,12 +957,16 @@ public struct Global: Equatable { /// /// - Parameter value: The new value to assign. /// - Throws: `Trap` if the global is immutable. - public func assign(_ value: Value) throws { - try handle.withValue { global in + public func assign(_ value: Value) throws(Trap) { + try handle.withValue { (global: inout GlobalEntity) throws(Trap) in guard global.globalType.mutability == .variable else { throw Trap(.cannotAssignToImmutableGlobal) } - try value.checkType(global.globalType.valueType) + do throws(WasmKitError) { + try value.checkType(global.globalType.valueType) + } catch let e { + throw Trap(.message(TrapReason.Message("trap"))) + } global.value = value } } @@ -918,7 +1007,7 @@ public struct Global: Equatable { /// let imports: Imports = ["env": ["i32-global": i32Global]] /// let instance = try module.instantiate(store: store, imports: imports) /// ``` - public init(store: Store, type: GlobalType, value: Value) throws { + public init(store: Store, type: GlobalType, value: Value) throws(WasmKitError) { let handle = try store.allocator.allocate(globalType: type, initialValue: value) self.init(handle: handle, allocator: store.allocator) } @@ -1040,3 +1129,75 @@ enum InternalExternalValue { case global(InternalGlobal) case tag(InternalTag) } + +// MARK: - Explicit property accessors for Embedded Swift +// In embedded mode, @dynamicMemberLookup (which uses KeyPath) is not available. +// These extensions provide direct property access without key paths. +#if $Embedded +extension InternalInstance { + var types: [FunctionType] { withValue { $0.types } } + var functions: ImmutableArray { withValue { $0.functions } } + var tables: ImmutableArray { withValue { $0.tables } } + var memories: ImmutableArray { withValue { $0.memories } } + var globals: ImmutableArray { withValue { $0.globals } } + var tags: ImmutableArray { withValue { $0.tags } } + var elementSegments: ImmutableArray { withValue { $0.elementSegments } } + var dataSegments: ImmutableArray { withValue { $0.dataSegments } } + var exports: ExportsStorage { withValue { $0.exports } } + var functionRefs: Set { withValue { $0.functionRefs } } + var features: WasmFeatureSet { withValue { $0.features } } + // dataCount is defined in Translator.swift extension — no redeclaration needed + var isDebuggable: Bool { withValue { $0.isDebuggable } } +} + +extension InternalTable { + var elements: [Reference] { withValue { $0.elements } } + var tableType: TableType { withValue { $0.tableType } } + var limits: Limits { withValue { $0.limits } } +} + +extension InternalMemory { + var limit: Limits { withValue { $0.limit } } + var maxPageCount: UInt64 { withValue { $0.maxPageCount } } + var byteCount: Int { withValue { $0.byteCount } } + var data: UnsafeBufferPointer { withValue { $0.data } } + var baseAddress: UnsafeMutableRawPointer? { withValue { $0.baseAddress } } +} + +extension InternalGlobal { + var value: Value { withValue { $0.value } } + var globalType: GlobalType { withValue { $0.globalType } } +} + +extension InternalElementSegment { + var type: ReferenceType { withValue { $0.type } } + var references: [Reference] { withValue { $0.references } } +} + +extension InternalDataSegment { + var data: ArraySlice { withValue { $0.data } } +} + +extension EntityHandle { + var type: InternedFuncType { withValue { $0.type } } +} + +extension EntityHandle { + var type: InternedFuncType { withValue { $0.type } } + var implementation: Function.Implementation { withValue { $0.implementation } } +} + +extension InternalUncompiledCode { + var locals: [ValueType] { withValue { $0.locals } } + var expression: ArraySlice { withValue { $0.expression } } + #if WasmDebuggingSupport + var originalAddress: Int { withValue { $0.originalAddress } } + #endif +} + +extension InternalInstance { + #if WasmDebuggingSupport + var instructionMapping: DebuggerInstructionMapping { withValue { $0.instructionMapping } } + #endif +} +#endif // $Embedded diff --git a/Sources/WasmKit/Execution/Instructions/Control.swift b/Sources/WasmKit/Execution/Instructions/Control.swift index d0f5448c..37cd08bf 100644 --- a/Sources/WasmKit/Execution/Instructions/Control.swift +++ b/Sources/WasmKit/Execution/Instructions/Control.swift @@ -1,7 +1,7 @@ /// > Note: /// extension Execution { - func unreachable(sp: Sp, pc: Pc) throws -> (Pc, CodeSlot) { + func unreachable(sp: Sp, pc: Pc) throws(Trap) -> (Pc, CodeSlot) { throw Trap(.unreachable) } mutating func nop(sp: Sp) { @@ -51,12 +51,12 @@ extension Execution { return pc.next() } - mutating func endOfExecution(sp: inout Sp, pc: Pc) throws -> (Pc, CodeSlot) { + mutating func endOfExecution(sp: inout Sp, pc: Pc) throws(EndOfExecution) -> (Pc, CodeSlot) { throw EndOfExecution(sp: sp) } @inline(__always) - mutating func call(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.CallOperand) throws -> (Pc, CodeSlot) { + mutating func call(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.CallOperand) throws(Trap) -> (Pc, CodeSlot) { var pc = pc (pc, sp) = try invoke( @@ -74,7 +74,7 @@ extension Execution { pc: inout Pc, callee: InternalFunction, internalCallOperand: Instruction.CallOperand - ) throws { + ) throws(Trap) { // The callee is known to be a function defined within the same module, so we can // skip updating the current instance. let (iseq, locals, instance) = internalCallOperand.callee.assumeCompiled() @@ -89,7 +89,7 @@ extension Execution { } @inline(__always) - mutating func internalCall(sp: inout Sp, pc: Pc, immediate: Instruction.CallOperand) throws -> (Pc, CodeSlot) { + mutating func internalCall(sp: inout Sp, pc: Pc, immediate: Instruction.CallOperand) throws(Trap) -> (Pc, CodeSlot) { var pc = pc let callee = immediate.callee try _internalCall(sp: &sp, pc: &pc, callee: callee, internalCallOperand: immediate) @@ -97,7 +97,7 @@ extension Execution { } @inline(__always) - mutating func compilingCall(sp: inout Sp, pc: Pc, immediate: Instruction.CallOperand) throws -> (Pc, CodeSlot) { + mutating func compilingCall(sp: inout Sp, pc: Pc, immediate: Instruction.CallOperand) throws(Trap) -> (Pc, CodeSlot) { var pc = pc // NOTE: `CompilingCallOperand` consumes 2 slots, discriminator is at -3 let headSlotPc = pc.advanced(by: -3) @@ -113,7 +113,7 @@ extension Execution { private func prepareForIndirectCall( sp: Sp, tableIndex: TableIndex, expectedType: InternedFuncType, address: VReg - ) throws -> (InternalFunction, InternalInstance) { + ) throws(Trap) -> (InternalFunction, InternalInstance) { let callerInstance = currentInstance(sp: sp) let table = callerInstance.tables[Int(tableIndex)] let value = sp[address].asAddressOffset(table.limits.isMemory64) @@ -137,7 +137,7 @@ extension Execution { } @inline(__always) - mutating func callIndirect(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.CallIndirectOperand) throws -> (Pc, CodeSlot) { + mutating func callIndirect(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.CallIndirectOperand) throws(Trap) -> (Pc, CodeSlot) { var pc = pc let (function, callerInstance) = try prepareForIndirectCall( sp: sp, tableIndex: immediate.tableIndex, expectedType: immediate.type, @@ -152,7 +152,7 @@ extension Execution { return pc.next() } - mutating func returnCall(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.ReturnCallOperand) throws -> (Pc, CodeSlot) { + mutating func returnCall(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.ReturnCallOperand) throws(Trap) -> (Pc, CodeSlot) { var pc = pc (pc, sp) = try tailInvoke( function: immediate.callee, @@ -162,7 +162,7 @@ extension Execution { return pc.next() } - mutating func returnCallIndirect(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.ReturnCallIndirectOperand) throws -> (Pc, CodeSlot) { + mutating func returnCallIndirect(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.ReturnCallIndirectOperand) throws(Trap) -> (Pc, CodeSlot) { var pc = pc let (function, callerInstance) = try prepareForIndirectCall( sp: sp, tableIndex: immediate.tableIndex, expectedType: immediate.type, @@ -176,7 +176,7 @@ extension Execution { return pc.next() } - mutating func resizeFrameHeader(sp: inout Sp, immediate: Instruction.ResizeFrameHeaderOperand) throws { + mutating func resizeFrameHeader(sp: inout Sp, immediate: Instruction.ResizeFrameHeaderOperand) throws(Trap) { // The params/results space are resized by `delta` slots and the rest of the // frame is copied to the new location. See the following diagram for the // layout of the frame before and after the resize operation: @@ -212,19 +212,23 @@ extension Execution { } mutating func onEnter(sp: Sp, immediate: Instruction.OnEnterOperand) { + #if !$Embedded let function = currentInstance(sp: sp).functions[Int(immediate)] self.store.value.engine.interceptor?.onEnterFunction( Function(handle: function, store: store.value) ) + #endif } mutating func onExit(sp: Sp, immediate: Instruction.OnExitOperand) { + #if !$Embedded let function = currentInstance(sp: sp).functions[Int(immediate)] self.store.value.engine.interceptor?.onExitFunction( Function(handle: function, store: store.value) ) + #endif } - mutating func breakpoint(sp: inout Sp, pc: Pc) throws -> (Pc, CodeSlot) { + mutating func breakpoint(sp: inout Sp, pc: Pc) throws(Breakpoint) -> (Pc, CodeSlot) { throw Breakpoint( sp: sp, // Throw `pc` value before the breakpoint was triggered to allow resumption in same place diff --git a/Sources/WasmKit/Execution/Instructions/ExceptionHandling.swift b/Sources/WasmKit/Execution/Instructions/ExceptionHandling.swift index 25e2e99c..bf281a08 100644 --- a/Sources/WasmKit/Execution/Instructions/ExceptionHandling.swift +++ b/Sources/WasmKit/Execution/Instructions/ExceptionHandling.swift @@ -1,5 +1,10 @@ /// > Note: /// +// Exception handling throws WasmKitException (dynamic error) which is not +// supported in embedded Swift. +#if !$Embedded +import WasmParserCore + extension Execution { /// Throw a new exception with the given tag. @@ -131,3 +136,4 @@ extension Execution { return storedExceptions[address] } } +#endif // !$Embedded diff --git a/Sources/WasmKit/Execution/Instructions/Instruction.swift b/Sources/WasmKit/Execution/Instructions/Instruction.swift index 1a9d2c68..ad97a182 100644 --- a/Sources/WasmKit/Execution/Instructions/Instruction.swift +++ b/Sources/WasmKit/Execution/Instructions/Instruction.swift @@ -1203,6 +1203,7 @@ extension Instruction { } extension Instruction { + #if !$Embedded var rawImmediate: (any InstructionImmediate)? { switch self { case .copyStack(let immediate): return immediate @@ -1476,7 +1477,283 @@ extension Instruction { default: return nil } } -} + #endif // !$Embedded + + /// Emit the immediate slots for this instruction without using existentials. + /// This is the embedded-compatible version of rawImmediate. + func emitImmediate(to emit: @escaping (CodeSlot) -> Void) { + switch self { + case .copyStack(let immediate): immediate.emit(to: emit) + case .globalGet(let immediate): immediate.emit(to: emit) + case .globalSet(let immediate): immediate.emit(to: emit) + case .call(let immediate): immediate.emit(to: emit) + case .compilingCall(let immediate): immediate.emit(to: emit) + case .internalCall(let immediate): immediate.emit(to: emit) + case .callIndirect(let immediate): immediate.emit(to: emit) + case .resizeFrameHeader(let immediate): immediate.emit(to: emit) + case .returnCall(let immediate): immediate.emit(to: emit) + case .returnCallIndirect(let immediate): immediate.emit(to: emit) + case .br(let immediate): immediate.emit(to: emit) + case .brIf(let immediate): immediate.emit(to: emit) + case .brIfNot(let immediate): immediate.emit(to: emit) + case .brTable(let immediate): immediate.emit(to: emit) + case .i32Load(let immediate): immediate.emit(to: emit) + case .i64Load(let immediate): immediate.emit(to: emit) + case .f32Load(let immediate): immediate.emit(to: emit) + case .f64Load(let immediate): immediate.emit(to: emit) + case .i32Load8S(let immediate): immediate.emit(to: emit) + case .i32Load8U(let immediate): immediate.emit(to: emit) + case .i32Load16S(let immediate): immediate.emit(to: emit) + case .i32Load16U(let immediate): immediate.emit(to: emit) + case .i64Load8S(let immediate): immediate.emit(to: emit) + case .i64Load8U(let immediate): immediate.emit(to: emit) + case .i64Load16S(let immediate): immediate.emit(to: emit) + case .i64Load16U(let immediate): immediate.emit(to: emit) + case .i64Load32S(let immediate): immediate.emit(to: emit) + case .i64Load32U(let immediate): immediate.emit(to: emit) + case .i32Store(let immediate): immediate.emit(to: emit) + case .i64Store(let immediate): immediate.emit(to: emit) + case .f32Store(let immediate): immediate.emit(to: emit) + case .f64Store(let immediate): immediate.emit(to: emit) + case .i32Store8(let immediate): immediate.emit(to: emit) + case .i32Store16(let immediate): immediate.emit(to: emit) + case .i64Store8(let immediate): immediate.emit(to: emit) + case .i64Store16(let immediate): immediate.emit(to: emit) + case .i64Store32(let immediate): immediate.emit(to: emit) + case .memorySize(let immediate): immediate.emit(to: emit) + case .memoryGrow(let immediate): immediate.emit(to: emit) + case .memoryInit(let immediate): immediate.emit(to: emit) + case .memoryDataDrop(let immediate): immediate.emit(to: emit) + case .memoryCopy(let immediate): immediate.emit(to: emit) + case .memoryFill(let immediate): immediate.emit(to: emit) + case .v128Const(let immediate): immediate.emit(to: emit) + case .i8x16Shuffle(let immediate): immediate.emit(to: emit) + case .simd(let immediate): immediate.emit(to: emit) + case .const32(let immediate): immediate.emit(to: emit) + case .const64(let immediate): immediate.emit(to: emit) + case .i32Add(let immediate): immediate.emit(to: emit) + case .i64Add(let immediate): immediate.emit(to: emit) + case .i32Sub(let immediate): immediate.emit(to: emit) + case .i64Sub(let immediate): immediate.emit(to: emit) + case .i32Mul(let immediate): immediate.emit(to: emit) + case .i64Mul(let immediate): immediate.emit(to: emit) + case .i32And(let immediate): immediate.emit(to: emit) + case .i64And(let immediate): immediate.emit(to: emit) + case .i32Or(let immediate): immediate.emit(to: emit) + case .i64Or(let immediate): immediate.emit(to: emit) + case .i32Xor(let immediate): immediate.emit(to: emit) + case .i64Xor(let immediate): immediate.emit(to: emit) + case .i32Shl(let immediate): immediate.emit(to: emit) + case .i64Shl(let immediate): immediate.emit(to: emit) + case .i32ShrS(let immediate): immediate.emit(to: emit) + case .i64ShrS(let immediate): immediate.emit(to: emit) + case .i32ShrU(let immediate): immediate.emit(to: emit) + case .i64ShrU(let immediate): immediate.emit(to: emit) + case .i32Rotl(let immediate): immediate.emit(to: emit) + case .i64Rotl(let immediate): immediate.emit(to: emit) + case .i32Rotr(let immediate): immediate.emit(to: emit) + case .i64Rotr(let immediate): immediate.emit(to: emit) + case .i32DivS(let immediate): immediate.emit(to: emit) + case .i64DivS(let immediate): immediate.emit(to: emit) + case .i32DivU(let immediate): immediate.emit(to: emit) + case .i64DivU(let immediate): immediate.emit(to: emit) + case .i32RemS(let immediate): immediate.emit(to: emit) + case .i64RemS(let immediate): immediate.emit(to: emit) + case .i32RemU(let immediate): immediate.emit(to: emit) + case .i64RemU(let immediate): immediate.emit(to: emit) + case .i32Eq(let immediate): immediate.emit(to: emit) + case .i64Eq(let immediate): immediate.emit(to: emit) + case .i32Ne(let immediate): immediate.emit(to: emit) + case .i64Ne(let immediate): immediate.emit(to: emit) + case .i32LtS(let immediate): immediate.emit(to: emit) + case .i64LtS(let immediate): immediate.emit(to: emit) + case .i32LtU(let immediate): immediate.emit(to: emit) + case .i64LtU(let immediate): immediate.emit(to: emit) + case .i32GtS(let immediate): immediate.emit(to: emit) + case .i64GtS(let immediate): immediate.emit(to: emit) + case .i32GtU(let immediate): immediate.emit(to: emit) + case .i64GtU(let immediate): immediate.emit(to: emit) + case .i32LeS(let immediate): immediate.emit(to: emit) + case .i64LeS(let immediate): immediate.emit(to: emit) + case .i32LeU(let immediate): immediate.emit(to: emit) + case .i64LeU(let immediate): immediate.emit(to: emit) + case .i32GeS(let immediate): immediate.emit(to: emit) + case .i64GeS(let immediate): immediate.emit(to: emit) + case .i32GeU(let immediate): immediate.emit(to: emit) + case .i64GeU(let immediate): immediate.emit(to: emit) + case .i32Clz(let immediate): immediate.emit(to: emit) + case .i64Clz(let immediate): immediate.emit(to: emit) + case .i32Ctz(let immediate): immediate.emit(to: emit) + case .i64Ctz(let immediate): immediate.emit(to: emit) + case .i32Popcnt(let immediate): immediate.emit(to: emit) + case .i64Popcnt(let immediate): immediate.emit(to: emit) + case .i32Eqz(let immediate): immediate.emit(to: emit) + case .i64Eqz(let immediate): immediate.emit(to: emit) + case .i32WrapI64(let immediate): immediate.emit(to: emit) + case .i64ExtendI32S(let immediate): immediate.emit(to: emit) + case .i64ExtendI32U(let immediate): immediate.emit(to: emit) + case .i32Extend8S(let immediate): immediate.emit(to: emit) + case .i64Extend8S(let immediate): immediate.emit(to: emit) + case .i32Extend16S(let immediate): immediate.emit(to: emit) + case .i64Extend16S(let immediate): immediate.emit(to: emit) + case .i64Extend32S(let immediate): immediate.emit(to: emit) + case .i32TruncF32S(let immediate): immediate.emit(to: emit) + case .i32TruncF32U(let immediate): immediate.emit(to: emit) + case .i32TruncSatF32S(let immediate): immediate.emit(to: emit) + case .i32TruncSatF32U(let immediate): immediate.emit(to: emit) + case .i32TruncF64S(let immediate): immediate.emit(to: emit) + case .i32TruncF64U(let immediate): immediate.emit(to: emit) + case .i32TruncSatF64S(let immediate): immediate.emit(to: emit) + case .i32TruncSatF64U(let immediate): immediate.emit(to: emit) + case .i64TruncF32S(let immediate): immediate.emit(to: emit) + case .i64TruncF32U(let immediate): immediate.emit(to: emit) + case .i64TruncSatF32S(let immediate): immediate.emit(to: emit) + case .i64TruncSatF32U(let immediate): immediate.emit(to: emit) + case .i64TruncF64S(let immediate): immediate.emit(to: emit) + case .i64TruncF64U(let immediate): immediate.emit(to: emit) + case .i64TruncSatF64S(let immediate): immediate.emit(to: emit) + case .i64TruncSatF64U(let immediate): immediate.emit(to: emit) + case .f32ConvertI32S(let immediate): immediate.emit(to: emit) + case .f32ConvertI32U(let immediate): immediate.emit(to: emit) + case .f32ConvertI64S(let immediate): immediate.emit(to: emit) + case .f32ConvertI64U(let immediate): immediate.emit(to: emit) + case .f64ConvertI32S(let immediate): immediate.emit(to: emit) + case .f64ConvertI32U(let immediate): immediate.emit(to: emit) + case .f64ConvertI64S(let immediate): immediate.emit(to: emit) + case .f64ConvertI64U(let immediate): immediate.emit(to: emit) + case .f32ReinterpretI32(let immediate): immediate.emit(to: emit) + case .f64ReinterpretI64(let immediate): immediate.emit(to: emit) + case .i32ReinterpretF32(let immediate): immediate.emit(to: emit) + case .i64ReinterpretF64(let immediate): immediate.emit(to: emit) + case .f32Add(let immediate): immediate.emit(to: emit) + case .f64Add(let immediate): immediate.emit(to: emit) + case .f32Sub(let immediate): immediate.emit(to: emit) + case .f64Sub(let immediate): immediate.emit(to: emit) + case .f32Mul(let immediate): immediate.emit(to: emit) + case .f64Mul(let immediate): immediate.emit(to: emit) + case .f32Div(let immediate): immediate.emit(to: emit) + case .f64Div(let immediate): immediate.emit(to: emit) + case .f32Min(let immediate): immediate.emit(to: emit) + case .f64Min(let immediate): immediate.emit(to: emit) + case .f32Max(let immediate): immediate.emit(to: emit) + case .f64Max(let immediate): immediate.emit(to: emit) + case .f32CopySign(let immediate): immediate.emit(to: emit) + case .f64CopySign(let immediate): immediate.emit(to: emit) + case .f32Eq(let immediate): immediate.emit(to: emit) + case .f64Eq(let immediate): immediate.emit(to: emit) + case .f32Ne(let immediate): immediate.emit(to: emit) + case .f64Ne(let immediate): immediate.emit(to: emit) + case .f32Lt(let immediate): immediate.emit(to: emit) + case .f64Lt(let immediate): immediate.emit(to: emit) + case .f32Gt(let immediate): immediate.emit(to: emit) + case .f64Gt(let immediate): immediate.emit(to: emit) + case .f32Le(let immediate): immediate.emit(to: emit) + case .f64Le(let immediate): immediate.emit(to: emit) + case .f32Ge(let immediate): immediate.emit(to: emit) + case .f64Ge(let immediate): immediate.emit(to: emit) + case .f32Abs(let immediate): immediate.emit(to: emit) + case .f64Abs(let immediate): immediate.emit(to: emit) + case .f32Neg(let immediate): immediate.emit(to: emit) + case .f64Neg(let immediate): immediate.emit(to: emit) + case .f32Ceil(let immediate): immediate.emit(to: emit) + case .f64Ceil(let immediate): immediate.emit(to: emit) + case .f32Floor(let immediate): immediate.emit(to: emit) + case .f64Floor(let immediate): immediate.emit(to: emit) + case .f32Trunc(let immediate): immediate.emit(to: emit) + case .f64Trunc(let immediate): immediate.emit(to: emit) + case .f32Nearest(let immediate): immediate.emit(to: emit) + case .f64Nearest(let immediate): immediate.emit(to: emit) + case .f32Sqrt(let immediate): immediate.emit(to: emit) + case .f64Sqrt(let immediate): immediate.emit(to: emit) + case .f64PromoteF32(let immediate): immediate.emit(to: emit) + case .f32DemoteF64(let immediate): immediate.emit(to: emit) + case .select(let immediate): immediate.emit(to: emit) + case .refNull(let immediate): immediate.emit(to: emit) + case .refIsNull(let immediate): immediate.emit(to: emit) + case .refFunc(let immediate): immediate.emit(to: emit) + case .tableGet(let immediate): immediate.emit(to: emit) + case .tableSet(let immediate): immediate.emit(to: emit) + case .tableSize(let immediate): immediate.emit(to: emit) + case .tableGrow(let immediate): immediate.emit(to: emit) + case .tableFill(let immediate): immediate.emit(to: emit) + case .tableCopy(let immediate): immediate.emit(to: emit) + case .tableInit(let immediate): immediate.emit(to: emit) + case .tableElementDrop(let immediate): immediate.emit(to: emit) + case .onEnter(let immediate): immediate.emit(to: emit) + case .onExit(let immediate): immediate.emit(to: emit) + case .i32AtomicLoad(let immediate): immediate.emit(to: emit) + case .i64AtomicLoad(let immediate): immediate.emit(to: emit) + case .i32AtomicLoad8U(let immediate): immediate.emit(to: emit) + case .i32AtomicLoad16U(let immediate): immediate.emit(to: emit) + case .i64AtomicLoad8U(let immediate): immediate.emit(to: emit) + case .i64AtomicLoad16U(let immediate): immediate.emit(to: emit) + case .i64AtomicLoad32U(let immediate): immediate.emit(to: emit) + case .i32AtomicStore(let immediate): immediate.emit(to: emit) + case .i64AtomicStore(let immediate): immediate.emit(to: emit) + case .i32AtomicStore8(let immediate): immediate.emit(to: emit) + case .i32AtomicStore16(let immediate): immediate.emit(to: emit) + case .i64AtomicStore8(let immediate): immediate.emit(to: emit) + case .i64AtomicStore16(let immediate): immediate.emit(to: emit) + case .i64AtomicStore32(let immediate): immediate.emit(to: emit) + case .i32AtomicRmwAdd(let immediate): immediate.emit(to: emit) + case .i64AtomicRmwAdd(let immediate): immediate.emit(to: emit) + case .i32AtomicRmwSub(let immediate): immediate.emit(to: emit) + case .i64AtomicRmwSub(let immediate): immediate.emit(to: emit) + case .i32AtomicRmwAnd(let immediate): immediate.emit(to: emit) + case .i64AtomicRmwAnd(let immediate): immediate.emit(to: emit) + case .i32AtomicRmwOr(let immediate): immediate.emit(to: emit) + case .i64AtomicRmwOr(let immediate): immediate.emit(to: emit) + case .i32AtomicRmwXor(let immediate): immediate.emit(to: emit) + case .i64AtomicRmwXor(let immediate): immediate.emit(to: emit) + case .i32AtomicRmwXchg(let immediate): immediate.emit(to: emit) + case .i64AtomicRmwXchg(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw8AddU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw8AddU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw8SubU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw8SubU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw8AndU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw8AndU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw8OrU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw8OrU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw8XorU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw8XorU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw8XchgU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw8XchgU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw16AddU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw16AddU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw16SubU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw16SubU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw16AndU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw16AndU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw16OrU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw16OrU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw16XorU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw16XorU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw16XchgU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw16XchgU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw32AddU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw32SubU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw32AndU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw32OrU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw32XorU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw32XchgU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmwCmpxchg(let immediate): immediate.emit(to: emit) + case .i64AtomicRmwCmpxchg(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw8CmpxchgU(let immediate): immediate.emit(to: emit) + case .i32AtomicRmw16CmpxchgU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw8CmpxchgU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw16CmpxchgU(let immediate): immediate.emit(to: emit) + case .i64AtomicRmw32CmpxchgU(let immediate): immediate.emit(to: emit) + case .memoryAtomicWait32(let immediate): immediate.emit(to: emit) + case .memoryAtomicWait64(let immediate): immediate.emit(to: emit) + case .memoryAtomicNotify(let immediate): immediate.emit(to: emit) + case .throwTag(let immediate): immediate.emit(to: emit) + case .throwRef(let immediate): immediate.emit(to: emit) + case .catchHandlers(let immediate): immediate.emit(to: emit) + case .catchHandlersEnd(let immediate): immediate.emit(to: emit) + default: break + } + }} extension Instruction { diff --git a/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift b/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift index 6bca9a67..462080b5 100644 --- a/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift +++ b/Sources/WasmKit/Execution/Instructions/InstructionSupport.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore /// A register that is used to store a value in the stack. typealias VReg = Int16 @@ -453,7 +453,9 @@ struct InstructionPrintingContext { case ._return: target.write("return") default: + #if !$Embedded target.write(String(describing: instruction)) + #endif } } } diff --git a/Sources/WasmKit/Execution/Instructions/Memory.swift b/Sources/WasmKit/Execution/Instructions/Memory.swift index c191fe81..1212768b 100644 --- a/Sources/WasmKit/Execution/Instructions/Memory.swift +++ b/Sources/WasmKit/Execution/Instructions/Memory.swift @@ -1,18 +1,18 @@ -import WasmParser /// > Note: /// import _CWasmKit +import WasmParserCore extension Execution { - @inline(never) func throwOutOfBoundsMemoryAccess() throws -> Never { + @inline(never) func throwOutOfBoundsMemoryAccess() throws(Trap) -> Never { throw Trap(.memoryOutOfBounds) } - @inline(never) func throwUnalignedAtomicAccess() throws -> Never { + @inline(never) func throwUnalignedAtomicAccess() throws(Trap) -> Never { throw Trap(.unalignedAtomic) } mutating func memoryLoad( sp: Sp, md: Md, ms: Ms, loadOperand: Instruction.LoadOperand, loadAs _: T.Type = T.self, castToValue: (T) -> UntypedValue - ) throws { + ) throws(Trap) { let length = UInt64(T.bitWidth) / 8 let i = sp[loadOperand.pointer].asAddressOffset() let (endAddress, isEndOverflow) = i.addingReportingOverflow(length &+ loadOperand.offset) @@ -26,7 +26,7 @@ extension Execution { } /// `[type].store[bitWidth]` - mutating func memoryStore(sp: Sp, md: Md, ms: Ms, storeOperand: Instruction.StoreOperand, castFromValue: (UntypedValue) -> T) throws { + mutating func memoryStore(sp: Sp, md: Md, ms: Ms, storeOperand: Instruction.StoreOperand, castFromValue: (UntypedValue) -> T) throws(Trap) { let value = sp[storeOperand.value] let length = UInt64(T.bitWidth) / 8 let i = sp[storeOperand.pointer].asAddressOffset() @@ -51,9 +51,9 @@ extension Execution { } } - mutating func memoryGrow(sp: Sp, md: inout Md, ms: inout Ms, immediate: Instruction.MemoryGrowOperand) throws { + mutating func memoryGrow(sp: Sp, md: inout Md, ms: inout Ms, immediate: Instruction.MemoryGrowOperand) throws(Trap) { let memory = currentInstance(sp: sp).memories[Int(immediate.memory)] - try memory.withValue { memory in + try memory.withValue { (memory: inout MemoryEntity) throws(Trap) -> Void in let isMemory64 = memory.limit.isMemory64 let value = sp[immediate.delta] @@ -63,10 +63,10 @@ extension Execution { sp[immediate.result] = UntypedValue(oldPageCount) } } - mutating func memoryInit(sp: Sp, immediate: Instruction.MemoryInitOperand) throws { + mutating func memoryInit(sp: Sp, immediate: Instruction.MemoryInitOperand) throws(Trap) { let instance = currentInstance(sp: sp) let memory = instance.memories[0] - try memory.withValue { memory in + try memory.withValue { (memory: inout MemoryEntity) throws(Trap) -> Void in let segment = instance.dataSegments[Int(immediate.segmentIndex)] let size = sp[immediate.size].i32 @@ -79,9 +79,9 @@ extension Execution { let segment = currentInstance(sp: sp).dataSegments[Int(immediate.segmentIndex)] segment.withValue { $0.drop() } } - mutating func memoryCopy(sp: Sp, immediate: Instruction.MemoryCopyOperand) throws { + mutating func memoryCopy(sp: Sp, immediate: Instruction.MemoryCopyOperand) throws(Trap) { let memory = currentInstance(sp: sp).memories[0] - try memory.withValue { memory in + try memory.withValue { (memory: inout MemoryEntity) throws(Trap) -> Void in let isMemory64 = memory.limit.isMemory64 let size = sp[immediate.size].asAddressOffset(isMemory64) let source = sp[immediate.sourceOffset].asAddressOffset(isMemory64) @@ -89,9 +89,9 @@ extension Execution { try memory.copy(from: source, to: destination, count: size) } } - mutating func memoryFill(sp: Sp, immediate: Instruction.MemoryFillOperand) throws { + mutating func memoryFill(sp: Sp, immediate: Instruction.MemoryFillOperand) throws(Trap) { let memory = currentInstance(sp: sp).memories[0] - try memory.withValue { memoryInstance in + try memory.withValue { (memoryInstance: inout MemoryEntity) throws(Trap) -> Void in let isMemory64 = memoryInstance.limit.isMemory64 let copyCounter = Int(sp[immediate.size].asAddressOffset(isMemory64)) let value = sp[immediate.value].i32 @@ -109,7 +109,7 @@ extension Execution { /// Atomic load operation mutating func atomicLoad( sp: Sp, md: Md, ms: Ms, loadOperand: Instruction.LoadOperand, loadAs _: T.Type = T.self, castToValue: (T) -> UntypedValue - ) throws { + ) throws(Trap) { let length = UInt64(T.bitWidth) / 8 let i = sp[loadOperand.pointer].asAddressOffset() let address = loadOperand.offset + i @@ -137,7 +137,7 @@ extension Execution { /// Atomic store operation mutating func atomicStore( sp: Sp, md: Md, ms: Ms, storeOperand: Instruction.StoreOperand, castFromValue: (UntypedValue) -> T - ) throws { + ) throws(Trap) { let value = sp[storeOperand.value] let length = UInt64(T.bitWidth) / 8 let i = sp[storeOperand.pointer].asAddressOffset() @@ -171,7 +171,7 @@ extension Execution { atomicOp: (UnsafeMutableRawPointer, T) -> T, castFromValue: (UntypedValue) -> T, castToValue: (T) -> UntypedValue - ) throws { + ) throws(Trap) { let length = UInt64(T.bitWidth) / 8 let i = sp[rmwOperand.pointer].asAddressOffset() let address = rmwOperand.offset + i @@ -197,7 +197,7 @@ extension Execution { atomicCmpxchg: (UnsafeMutableRawPointer, T, T) -> T, castFromValue: (UntypedValue) -> T, castToValue: (T) -> UntypedValue - ) throws { + ) throws(Trap) { let length = UInt64(T.bitWidth) / 8 let i = sp[cmpxchgOperand.pointer].asAddressOffset() let address = cmpxchgOperand.offset + i @@ -219,6 +219,7 @@ extension Execution { // MARK: - Atomic Wait/Notify + #if !$Embedded /// Atomic wait32 - wait for a value to change at an address mutating func atomicWait32(sp: Sp, md: Md, ms: Ms, waitOperand: Instruction.AtomicWaitOperand) throws { let i = sp[waitOperand.pointer].asAddressOffset() @@ -352,6 +353,8 @@ extension Execution { } } + #endif // !$Embedded + /// Atomic fence - sequential consistency barrier mutating func atomicFence(sp: Sp) { wasmkit_atomic_fence() diff --git a/Sources/WasmKit/Execution/Instructions/Misc.swift b/Sources/WasmKit/Execution/Instructions/Misc.swift index e8310fe8..2c41fee1 100644 --- a/Sources/WasmKit/Execution/Instructions/Misc.swift +++ b/Sources/WasmKit/Execution/Instructions/Misc.swift @@ -1,5 +1,7 @@ /// > Note: /// +import WasmParserCore + extension Execution { mutating func globalGet(sp: Sp, immediate: Instruction.GlobalAndVRegOperand) { immediate.global.withValue { diff --git a/Sources/WasmKit/Execution/Instructions/SIMDCore.swift b/Sources/WasmKit/Execution/Instructions/SIMDCore.swift index 3c1dea7f..2f6c821d 100644 --- a/Sources/WasmKit/Execution/Instructions/SIMDCore.swift +++ b/Sources/WasmKit/Execution/Instructions/SIMDCore.swift @@ -29,7 +29,7 @@ extension Execution { sp.storeV128(V128Lanes.pack(out, widthBits: 8, laneCount: 16), at: immediate.result) } - mutating func simd(sp: Sp, md: Md, ms: Ms, immediate: Instruction.SimdOperand) throws { + mutating func simd(sp: Sp, md: Md, ms: Ms, immediate: Instruction.SimdOperand) throws(Trap) { guard let opcode = SIMDOpcode(rawValue: immediate.opcode) else { preconditionFailure("Unknown SIMD opcode: \(immediate.opcode)") } diff --git a/Sources/WasmKit/Execution/Instructions/SIMDMemoryAndLane.swift b/Sources/WasmKit/Execution/Instructions/SIMDMemoryAndLane.swift index 721df8a4..b785ad25 100644 --- a/Sources/WasmKit/Execution/Instructions/SIMDMemoryAndLane.swift +++ b/Sources/WasmKit/Execution/Instructions/SIMDMemoryAndLane.swift @@ -2,7 +2,7 @@ import WasmTypes extension Execution { @inline(__always) - private func boundsCheck(_ start: UInt64, length: UInt64, ms: Ms) throws { + private func boundsCheck(_ start: UInt64, length: UInt64, ms: Ms) throws(Trap) { let (end, overflow) = start.addingReportingOverflow(length) if _fastPath(!overflow && end <= UInt64(ms)) { return } try throwOutOfBoundsMemoryAccess() @@ -34,7 +34,7 @@ extension Execution { md: Md, ms: Ms, immediate: Instruction.SimdOperand - ) throws -> Bool { + ) throws(Trap) -> Bool { @inline(__always) func storeI32(_ value: UInt32) { sp[immediate.result] = UntypedValue.i32(value) } @inline(__always) diff --git a/Sources/WasmKit/Execution/Instructions/SIMDNumeric.swift b/Sources/WasmKit/Execution/Instructions/SIMDNumeric.swift index 79dbbfb3..3d646ccc 100644 --- a/Sources/WasmKit/Execution/Instructions/SIMDNumeric.swift +++ b/Sources/WasmKit/Execution/Instructions/SIMDNumeric.swift @@ -37,7 +37,7 @@ extension Execution { opcode: SIMDOpcode, sp: Sp, immediate: Instruction.SimdOperand - ) throws -> Bool { + ) throws(Trap) -> Bool { @inline(__always) func v128Unary(_ body: (V128Storage) throws -> V128Storage) rethrows { let v0 = sp.loadV128(at: immediate.input0) diff --git a/Sources/WasmKit/Execution/Instructions/Table.swift b/Sources/WasmKit/Execution/Instructions/Table.swift index b1ab63de..eeeb2152 100644 --- a/Sources/WasmKit/Execution/Instructions/Table.swift +++ b/Sources/WasmKit/Execution/Instructions/Table.swift @@ -1,10 +1,10 @@ /// > Note: /// -import WasmParser +import WasmParserCore extension Execution { - mutating func tableGet(sp: Sp, immediate: Instruction.TableGetOperand) throws { + mutating func tableGet(sp: Sp, immediate: Instruction.TableGetOperand) throws(Trap) { let table = getTable(immediate.tableIndex, sp: sp, store: store.value) let elementIndex = try getElementIndex(sp: sp, VReg(immediate.index), table) @@ -12,7 +12,7 @@ extension Execution { let reference = table.elements[Int(elementIndex)] sp[immediate.result] = UntypedValue(.ref(reference)) } - mutating func tableSet(sp: Sp, immediate: Instruction.TableSetOperand) throws { + mutating func tableSet(sp: Sp, immediate: Instruction.TableSetOperand) throws(Trap) { let table = getTable(immediate.tableIndex, sp: sp, store: store.value) let reference = sp.getReference(VReg(immediate.value), type: table.tableType) @@ -24,28 +24,28 @@ extension Execution { let elementsCount = table.elements.count sp[immediate.result] = UntypedValue(table.limits.isMemory64 ? .i64(UInt64(elementsCount)) : .i32(UInt32(elementsCount))) } - mutating func tableGrow(sp: Sp, immediate: Instruction.TableGrowOperand) throws { + mutating func tableGrow(sp: Sp, immediate: Instruction.TableGrowOperand) throws(Trap) { let table = getTable(immediate.tableIndex, sp: sp, store: store.value) let growthSize = sp[immediate.delta].asAddressOffset(table.limits.isMemory64) let growthValue = sp.getReference(VReg(immediate.value), type: table.tableType) let oldSize = table.elements.count - guard try table.withValue({ try $0.grow(by: growthSize, value: growthValue, resourceLimiter: store.value.resourceLimiter) }) else { + guard try table.withValue({ (t: inout TableEntity) throws(Trap) -> Bool in try t.grow(by: growthSize, value: growthValue, resourceLimiter: store.value.resourceLimiter) }) else { sp[immediate.result] = UntypedValue(.i32(Int32(-1).unsigned)) return } sp[immediate.result] = UntypedValue(table.limits.isMemory64 ? .i64(UInt64(oldSize)) : .i32(UInt32(oldSize))) } - mutating func tableFill(sp: Sp, immediate: Instruction.TableFillOperand) throws { + mutating func tableFill(sp: Sp, immediate: Instruction.TableFillOperand) throws(Trap) { let table = getTable(immediate.tableIndex, sp: sp, store: store.value) let fillCounter = sp[immediate.size].asAddressOffset(table.limits.isMemory64) let fillValue = sp.getReference(immediate.value, type: table.tableType) let startIndex = sp[immediate.destOffset].asAddressOffset(table.limits.isMemory64) - try table.withValue { try $0.fill(repeating: fillValue, from: Int(startIndex), count: Int(fillCounter)) } + try table.withValue { (t: inout TableEntity) throws(Trap) in try t.fill(repeating: fillValue, from: Int(startIndex), count: Int(fillCounter)) } } - mutating func tableCopy(sp: Sp, immediate: Instruction.TableCopyOperand) throws { + mutating func tableCopy(sp: Sp, immediate: Instruction.TableCopyOperand) throws(Trap) { let sourceTableIndex = immediate.sourceIndex let destinationTableIndex = immediate.destIndex let store = self.store.value @@ -60,7 +60,7 @@ extension Execution { try destinationTable.copy(sourceTable, from: Int(sourceIndex), to: Int(destinationIndex), count: Int(size)) } - mutating func tableInit(sp: Sp, immediate: Instruction.TableInitOperand) throws { + mutating func tableInit(sp: Sp, immediate: Instruction.TableInitOperand) throws(Trap) { let tableIndex = immediate.tableIndex let segmentIndex = immediate.segmentIndex let destinationTable = getTable(tableIndex, sp: sp, store: store.value) @@ -70,8 +70,8 @@ extension Execution { let sourceIndex = UInt64(sp[immediate.sourceOffset].i32) let destinationIndex = sp[immediate.destOffset].asAddressOffset(destinationTable.limits.isMemory64) - try destinationTable.withValue { - try $0.initialize( + try destinationTable.withValue { (t: inout TableEntity) throws(Trap) in + try t.initialize( sourceElement, from: Int(sourceIndex), to: Int(destinationIndex), count: Int(copyCounter) @@ -102,7 +102,7 @@ extension Execution { fileprivate mutating func getElementIndex( sp: Sp, _ register: VReg, _ table: InternalTable - ) throws -> ElementIndex { + ) throws(Trap) -> ElementIndex { let elementIndex = sp[register].asAddressOffset(table.limits.isMemory64) guard elementIndex < table.elements.count else { diff --git a/Sources/WasmKit/Execution/MprotectLinearMemory.swift b/Sources/WasmKit/Execution/MprotectLinearMemory.swift index 0de1628f..ce0a1bb2 100644 --- a/Sources/WasmKit/Execution/MprotectLinearMemory.swift +++ b/Sources/WasmKit/Execution/MprotectLinearMemory.swift @@ -57,7 +57,7 @@ } } - mutating func grow(to newCommittedSize: Int) throws { + mutating func grow(to newCommittedSize: Int) throws(Trap) { precondition(newCommittedSize >= committedSize) guard newCommittedSize <= reservationSize else { throw Trap(.memoryOutOfBounds) diff --git a/Sources/WasmKit/Execution/NameRegistry.swift b/Sources/WasmKit/Execution/NameRegistry.swift index 1d7d99d0..409d999f 100644 --- a/Sources/WasmKit/Execution/NameRegistry.swift +++ b/Sources/WasmKit/Execution/NameRegistry.swift @@ -1,7 +1,10 @@ -import struct WasmParser.CustomSection -import struct WasmParser.NameMap -import struct WasmParser.NameSectionParser -import class WasmParser.StaticByteStream +// NameRegistry uses closures with untyped throws (any Error) via materializers array. +// This is not supported in embedded Swift. Use a stub in embedded mode. +#if !$Embedded +import struct WasmParserCore.CustomSection +import struct WasmParserCore.NameMap +import struct WasmParserCore.NameSectionParser +import class WasmParserCore.StaticByteStream struct NameRegistry { private var functionNames: [InternalFunction: String] = [:] @@ -65,3 +68,14 @@ struct NameRegistry { } } } +#else // $Embedded +import WasmParserCore +// Minimal NameRegistry stub for embedded Swift +struct NameRegistry { + init() {} + mutating func register(instance: InternalInstance, nameSection: CustomSection) {} + mutating func flush() {} + func symbolicate(_ function: InternalFunction) -> String { return "" } + func lookup(_ function: InternalFunction) -> String? { return nil } +} +#endif // !$Embedded diff --git a/Sources/WasmKit/Execution/ParsedComponentBuilder.swift b/Sources/WasmKit/Execution/ParsedComponentBuilder.swift index 70e6f958..45213a21 100644 --- a/Sources/WasmKit/Execution/ParsedComponentBuilder.swift +++ b/Sources/WasmKit/Execution/ParsedComponentBuilder.swift @@ -68,7 +68,7 @@ stream: Stream, features: WasmFeatureSet ) throws -> ParsedComponent { - var parser = WasmParser.ComponentParser(stream: stream, features: features) + var parser = WasmParserCore.ComponentParser(stream: stream, features: features) var builder = ParsedComponentBuilder() while let payload = try parser.parseNext() { diff --git a/Sources/WasmKit/Execution/Profiler.swift b/Sources/WasmKit/Execution/Profiler.swift index 8f2f4144..304563af 100644 --- a/Sources/WasmKit/Execution/Profiler.swift +++ b/Sources/WasmKit/Execution/Profiler.swift @@ -1,3 +1,5 @@ +// Profiler depends on SystemExtras and SystemPackage; excluded from embedded builds. +#if !$Embedded import SystemExtras import SystemPackage @@ -138,3 +140,4 @@ private enum JSON { return output } } +#endif // !$Embedded diff --git a/Sources/WasmKit/Execution/Runtime.swift b/Sources/WasmKit/Execution/Runtime.swift index 37a2a56f..84d0b84b 100644 --- a/Sources/WasmKit/Execution/Runtime.swift +++ b/Sources/WasmKit/Execution/Runtime.swift @@ -1,13 +1,16 @@ -import WasmParser +import WasmParserCore +#if !$Embedded /// A container to manage execution state of one or more module instances. @available(*, deprecated, message: "Use `Engine` instead") public final class Runtime { public let store: Store let engine: Engine + #if !$Embedded var interceptor: EngineInterceptor? { engine.interceptor } + #endif var funcTypeInterner: Interner { engine.funcTypeInterner } @@ -25,6 +28,7 @@ public final class Runtime { /// - Parameter hostModules: Host module names mapped to their corresponding ``HostModule`` definitions. /// - Parameter interceptor: An optional runtime interceptor to intercept execution of instructions. /// - Parameter configuration: An optional runtime configuration to customize the runtime behavior. + #if !$Embedded public init( hostModules: [String: HostModule] = [:], interceptor: EngineInterceptor? = nil, @@ -32,11 +36,22 @@ public final class Runtime { ) { self.engine = Engine(configuration: configuration, interceptor: interceptor) store = Store(engine: engine) - for (moduleName, hostModule) in hostModules { registerUniqueHostModule(hostModule, as: moduleName, engine: engine) } } + #else + public init( + hostModules: [String: HostModule] = [:], + configuration: EngineConfiguration = EngineConfiguration() + ) { + self.engine = Engine(configuration: configuration) + store = Store(engine: engine) + for (moduleName, hostModule) in hostModules { + registerUniqueHostModule(hostModule, as: moduleName, engine: engine) + } + } + #endif func resolveType(_ type: InternedFuncType) -> FunctionType { return funcTypeInterner.resolve(type) @@ -96,7 +111,7 @@ public final class Runtime { availableExports[name] = moduleExports } - func getExternalValues(_ module: Module, runtime: Runtime) throws -> Imports { + func getExternalValues(_ module: Module, runtime: Runtime) throws(ImportError) -> Imports { var result = Imports() for i in module.imports { @@ -128,7 +143,7 @@ public final class Runtime { /// let value = myGlobal.value /// ``` @available(*, deprecated, message: "Use `Instance.export` and `Global.value` instead") - public func getGlobal(_ instance: Instance, globalName: String) throws -> Value { + public func getGlobal(_ instance: Instance, globalName: String) throws(Trap) -> Value { guard case .global(let global) = instance.export(globalName) else { throw Trap(.noGlobalExportWithName(globalName: globalName, instance: instance)) } @@ -212,3 +227,4 @@ public struct HostModule { /// Names of functions exported by this module mapped to corresponding host functions. public var functions: [String: HostFunction] } +#endif // !$Embedded diff --git a/Sources/WasmKit/Execution/Store.swift b/Sources/WasmKit/Execution/Store.swift index acd9a923..91151726 100644 --- a/Sources/WasmKit/Execution/Store.swift +++ b/Sources/WasmKit/Execution/Store.swift @@ -1,12 +1,17 @@ -import WasmParser +import WasmParserCore /// A container to manage WebAssembly object space. /// > Note: /// public final class Store { var nameRegistry = NameRegistry() + #if !$Embedded @_spi(Fuzzing) // Consider making this public - public var resourceLimiter: ResourceLimiter = DefaultResourceLimiter() + public var resourceLimiter: any ResourceLimiter = DefaultResourceLimiter() + #else + @_spi(Fuzzing) + public var resourceLimiter: DefaultResourceLimiter = DefaultResourceLimiter() + #endif @available(*, unavailable) public var namedModuleInstances: [String: Any] { @@ -18,8 +23,10 @@ public final class Store { /// The engine associated with this store. public let engine: Engine + #if !$Embedded /// Parking lot for atomic wait/notify operations let atomicParkingLot = AtomicParkingLot() + #endif /// Create a new store associated with the given engine. public init(engine: Engine) { @@ -54,9 +61,11 @@ public struct Caller: ~Copyable { /// The store associated with the caller execution context. public let store: Store + #if !$Embedded /// The runtime that called the host function. @available(*, unavailable, message: "Use `engine` instead") public var runtime: Runtime { fatalError() } + #endif init(instanceHandle: InternalInstance?, store: Store, sp: Sp? = nil) { self.instanceHandle = instanceHandle @@ -88,8 +97,10 @@ extension Store { /// - Parameters: /// - hostModule: A host module to register. /// - name: A name to register the given host module. + #if !$Embedded @available(*, unavailable, message: "Use ``Imports/define(_:as:)`` instead. Or use ``Runtime/register(_:as:)`` as a temporary drop-in replacement.") public func register(_ hostModule: HostModule, as name: String, runtime: Any) throws {} + #endif @available(*, deprecated, message: "Address-based APIs has been removed; use Memory instead") public func memory(at address: Memory) -> Memory { diff --git a/Sources/WasmKit/Execution/StoreAllocator.swift b/Sources/WasmKit/Execution/StoreAllocator.swift index eda7dd26..42a34f56 100644 --- a/Sources/WasmKit/Execution/StoreAllocator.swift +++ b/Sources/WasmKit/Execution/StoreAllocator.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore /// A simple bump allocator for a single type. class BumpAllocator { @@ -105,6 +105,12 @@ struct ImmutableArray { buffer = UnsafeBufferPointer(mutable) } + fileprivate init(allocator: ImmutableArrayAllocator, count: Int, initializeTyped initialize: (inout UnsafeMutableBufferPointer) throws(E) -> Void) throws(E) { + var mutable: UnsafeMutableBufferPointer = allocator.allocate(count: count) + try initialize(&mutable) + buffer = UnsafeBufferPointer(mutable) + } + /// Initializes an empty immutable array. init() { buffer = UnsafeBufferPointer(start: nil, count: 0) @@ -256,13 +262,33 @@ extension StoreAllocator: Equatable { } } +extension StoreAllocator { + // Helper method accessible from both non-embedded and embedded allocate(module:) + func allocateEntitiesTypedMethod( + imports: [EHandle], + internals: Internals, allocateHandle: (Internals.Element, Int) throws(E) -> EHandle + ) throws(E) -> ImmutableArray { + return try ImmutableArray(allocator: arrayAllocator, count: imports.count + internals.count, initializeTyped: { (buffer: inout UnsafeMutableBufferPointer) throws(E) in + for (index, importedEntity) in imports.enumerated() { + buffer.initializeElement(at: index, to: importedEntity) + } + for (internalIndex, internalEntity) in internals.enumerated() { + let index = imports.count + internalIndex + let allocated = try allocateHandle(internalEntity, index) + buffer.initializeElement(at: index, to: allocated) + } + }) + } +} + extension StoreAllocator { /// > Note: /// - func allocate( + #if !$Embedded + func allocate( module: Module, engine: Engine, - resourceLimiter: any ResourceLimiter, + resourceLimiter: RL, imports: Imports, isDebuggable: Bool ) throws -> InternalInstance { @@ -278,12 +304,17 @@ extension StoreAllocator { // External values imported in this module should be included in corresponding index spaces before definitions // local to to the module are added. for importEntry in module.imports { + #if !$Embedded guard let (external, allocator) = imports.lookup(module: importEntry.module, name: importEntry.name) else { throw ImportError(.missing(moduleName: importEntry.module, externalName: importEntry.name)) } guard allocator === self else { throw ImportError(.importedEntityFromDifferentStore(importEntry)) } + #else + guard let (external, allocator) = imports.lookup(module: importEntry.module, name: importEntry.name), + allocator === self else { continue } + #endif switch (importEntry.descriptor, external) { case (.function(let typeIndex), .function(let externalFunc)): @@ -292,47 +323,49 @@ extension StoreAllocator { throw WasmKitError(message: .indexOutOfBounds("type", typeIndex, max: module.types.count)) } let expected = module.types[Int(typeIndex)] + #if !$Embedded guard engine.internType(expected) == type else { let actual = engine.resolveType(type) throw ImportError(.incompatibleFunctionType(importEntry, actual: actual, expected: expected)) } + #endif importedFunctions.append(externalFunc) case (.table(let tableType), .table(let table)): + #if !$Embedded if let max = table.limits.max, max < tableType.limits.min { throw ImportError(.incompatibleTableType(importEntry, actual: tableType, expected: table.tableType)) } + #endif importedTables.append(table) case (.memory(let memoryType), .memory(let memory)): + #if !$Embedded let limit = memory.withValue { $0.limit } - - // Check shared flag matches guard memoryType.shared == limit.shared else { throw ImportError(.incompatibleMemoryType(importEntry, actual: memoryType, expected: limit)) } - // Check memory64 flag matches guard memoryType.isMemory64 == limit.isMemory64 else { throw ImportError(.incompatibleMemoryType(importEntry, actual: memoryType, expected: limit)) } - // Check limits compatibility: provided memory must satisfy imported memory type requirements. - // Note: The memory may have grown already, so compare against the current size. let currentSizeInPages = UInt64(memory.withValue { $0.byteCount }) / UInt64(MemoryEntity.pageSize) guard currentSizeInPages >= memoryType.min else { throw ImportError(.incompatibleMemoryType(importEntry, actual: memoryType, expected: limit)) } - // If the imported memory type has a max, the provided memory must have a max and be <= imported max. if let importedMax = memoryType.max { guard let providedMax = limit.max, providedMax <= importedMax else { throw ImportError(.incompatibleMemoryType(importEntry, actual: memoryType, expected: limit)) } } + #endif importedMemories.append(memory) case (.global(let globalType), .global(let global)): + #if !$Embedded guard globalType == global.globalType else { throw ImportError(.incompatibleGlobalType(importEntry, actual: global.globalType, expected: globalType)) } + #endif importedGlobals.append(global) case (.tag(let typeIndex), .tag(let tag)): @@ -340,13 +373,19 @@ extension StoreAllocator { throw WasmKitError(message: .indexOutOfBounds("type", typeIndex, max: module.types.count)) } let expected = module.types[Int(typeIndex)] + #if !$Embedded guard engine.internType(expected) == tag.type else { throw ImportError(.incompatibleFunctionType(importEntry, actual: engine.resolveType(tag.type), expected: expected)) } + #endif importedTags.append(tag) default: + #if !$Embedded throw ImportError(.incompatibleType(importEntry, entity: external)) + #else + break + #endif } } @@ -366,6 +405,22 @@ extension StoreAllocator { } } + func allocateEntitiesTyped( + imports: [EHandle], + internals: Internals, allocateHandle: (Internals.Element, Int) throws(E) -> EHandle + ) throws(E) -> ImmutableArray { + return try ImmutableArray(allocator: arrayAllocator, count: imports.count + internals.count, initializeTyped: { (buffer: inout UnsafeMutableBufferPointer) throws(E) in + for (index, importedEntity) in imports.enumerated() { + buffer.initializeElement(at: index, to: importedEntity) + } + for (internalIndex, internalEntity) in internals.enumerated() { + let index = imports.count + internalIndex + let allocated = try allocateHandle(internalEntity, index) + buffer.initializeElement(at: index, to: allocated) + } + }) + } + // Uninitialized instance let instancePointer = instances.allocate() var instanceInitialized = false @@ -390,17 +445,17 @@ extension StoreAllocator { ) // Step 3. - let tables = try allocateEntities( + let tables = try allocateEntitiesTyped( imports: importedTables, internals: module.internalTables, - allocateHandle: { t, _ in try allocate(tableType: t, resourceLimiter: resourceLimiter) } + allocateHandle: { (t: TableType, _: Int) throws(Trap) -> InternalTable in try allocate(tableType: t, resourceLimiter: resourceLimiter) } ) // Step 4. - let memories = try allocateEntities( + let memories = try allocateEntitiesTyped( imports: importedMemories, internals: module.internalMemories, - allocateHandle: { m, _ in try allocate(memoryType: m, engineConfiguration: engine.configuration, resourceLimiter: resourceLimiter) } + allocateHandle: { (m: MemoryType, _: Int) throws(Trap) -> InternalMemory in try allocate(memoryType: m, engineConfiguration: engine.configuration, resourceLimiter: resourceLimiter) } ) var functionRefs: Set = [] @@ -413,10 +468,10 @@ extension StoreAllocator { } ) - let globals = try allocateEntities( + let globals = try allocateEntitiesTyped( imports: importedGlobals, internals: module.globals, - allocateHandle: { global, _ in + allocateHandle: { (global: WasmParserCore.Global, _: Int) throws(WasmKitError) -> InternalGlobal in let initialValue = try global.initializer.evaluate( context: constEvalContext, expectedType: global.type.valueType ) @@ -425,17 +480,17 @@ extension StoreAllocator { ) // Allocate tags. - let tags = try allocateEntities( + let tags = try allocateEntitiesTyped( imports: importedTags, internals: module.tagTypes[module.moduleImports.numberOfTags...], - allocateHandle: { typeIndex, _ in + allocateHandle: { (typeIndex: TypeIndex, _: Int) throws(WasmKitError) -> InternalTag in let funcType = try Module.resolveType(typeIndex, typeSection: module.types) return allocate(tagType: funcType, engine: engine) } ) // Step 6. - let elements = try ImmutableArray(allocator: arrayAllocator, count: module.elements.count) { buffer in + let elements = try ImmutableArray(allocator: arrayAllocator, count: module.elements.count, initializeTyped: { (buffer: inout UnsafeMutableBufferPointer) throws(WasmKitError) in for (index, element) in module.elements.enumerated() { // TODO: Avoid evaluating element expr twice in `Module.instantiate` and here. var references = try element.evaluateInits(context: constEvalContext) @@ -448,7 +503,7 @@ extension StoreAllocator { let handle = allocate(elementType: element.type, references: references) buffer.initializeElement(at: index, to: handle) } - } + }) // Step 13. let dataSegments = ImmutableArray(allocator: arrayAllocator, count: module.data.count) { buffer in @@ -467,7 +522,7 @@ extension StoreAllocator { } } - func createExportValue(_ export: WasmParser.Export) throws -> InternalExternalValue { + func createExportValue(_ export: WasmParserCore.Export) throws(WasmKitError) -> InternalExternalValue { switch export.descriptor { case .function(let index): let handle = try functions[validating: Int(index)] @@ -487,12 +542,23 @@ extension StoreAllocator { } } - let exports: [String: InternalExternalValue] = try module.exports.reduce(into: [:]) { result, export in + #if !$Embedded + let exports: ExportsStorage = try module.exports.reduce(into: [:]) { (result: inout ExportsStorage, export: WasmParserCore.Export) throws(WasmKitError) in guard result[export.name] == nil else { throw WasmKitError(message: .duplicateExportName(name: export.name)) } result[export.name] = try createExportValue(export) } + #else + // Embedded mode: use array to avoid String.hashValue → NFC normalization. + var exports = ExportsStorage() + for export in module.exports { + guard !exports.contains(where: { $0.key.utf8.elementsEqual(export.name.utf8) }) else { + throw WasmKitError(message: .duplicateExportName(name: export.name)) + } + exports.append((key: export.name, value: try createExportValue(export))) + } + #endif // Steps 20-21. let instanceEntity = InstanceEntity( @@ -515,6 +581,122 @@ extension StoreAllocator { instanceInitialized = true return instanceHandle } + #else // $Embedded - simplified version without ImportError + func allocate( + module: Module, + engine: Engine, + resourceLimiter: RL, + imports: Imports, + isDebuggable: Bool + ) throws(WasmKitError) -> InternalInstance { + let types = module.types + var importedFunctions: [InternalFunction] = [] + var importedTables: [InternalTable] = [] + var importedMemories: [InternalMemory] = [] + var importedGlobals: [InternalGlobal] = [] + var importedTags: [InternalTag] = [] + + // Resolve imports (skip validation in embedded) + for importEntry in module.imports { + guard let (external, allocator) = imports.lookup(module: importEntry.module, name: importEntry.name), + allocator === self else { continue } + switch (importEntry.descriptor, external) { + case (.function, .function(let f)): importedFunctions.append(f) + case (.table, .table(let t)): importedTables.append(t) + case (.memory, .memory(let m)): importedMemories.append(m) + case (.global, .global(let g)): importedGlobals.append(g) + case (.tag, .tag(let t)): importedTags.append(t) + default: break + } + } + + // Allocate uninitialized instance pointer for self-reference + let instancePointer = instances.allocate() + let instanceHandle = InternalInstance(unsafe: instancePointer) + + let arrayAllocator = self.arrayAllocator + + // Allocate wasm functions + var allFunctions = ImmutableArray(allocator: arrayAllocator, count: importedFunctions.count + module.functions.count) { buffer in + for (i, f) in importedFunctions.enumerated() { buffer.initializeElement(at: i, to: f) } + for (i, f) in module.functions.enumerated() { + let idx = importedFunctions.count + i + let handle = allocate(function: f, index: FunctionIndex(idx), instance: instanceHandle, engine: engine) + buffer.initializeElement(at: idx, to: handle) + } + } + + // Allocate tables (convert Trap → WasmKitError) + let tables: ImmutableArray + do throws(Trap) { tables = try allocateEntitiesTypedMethod(imports: importedTables, internals: module.internalTables, allocateHandle: { (t: TableType, _: Int) throws(Trap) -> InternalTable in try allocate(tableType: t, resourceLimiter: resourceLimiter) }) } + catch let e { throw WasmKitError(e) } + + // Allocate memories (convert Trap → WasmKitError) + let memories: ImmutableArray + do throws(Trap) { memories = try allocateEntitiesTypedMethod(imports: importedMemories, internals: module.internalMemories, allocateHandle: { (m: MemoryType, _: Int) throws(Trap) -> InternalMemory in try allocate(memoryType: m, engineConfiguration: engine.configuration, resourceLimiter: resourceLimiter) }) } + catch let e { throw WasmKitError(e) } + + // Allocate globals + let constEvalContext = ConstEvaluationContext(functions: allFunctions, globals: importedGlobals.map { $0.value }, onFunctionReferenced: nil) + let globals = try allocateEntitiesTypedMethod(imports: importedGlobals, internals: module.globals, allocateHandle: { (global: WasmParserCore.Global, _: Int) throws(WasmKitError) -> InternalGlobal in + let v = try global.initializer.evaluate(context: constEvalContext, expectedType: global.type.valueType) + return try allocate(globalType: global.type, initialValue: v) + }) + + // Allocate tags + let tags = try allocateEntitiesTypedMethod(imports: importedTags, internals: module.tagTypes[module.moduleImports.numberOfTags...], allocateHandle: { (typeIndex: TypeIndex, _: Int) throws(WasmKitError) -> InternalTag in + let funcType = try Module.resolveType(typeIndex, typeSection: types) + return allocate(tagType: funcType, engine: engine) + }) + + // Allocate elements + let constEvalContext2 = ConstEvaluationContext(instance: instanceHandle, moduleImports: module.moduleImports) + let elements = try ImmutableArray(allocator: arrayAllocator, count: module.elements.count, initializeTyped: { (buffer: inout UnsafeMutableBufferPointer) throws(WasmKitError) in + for (i, element) in module.elements.enumerated() { + var references = try element.evaluateInits(context: constEvalContext2) + switch element.mode { case .active, .declarative: references = []; case .passive: break } + buffer.initializeElement(at: i, to: allocate(elementType: element.type, references: references)) + } + }) + + // Allocate data segments + let dataSegments = ImmutableArray(allocator: arrayAllocator, count: module.data.count) { buffer in + for (i, datum) in module.data.enumerated() { + let seg: InternalDataSegment + switch datum { case .passive(let b): seg = allocate(bytes: b); case .active: seg = allocate(bytes: []) } + buffer.initializeElement(at: i, to: seg) + } + } + + // Create exports (manual loop to avoid typed-throws issues with reduce) + // Embedded mode: use array to avoid String.hashValue → NFC normalization (~31 KB). + var exports = ExportsStorage() + func exportVal(_ e: WasmParserCore.Export) throws(WasmKitError) -> InternalExternalValue { + switch e.descriptor { + case .function(let i): return .function(try allFunctions[validating: Int(i)]) + case .table(let i): return .table(try tables[validating: Int(i)]) + case .memory(let i): return .memory(try memories[validating: Int(i), MemoryEntity.createOutOfBoundsError]) + case .global(let i): return .global(try globals[validating: Int(i)]) + case .tag(let i): return .tag(try tags[validating: Int(i)]) + } + } + for export in module.exports { + guard !exports.contains(where: { $0.key.utf8.elementsEqual(export.name.utf8) }) else { + throw WasmKitError(message: .duplicateExportName(name: export.name)) + } + exports.append((key: export.name, value: try exportVal(export))) + } + + let instanceEntity = InstanceEntity( + types: types, functions: allFunctions, tables: tables, memories: memories, + globals: globals, tags: tags, elementSegments: elements, dataSegments: dataSegments, + exports: exports, functionRefs: [], features: module.features, dataCount: module.dataCount, + isDebuggable: isDebuggable, instructionMapping: .init() + ) + instancePointer.initialize(to: instanceEntity) + return instanceHandle + } + #endif // !$Embedded /// > Note: /// @@ -550,21 +732,21 @@ extension StoreAllocator { /// > Note: /// - func allocate(tableType: TableType, resourceLimiter: any ResourceLimiter) throws -> InternalTable { + func allocate(tableType: TableType, resourceLimiter: RL) throws(Trap) -> InternalTable { let pointer = try tables.allocate(initializing: TableEntity(tableType, resourceLimiter: resourceLimiter)) return InternalTable(unsafe: pointer) } /// > Note: /// - func allocate(memoryType: MemoryType, engineConfiguration: EngineConfiguration, resourceLimiter: any ResourceLimiter) throws -> InternalMemory { + func allocate(memoryType: MemoryType, engineConfiguration: EngineConfiguration, resourceLimiter: RL) throws(Trap) -> InternalMemory { let pointer = try memories.allocate(initializing: MemoryEntity(memoryType, engineConfiguration: engineConfiguration, resourceLimiter: resourceLimiter)) return InternalMemory(unsafe: pointer) } /// > Note: /// - func allocate(globalType: GlobalType, initialValue: Value) throws -> InternalGlobal { + func allocate(globalType: GlobalType, initialValue: Value) throws(WasmKitError) -> InternalGlobal { let pointer = try globals.allocate(initializing: GlobalEntity(globalType: globalType, initialValue: initialValue)) return InternalGlobal(unsafe: pointer) } diff --git a/Sources/WasmKit/Execution/UntypedValue.swift b/Sources/WasmKit/Execution/UntypedValue.swift index f32bc8c8..ea5c9086 100644 --- a/Sources/WasmKit/Execution/UntypedValue.swift +++ b/Sources/WasmKit/Execution/UntypedValue.swift @@ -1,3 +1,5 @@ +import WasmParserCore + /// A type-erased value that can represent any WebAssembly value type. /// /// NOTE: This type assumes any non-null references can be represented as a diff --git a/Sources/WasmKit/Execution/Value.swift b/Sources/WasmKit/Execution/Value.swift index 9c6a4fcb..4850ca00 100644 --- a/Sources/WasmKit/Execution/Value.swift +++ b/Sources/WasmKit/Execution/Value.swift @@ -1,5 +1,4 @@ -import struct WasmTypes.ReferenceType -import enum WasmTypes.ValueType +import WasmParserCore /// > Note: /// @@ -145,25 +144,25 @@ extension RawUnsignedInteger { return self >> shift | self << (Self(Self.bitWidth) - shift) } - func divS(_ other: Self) throws -> Self { + func divS(_ other: Self) throws(Trap) -> Self { if _slowPath(other == 0) { throw Trap(.integerDividedByZero) } let (signed, overflow) = signed.dividedReportingOverflow(by: other.signed) guard !overflow else { throw Trap(.integerOverflow) } return signed.unsigned } - func divU(_ other: Self) throws -> Self { + func divU(_ other: Self) throws(Trap) -> Self { if _slowPath(other == 0) { throw Trap(.integerDividedByZero) } let (unsigned, overflow) = dividedReportingOverflow(by: other) guard !overflow else { throw Trap(.integerOverflow) } return unsigned } - func remS(_ other: Self) throws -> Self { + func remS(_ other: Self) throws(Trap) -> Self { if _slowPath(other == 0) { throw Trap(.integerDividedByZero) } let (signed, overflow) = signed.remainderReportingOverflow(dividingBy: other.signed) guard !overflow else { return 0 } return signed.unsigned } - func remU(_ other: Self) throws -> Self { + func remU(_ other: Self) throws(Trap) -> Self { if _slowPath(other == 0) { throw Trap(.integerDividedByZero) } let (unsigned, overflow) = remainderReportingOverflow(dividingBy: other) guard !overflow else { throw Trap(.integerOverflow) } @@ -262,7 +261,7 @@ extension FloatingPoint { fileprivate func truncTo( rounding: (Self) -> T, max: Self, min: Self - ) throws -> T { + ) throws(Trap) -> T { guard !self.isNaN else { throw Trap(.invalidConversionToInteger) } if self <= min || self >= max { throw Trap(.integerOverflow) @@ -273,7 +272,7 @@ extension FloatingPoint { fileprivate func truncSatTo( rounding: (Self) -> T, max: Self, min: Self - ) throws -> T { + ) throws(Trap) -> T { guard !self.isNaN else { return .zero } if self <= min { return .min @@ -286,42 +285,42 @@ extension FloatingPoint { extension Float32 { var truncToI32S: UInt32 { - get throws { + get throws(Trap) { return try truncTo(rounding: { Int32($0) }, max: 2147483648.0, min: -2147483904.0).unsigned } } var truncToI64S: UInt64 { - get throws { + get throws(Trap) { return try truncTo(rounding: { Int64($0) }, max: 9223372036854775808.0, min: -9223373136366403584.0).unsigned } } var truncToI32U: UInt32 { - get throws { + get throws(Trap) { return try truncTo(rounding: { UInt32($0) }, max: 4294967296.0, min: -1.0) } } var truncToI64U: UInt64 { - get throws { + get throws(Trap) { return try truncTo(rounding: { UInt64($0) }, max: 18446744073709551616.0, min: -1.0) } } var truncSatToI32S: UInt32 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { Int32($0) }, max: 2147483648.0, min: -2147483904.0).unsigned } } var truncSatToI64S: UInt64 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { Int64($0) }, max: 9223372036854775808.0, min: -9223373136366403584.0).unsigned } } var truncSatToI32U: UInt32 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { UInt32($0) }, max: 4294967296.0, min: -1.0) } } var truncSatToI64U: UInt64 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { UInt64($0) }, max: 18446744073709551616.0, min: -1.0) } } @@ -330,42 +329,42 @@ extension Float32 { } extension Float64 { var truncToI32S: UInt32 { - get throws { + get throws(Trap) { return try truncTo(rounding: { Int32($0) }, max: 2147483648.0, min: -2147483649.0).unsigned } } var truncToI64S: UInt64 { - get throws { + get throws(Trap) { return try truncTo(rounding: { Int64($0) }, max: 9223372036854775808.0, min: -9223372036854777856.0).unsigned } } var truncToI32U: UInt32 { - get throws { + get throws(Trap) { return try truncTo(rounding: { UInt32($0) }, max: 4294967296.0, min: -1.0) } } var truncToI64U: UInt64 { - get throws { + get throws(Trap) { return try truncTo(rounding: { UInt64($0) }, max: 18446744073709551616.0, min: -1.0) } } var truncSatToI32S: UInt32 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { Int32($0) }, max: 2147483648.0, min: -2147483649.0).unsigned } } var truncSatToI64S: UInt64 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { Int64($0) }, max: 9223372036854775808.0, min: -9223372036854777856.0).unsigned } } var truncSatToI32U: UInt32 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { UInt32($0) }, max: 4294967296.0, min: -1.0) } } var truncSatToI64U: UInt64 { - get throws { + get throws(Trap) { return try truncSatTo(rounding: { UInt64($0) }, max: 18446744073709551616.0, min: -1.0) } } diff --git a/Sources/WasmKit/Imports.swift b/Sources/WasmKit/Imports.swift index cfae6207..e6c3f4e7 100644 --- a/Sources/WasmKit/Imports.swift +++ b/Sources/WasmKit/Imports.swift @@ -1,4 +1,4 @@ -import struct WasmParser.Import +import struct WasmParserCore.Import /// A set of entities used to import values when instantiating a module. /// @@ -23,7 +23,15 @@ import struct WasmParser.Import /// let instance = try module.instantiate(store: store, imports: imports) /// ``` public struct Imports { + #if !$Embedded private var definitions: [String: [String: ExternalValue]] = [:] + #else + // Embedded Swift: use a flat array instead of nested dictionaries. + // Dictionary uses String.hashValue which pulls in Unicode NFC + // normalization tables (~31 KB rodata). Linear search with UTF-8 byte + // comparison is sufficient for the small number of WASM imports. + private var embeddedEntries: [(module: String, name: String, value: ExternalValue)] = [] + #endif /// Initializes a new instance of `Imports`. public init() { @@ -31,16 +39,22 @@ public struct Imports { /// Define a value to be imported by the given module and name. public mutating func define(module: String, name: String, _ value: Extern) { + #if !$Embedded definitions[module, default: [:]][name] = value.externalValue + #else + embeddedEntries.append((module: module, name: name, value: value.externalValue)) + #endif } /// Define a set of values to be imported by the given module. /// - Parameters: /// - module: The module name to be used for resolving the imports. /// - values: The values to be imported keyed by their name. + #if !$Embedded public mutating func define(module: String, _ values: Exports) { definitions[module, default: [:]].merge(values.map { ($0, $1) }, uniquingKeysWith: { _, new in new }) } + #endif mutating func define(_ importEntry: Import, _ value: ExternalValue) { define(module: importEntry.module, name: importEntry.name, value) @@ -48,7 +62,22 @@ public struct Imports { /// Lookup a value to be imported by the given module and name. func lookup(module: String, name: String) -> (InternalExternalValue, StoreAllocator)? { - definitions[module]?[name]?.internalize() + #if !$Embedded + return definitions[module]?[name]?.internalize() + #else + // Byte-by-byte UTF-8 comparison avoids String.hashValue and + // String.== which transitively require Unicode NFC normalization. + let mBytes = module.utf8 + let nBytes = name.utf8 + for entry in embeddedEntries { + guard entry.module.utf8.count == mBytes.count, + entry.name.utf8.count == nBytes.count else { continue } + guard entry.module.utf8.elementsEqual(mBytes) else { continue } + guard entry.name.utf8.elementsEqual(nBytes) else { continue } + return entry.value.internalize() + } + return nil + #endif } } @@ -81,8 +110,10 @@ extension Tag: ExternalValueConvertible { public var externalValue: ExternalValue { .tag(self) } } +#if !$Embedded extension Imports: ExpressibleByDictionaryLiteral { public typealias Key = String + #if !$Embedded public struct Value: ExpressibleByDictionaryLiteral { public typealias Key = String public typealias Value = ExternalValueConvertible @@ -93,8 +124,21 @@ extension Imports: ExpressibleByDictionaryLiteral { self.definitions = Dictionary(uniqueKeysWithValues: elements.map { ($0.0, $0.1.externalValue) }) } } + #else + public struct Value: ExpressibleByDictionaryLiteral { + public typealias Key = String + public typealias Value = ExternalValue + + let definitions: [String: ExternalValue] + + public init(dictionaryLiteral elements: (String, ExternalValue)...) { + self.definitions = Dictionary(uniqueKeysWithValues: elements.map { ($0.0, $0.1) }) + } + } + #endif public init(dictionaryLiteral elements: (String, Value)...) { self.definitions = Dictionary(uniqueKeysWithValues: elements.map { ($0.0, $0.1.definitions) }) } } +#endif // !$Embedded diff --git a/Sources/WasmKit/Module.swift b/Sources/WasmKit/Module.swift index d8876f75..3c391368 100644 --- a/Sources/WasmKit/Module.swift +++ b/Sources/WasmKit/Module.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore struct ModuleImports { let numberOfFunctions: Int @@ -58,8 +58,8 @@ public struct Module { let elements: [ElementSegment] let data: [DataSegment] let start: FunctionIndex? - let globals: [WasmParser.Global] - let tags: [WasmParser.Tag] + let globals: [WasmParserCore.Global] + let tags: [WasmParserCore.Tag] public let imports: [Import] public let exports: [Export] public let customSections: [CustomSection] @@ -81,10 +81,10 @@ public struct Module { start: FunctionIndex?, imports: [Import], exports: [Export], - globals: [WasmParser.Global], + globals: [WasmParserCore.Global], memories: [MemoryType], tables: [TableType], - tags: [WasmParser.Tag] = [], + tags: [WasmParserCore.Tag] = [], customSections: [CustomSection], features: WasmFeatureSet, dataCount: UInt32? @@ -119,7 +119,7 @@ public struct Module { self.importedFunctionTypes = importedFunctionTypes self.memoryTypes = memoryTypes + memories self.tableTypes = tableTypes + tables - self.tagTypes = tagTypes + tags.map(\.type) + self.tagTypes = tagTypes + tags.map { $0.type } } static func resolveType(_ index: TypeIndex, typeSection: [FunctionType]) throws(WasmKitError) -> FunctionType { @@ -148,9 +148,15 @@ public struct Module { /// - store: The ``Store`` to allocate the instance in. /// - imports: The imports to use for instantiation. All imported entities /// must be allocated in the given store. - public func instantiate(store: Store, imports: Imports = [:]) throws -> Instance { + #if !$Embedded + public func instantiate(store: Store, imports: Imports = Imports()) throws -> Instance { Instance(handle: try self.instantiateHandle(store: store, imports: imports), store: store) } + #else + public func instantiate(store: Store, imports: Imports = Imports()) throws(WasmKitError) -> Instance { + Instance(handle: try self.instantiateHandle(store: store, imports: imports), store: store) + } + #endif #if WasmDebuggingSupport /// Instantiate this module with the given imports. @@ -161,13 +167,20 @@ public struct Module { /// must be allocated in the given store. /// - isDebuggable: Whether the module should support debugging actions /// (breakpoints etc) after instantiation. - public func instantiate(store: Store, imports: Imports = [:], isDebuggable: Bool) throws -> Instance { + #if !$Embedded + public func instantiate(store: Store, imports: Imports = Imports(), isDebuggable: Bool) throws -> Instance { Instance(handle: try self.instantiateHandle(store: store, imports: imports, isDebuggable: isDebuggable), store: store) } + #else + public func instantiate(store: Store, imports: Imports = Imports(), isDebuggable: Bool) throws(WasmKitError) -> Instance { + Instance(handle: try self.instantiateHandle(store: store, imports: imports, isDebuggable: isDebuggable), store: store) + } + #endif #endif /// > Note: /// +#if !$Embedded private func instantiateHandle(store: Store, imports: Imports, isDebuggable: Bool = false) throws -> InternalInstance { try ModuleValidator(module: self).validate() @@ -201,7 +214,7 @@ public struct Module { context: constEvalContext, expectedType: .addressType(isMemory64: table.limits.isMemory64) ) - try table.withValue { table in + try table.withValue { (table: inout TableEntity) throws(WasmKitError) in guard let offset = offsetValue.maybeAddressOffset(table.limits.isMemory64) else { throw WasmKitError( kind: .message( @@ -223,9 +236,11 @@ public struct Module { ) } let references = try element.evaluateInits(context: constEvalContext) - try table.initialize( - references, from: 0, to: Int(offset), count: references.count - ) + do throws(Trap) { + try table.initialize(references, from: 0, to: Int(offset), count: references.count) + } catch let e { + throw WasmKitError(e) + } } } @@ -237,7 +252,7 @@ public struct Module { context: constEvalContext, expectedType: .addressType(isMemory64: isMemory64) ) - try memory.withValue { memory in + try memory.withValue { (memory: inout MemoryEntity) throws(WasmKitError) in guard let offset = offsetValue.maybeAddressOffset(isMemory64) else { throw WasmKitError( kind: .message( @@ -248,7 +263,8 @@ public struct Module { ) ) } - try memory.write(offset: Int(offset), bytes: data.initializer) + do throws(Trap) { try memory.write(offset: Int(offset), bytes: data.initializer) } + catch let e { throw WasmKitError(e) } } } @@ -260,13 +276,120 @@ public struct Module { // Compile all functions eagerly if the engine is in eager compilation mode if store.engine.configuration.compilationMode == .eager { - try instance.withValue { - try $0.compileAllFunctions(store: store) + try instance.withValue { (inst: inout InstanceEntity) throws(Trap) in + try inst.compileAllFunctions(store: store) + } + } + + return instance + } +#else // $Embedded + private func instantiateHandle(store: Store, imports: Imports, isDebuggable: Bool = false) throws(WasmKitError) -> InternalInstance { + try ModuleValidator(module: self).validate() + + // Steps 5-8. + + // Step 9. + // Process `elem.init` evaluation during allocation + + // Step 11. + let instance = try store.allocator.allocate( + module: self, engine: store.engine, + resourceLimiter: store.resourceLimiter, + imports: imports, + isDebuggable: isDebuggable + ) + + if let nameSection = customSections.first(where: { $0.name == "name" }) { + // FIXME?: Just ignore parsing error of name section for now. + // Should emit warning instead of just discarding it? + try? store.nameRegistry.register(instance: instance, nameSection: nameSection) + } + + let constEvalContext = ConstEvaluationContext(instance: instance, moduleImports: moduleImports) + // Step 12-13. + + // Steps 14-15. + for element in elements { + guard case .active(let tableIndex, let offset) = element.mode else { continue } + let table = try instance.tables[validating: Int(tableIndex)] + let offsetValue = try offset.evaluate( + context: constEvalContext, + expectedType: .addressType(isMemory64: table.limits.isMemory64) + ) + try table.withValue { (table: inout TableEntity) throws(WasmKitError) in + guard let offset = offsetValue.maybeAddressOffset(table.limits.isMemory64) else { + throw WasmKitError( + kind: .message( + .unexpectedOffsetInitializer( + expected: .addressType(isMemory64: table.limits.isMemory64), + got: offsetValue + ) + ) + ) + } + guard table.tableType.elementType == element.type else { + throw WasmKitError( + kind: .message( + .elementSegmentTypeMismatch( + elementType: element.type, + tableElementType: table.tableType.elementType + ) + ) + ) + } + let references = try element.evaluateInits(context: constEvalContext) + do throws(Trap) { + try table.initialize(references, from: 0, to: Int(offset), count: references.count) + } catch let e { + throw WasmKitError(e) + } + } + } + + // Step 16. + for case .active(let data) in data { + let memory = try instance.memories[validating: Int(data.index), MemoryEntity.createOutOfBoundsError] + let isMemory64 = memory.withValue { $0.limit.isMemory64 } + let offsetValue = try data.offset.evaluate( + context: constEvalContext, + expectedType: .addressType(isMemory64: isMemory64) + ) + try memory.withValue { (memory: inout MemoryEntity) throws(WasmKitError) in + guard let offset = offsetValue.maybeAddressOffset(isMemory64) else { + throw WasmKitError( + kind: .message( + .unexpectedOffsetInitializer( + expected: .addressType(isMemory64: isMemory64), + got: offsetValue + ) + ) + ) + } + do throws(Trap) { try memory.write(offset: Int(offset), bytes: data.initializer) } + catch let e { throw WasmKitError(e) } } } + // Step 17. + if let startIndex = start { + let startFunction = try instance.functions[validating: Int(startIndex)] + do throws(Trap) { _ = try startFunction.invoke([], store: store) } + catch let e { throw WasmKitError(e) } + } + + // Compile all functions eagerly if the engine is in eager compilation mode + if store.engine.configuration.compilationMode == .eager { + do throws(Trap) { + try instance.withValue { (inst: inout InstanceEntity) throws(Trap) in + try inst.compileAllFunctions(store: store) + } + } catch let e { throw WasmKitError(e) } + } + return instance } +#endif // !$Embedded /// Materialize lazily-computed elements in this module @available(*, deprecated, message: "Module materialization is no longer supported. Instantiate the module explicitly instead.") diff --git a/Sources/WasmKit/ModuleParser.swift b/Sources/WasmKit/ModuleParser.swift index a2351823..23e8889a 100644 --- a/Sources/WasmKit/ModuleParser.swift +++ b/Sources/WasmKit/ModuleParser.swift @@ -1,6 +1,10 @@ import SystemExtras import SystemPackage +import WasmParserCore + +#if !$Embedded import WasmParser +import SystemPackage #if os(Windows) import ucrt @@ -26,6 +30,7 @@ public func parseWasm(filePath: FilePath, features: WasmFeatureSet = .default) t try fileHandle.close() } } +#endif // !$Embedded /// Parse a given byte array as a WebAssembly binary format file /// > Note: @@ -37,7 +42,7 @@ public func parseWasm(bytes: [UInt8], features: WasmFeatureSet = .default) throw /// Parse a given byte slice as a WebAssembly binary format file /// > Note: -public func parseWasm(bytes: ArraySlice, features: WasmFeatureSet = .default) throws -> Module { +public func parseWasm(bytes: ArraySlice, features: WasmFeatureSet = .default) throws(WasmKitError) -> Module { let stream = StaticByteStream(bytes: bytes) let module = try parseModule(stream: stream, features: features) return module @@ -51,8 +56,8 @@ func parseModule(stream: Stream, features: WasmFeatureSet = var codes: [Code] = [] var tables: [TableType] = [] var memories: [MemoryType] = [] - var globals: [WasmParser.Global] = [] - var tags: [WasmParser.Tag] = [] + var globals: [WasmParserCore.Global] = [] + var tags: [WasmParserCore.Tag] = [] var elements: [ElementSegment] = [] var data: [DataSegment] = [] var start: FunctionIndex? @@ -61,7 +66,7 @@ func parseModule(stream: Stream, features: WasmFeatureSet = var customSections: [CustomSection] = [] var dataCount: UInt32? - var parser = WasmParser.Parser( + var parser = WasmParserCore.Parser( stream: stream, features: features ) @@ -77,9 +82,9 @@ func parseModule(stream: Stream, features: WasmFeatureSet = case .functionSection(let types): typeIndices = types case .tableSection(let tableSection): - tables = tableSection.map(\.type) + tables = tableSection.map { $0.type } case .memorySection(let memorySection): - memories = memorySection.map(\.type) + memories = memorySection.map { $0.type } case .globalSection(let globalSection): globals = globalSection case .tagSection(let tagSection): diff --git a/Sources/WasmKit/ResourceLimiter.swift b/Sources/WasmKit/ResourceLimiter.swift index b9591239..fa9497f2 100644 --- a/Sources/WasmKit/ResourceLimiter.swift +++ b/Sources/WasmKit/ResourceLimiter.swift @@ -1,29 +1,18 @@ /// A protocol for limiting resource allocation. public protocol ResourceLimiter: Sendable { /// Limit the memory growth of the process to the specified number of bytes. - /// - /// - Parameter desired: The desired size of the memory in bytes. - /// - Returns: `true` if the memory growth should be allowed. `false` if - /// the memory growth should be denied. - func limitMemoryGrowth(to desired: Int) throws -> Bool - + func limitMemoryGrowth(to desired: Int) throws(Trap) -> Bool /// Limit the table growth of the process to the specified number of elements. - /// - /// - Parameter desired: The desired size of the table in elements. - /// - Returns: `true` if the table growth should be allowed. `false` if - /// the table growth should be denied. - func limitTableGrowth(to desired: Int) throws -> Bool + func limitTableGrowth(to desired: Int) throws(Trap) -> Bool } // By default, we don't limit resource growth. extension ResourceLimiter { - func limitMemoryGrowth(to desired: Int) throws -> Bool { - return true - } - func limitTableGrowth(to desired: Int) throws -> Bool { - return true - } + public func limitMemoryGrowth(to desired: Int) throws(Trap) -> Bool { true } + public func limitTableGrowth(to desired: Int) throws(Trap) -> Bool { true } } /// A default resource limiter that doesn't limit resource growth. -struct DefaultResourceLimiter: ResourceLimiter {} +public struct DefaultResourceLimiter: ResourceLimiter { + public init() {} +} diff --git a/Sources/WasmKit/SIMDOpcode.swift b/Sources/WasmKit/SIMDOpcode.swift index 2c2448bd..dc5aa52d 100644 --- a/Sources/WasmKit/SIMDOpcode.swift +++ b/Sources/WasmKit/SIMDOpcode.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore /// A compact opcode space for all SIMD-related Wasm instructions executed by `Instruction.simd`. enum SIMDOpcode: UInt16 { @@ -265,7 +265,7 @@ enum SIMDOpcode: UInt16 { } extension SIMDOpcode { - static func fromLoad(_ value: WasmParser.Instruction.Load) -> SIMDOpcode? { + static func fromLoad(_ value: WasmParserCore.Instruction.Load) -> SIMDOpcode? { switch value { case .v128Load: return .v128Load case .v128Load8X8S: return .v128Load8X8S @@ -284,14 +284,14 @@ extension SIMDOpcode { } } - static func fromStore(_ value: WasmParser.Instruction.Store) -> SIMDOpcode? { + static func fromStore(_ value: WasmParserCore.Instruction.Store) -> SIMDOpcode? { switch value { case .v128Store: return .v128Store default: return nil } } - static func fromSimd(_ value: WasmParser.Instruction.Simd) -> SIMDOpcode? { + static func fromSimd(_ value: WasmParserCore.Instruction.Simd) -> SIMDOpcode? { switch value { case .i8x16Swizzle: return .i8x16Swizzle case .i8x16Splat: return .i8x16Splat @@ -494,7 +494,7 @@ extension SIMDOpcode { } } - static func fromSimdLane(_ value: WasmParser.Instruction.SimdLane) -> SIMDOpcode? { + static func fromSimdLane(_ value: WasmParserCore.Instruction.SimdLane) -> SIMDOpcode? { switch value { case .i8x16ExtractLaneS: return .i8x16ExtractLaneS case .i8x16ExtractLaneU: return .i8x16ExtractLaneU @@ -513,7 +513,7 @@ extension SIMDOpcode { } } - static func fromSimdMemLane(_ value: WasmParser.Instruction.SimdMemLane) -> SIMDOpcode? { + static func fromSimdMemLane(_ value: WasmParserCore.Instruction.SimdMemLane) -> SIMDOpcode? { switch value { case .v128Load8Lane: return .v128Load8Lane case .v128Load16Lane: return .v128Load16Lane diff --git a/Sources/WasmKit/Translator.swift b/Sources/WasmKit/Translator.swift index 26782716..1bdba503 100644 --- a/Sources/WasmKit/Translator.swift +++ b/Sources/WasmKit/Translator.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore import WasmTypes class ISeqAllocator { @@ -704,14 +704,12 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { let headSlot = instruction.headSlot(threadingModel: engineConfiguration.threadingModel) trace(" [\(index)] = 0x\(String(headSlot, radix: 16))") self.instructions[index] = headSlot - if let immediate = instruction.rawImmediate { - var slots: [CodeSlot] = [] - immediate.emit(to: { slots.append($0) }) - for (i, slot) in slots.enumerated() { - let slotIndex = index + 1 + i - trace(" [\(slotIndex)] = 0x\(String(slot, radix: 16))") - self.instructions[slotIndex] = slot - } + var slots: [CodeSlot] = [] + instruction.emitImmediate(to: { slots.append($0) }) + for (i, slot) in slots.enumerated() { + let slotIndex = index + 1 + i + trace(" [\(slotIndex)] = 0x\(String(slot, radix: 16))") + self.instructions[slotIndex] = slot } } @@ -748,11 +746,9 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { self.lastEmission = LastEmission(position: insertingPC, resultRelink: resultRelink) trace("emitInstruction: \(instruction)") emitSlot(instruction.headSlot(threadingModel: engineConfiguration.threadingModel)) - if let immediate = instruction.rawImmediate { - var slots: [CodeSlot] = [] - immediate.emit(to: { slots.append($0) }) - for slot in slots { emitSlot(slot) } - } + var slots: [CodeSlot] = [] + instruction.emitImmediate(to: { slots.append($0) }) + for slot in slots { emitSlot(slot) } } mutating func putLabel() -> LabelRef { @@ -1329,7 +1325,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { emit(.nop) } - mutating func visitBlock(blockType: WasmParser.BlockType) throws(WasmKitError) -> Output { + mutating func visitBlock(blockType: WasmParserCore.BlockType) throws(WasmKitError) -> Output { let blockType = try module.resolveBlockType(blockType) let endLabel = iseqBuilder.allocLabel() self.preserveLocalsOnStack(depth: self.valueStack.valueHeight) @@ -1345,7 +1341,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { ) } - mutating func visitLoop(blockType: WasmParser.BlockType) throws(WasmKitError) -> Output { + mutating func visitLoop(blockType: WasmParserCore.BlockType) throws(WasmKitError) -> Output { let blockType = try module.resolveBlockType(blockType) preserveOnStack(depth: blockType.parameters.count) iseqBuilder.resetLastEmission() @@ -1368,7 +1364,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { ) } - mutating func visitIf(blockType: WasmParser.BlockType) throws(WasmKitError) -> Output { + mutating func visitIf(blockType: WasmParserCore.BlockType) throws(WasmKitError) -> Output { // Pop condition value let condition = try popVRegOperand(.i32) let blockType = try module.resolveBlockType(blockType) @@ -1622,7 +1618,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { try popPushValues(frame.copyTypes) } - mutating func visitBrTable(targets: WasmParser.BrTable) throws(WasmKitError) -> Output { + mutating func visitBrTable(targets: WasmParserCore.BrTable) throws(WasmKitError) -> Output { guard let index = try popVRegOperand(.i32) else { return } let defaultFrame = try controlStack.branchTarget(relativeDepth: targets.defaultIndex) @@ -1877,7 +1873,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { try markUnreachable() } - mutating func visitTryTable(blockType: WasmParser.BlockType, tryCatch: WasmParser.TryCatch) throws(WasmKitError) -> Output { + mutating func visitTryTable(blockType: WasmParserCore.BlockType, tryCatch: WasmParserCore.TryCatch) throws(WasmKitError) -> Output { let blockType = try module.resolveBlockType(blockType) let endLabel = iseqBuilder.allocLabel() @@ -2223,7 +2219,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { } } - mutating func visitLoad(_ load: WasmParser.Instruction.Load, memarg: MemArg) throws(WasmKitError) { + mutating func visitLoad(_ load: WasmParserCore.Instruction.Load, memarg: MemArg) throws(WasmKitError) { let instruction: (Instruction.LoadOperand) -> Instruction switch load { case .i32Load: instruction = Instruction.i32Load @@ -2272,7 +2268,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { try visitLoad(memarg, load.type, load.naturalAlignment, instruction) } - mutating func visitStore(_ store: WasmParser.Instruction.Store, memarg: MemArg) throws(WasmKitError) { + mutating func visitStore(_ store: WasmParserCore.Instruction.Store, memarg: MemArg) throws(WasmKitError) { let instruction: (Instruction.StoreOperand) -> Instruction switch store { case .i32Store: instruction = Instruction.i32Store @@ -2343,7 +2339,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { } } - mutating func visitSimd(_ simd: WasmParser.Instruction.Simd) throws(WasmKitError) { + mutating func visitSimd(_ simd: WasmParserCore.Instruction.Simd) throws(WasmKitError) { guard let opcode = SIMDOpcode.fromSimd(simd) else { preconditionFailure("missing SIMDOpcode mapping: \(simd)") } func emitUnaryV128() throws(WasmKitError) { try popPushEmit(.v128, .v128) { v0, result in @@ -2455,7 +2451,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { } } - mutating func visitSimdLane(_ simdLane: WasmParser.Instruction.SimdLane, lane: UInt8) throws(WasmKitError) { + mutating func visitSimdLane(_ simdLane: WasmParserCore.Instruction.SimdLane, lane: UInt8) throws(WasmKitError) { guard let opcode = SIMDOpcode.fromSimdLane(simdLane) else { preconditionFailure("missing SIMDOpcode mapping: \(simdLane)") } let laneCount: UInt8 switch simdLane { @@ -2507,7 +2503,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { } } - mutating func visitSimdMemLane(_ simdMemLane: WasmParser.Instruction.SimdMemLane, memarg: MemArg, lane: UInt8) throws(WasmKitError) { + mutating func visitSimdMemLane(_ simdMemLane: WasmParserCore.Instruction.SimdMemLane, memarg: MemArg, lane: UInt8) throws(WasmKitError) { let isMemory64 = try module.isMemory64(memoryIndex: 0) guard let opcode = SIMDOpcode.fromSimdMemLane(simdMemLane) else { preconditionFailure("missing SIMDOpcode mapping: \(simdMemLane)") } let naturalAlignment: Int @@ -2629,7 +2625,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { .i32Eqz(Instruction.UnaryOperand(result: LVReg(result), input: LVReg(value))) } } - mutating func visitCmp(_ cmp: WasmParser.Instruction.Cmp) throws(WasmKitError) { + mutating func visitCmp(_ cmp: WasmParserCore.Instruction.Cmp) throws(WasmKitError) { let operand: ValueType let instruction: (Instruction.BinaryOperand) -> Instruction switch cmp { @@ -2668,7 +2664,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { } try visitCmp(operand, instruction) } - public mutating func visitBinary(_ binary: WasmParser.Instruction.Binary) throws(WasmKitError) { + public mutating func visitBinary(_ binary: WasmParserCore.Instruction.Binary) throws(WasmKitError) { let operand: ValueType let result: ValueType let instruction: (Instruction.BinaryOperand) -> Instruction @@ -2725,7 +2721,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { .i64Eqz(Instruction.UnaryOperand(result: LVReg(result), input: LVReg(value))) } } - mutating func visitUnary(_ unary: WasmParser.Instruction.Unary) throws(WasmKitError) { + mutating func visitUnary(_ unary: WasmParserCore.Instruction.Unary) throws(WasmKitError) { let operand: ValueType let instruction: (Instruction.UnaryOperand) -> Instruction switch unary { @@ -2757,7 +2753,7 @@ struct InstructionTranslator: ~Copyable, InstructionVisitor { } try visitUnary(operand, instruction) } - mutating func visitConversion(_ conversion: WasmParser.Instruction.Conversion) throws(WasmKitError) { + mutating func visitConversion(_ conversion: WasmParserCore.Instruction.Conversion) throws(WasmKitError) { let from: ValueType let to: ValueType let instruction: (Instruction.UnaryOperand) -> Instruction @@ -3385,7 +3381,7 @@ extension InstructionTranslator.MetaValue { } extension FunctionType { - fileprivate init(blockType: WasmParser.BlockType, typeSection: [FunctionType]) throws(WasmKitError) { + fileprivate init(blockType: WasmParserCore.BlockType, typeSection: [FunctionType]) throws(WasmKitError) { switch blockType { case .type(let valueType): self.init(parameters: [], results: [valueType]) diff --git a/Sources/WasmKit/Validator.swift b/Sources/WasmKit/Validator.swift index be8598c0..f67e55d0 100644 --- a/Sources/WasmKit/Validator.swift +++ b/Sources/WasmKit/Validator.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore /// Validates instructions within a given context. struct InstructionValidator { diff --git a/Sources/WasmKit/WasmKitError.swift b/Sources/WasmKit/WasmKitError.swift index d9c260c4..5fc651ff 100644 --- a/Sources/WasmKit/WasmKitError.swift +++ b/Sources/WasmKit/WasmKitError.swift @@ -1,4 +1,4 @@ -import WasmParser +import WasmParserCore import WasmTypes /// A unified error type for the WasmKit module, encompassing validation, translation, @@ -48,6 +48,21 @@ extension WasmKitError { } } +extension WasmKitError { + #if $Embedded + /// Convert a Trap into a WasmKitError in Embedded mode where Trap has no + /// CustomStringConvertible conformance. Extracts the text from the reason + /// or falls back to a generic message. + @usableFromInline + package init(_ trap: Trap) { + switch trap.reason { + case .message(let m): self.init(m.text) + default: self.init("trap") + } + } + #endif +} + extension WasmKitError { /// Wrap a closure that throws WasmParserError into one that throws WasmKitError. @usableFromInline @@ -60,6 +75,7 @@ extension WasmKitError { } } +#if !$Embedded extension WasmKitError: CustomStringConvertible { public var description: String { switch self.kind { @@ -74,6 +90,7 @@ extension WasmKitError: CustomStringConvertible { } } } +#endif // !$Embedded // MARK: - Validation Messages @@ -206,8 +223,12 @@ extension WasmKitError.Message { } static func expectedTypeOnStackButEmpty(expected: ValueType?) -> Self { + #if !$Embedded let typeHint = expected.map(String.init(describing:)) ?? "a value" return Self("expected \(typeHint) on the stack top but it's empty") + #else + return Self("expected value on the stack top but it's empty") + #endif } static func expectedMoreEndInstructions(count: Int) -> Self { @@ -245,7 +266,7 @@ extension WasmKitError.Message { Self("expect `end` at the end of offset expression") } - static func illegalConstExpressionInstruction(_ constInst: WasmParser.Instruction) -> Self { + static func illegalConstExpressionInstruction(_ constInst: WasmParserCore.Instruction) -> Self { Self("illegal const expression instruction: \(constInst)") } diff --git a/Sources/WasmParser/Stream/FileHandleStream.swift b/Sources/WasmParser/Stream/FileHandleStream.swift index da4a87b6..882c8123 100644 --- a/Sources/WasmParser/Stream/FileHandleStream.swift +++ b/Sources/WasmParser/Stream/FileHandleStream.swift @@ -34,7 +34,7 @@ public final class FileHandleStream: ByteStream { @discardableResult public func consumeAny() throws(WasmParserError) -> UInt8 { guard let consumed = try peek() else { - throw WasmParserError(message: .unexpectedEnd, offset: currentIndex) + throw WasmParserError(kind: .parserUnexpectedEnd(expected: nil), offset: currentIndex) } currentIndex = bytes.index(after: currentIndex) return consumed diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index a223f25f..9be7f640 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -1,5 +1,6 @@ import SystemExtras import WasmTypes +@_exported import WasmParserCore import struct SystemPackage.FileDescriptor import struct SystemPackage.FilePath @@ -8,53 +9,6 @@ import struct SystemPackage.FilePath import ucrt #endif -/// A streaming parser for WebAssembly binary format. -/// -/// The parser is designed to be used to incrementally parse a WebAssembly binary bytestream. -public struct Parser { - @usableFromInline - let stream: Stream - @usableFromInline let limits: ParsingLimits - @usableFromInline var orderTracking = OrderTracking() - - @usableFromInline - enum NextParseTarget { - case header - case section - } - @usableFromInline - var nextParseTarget: NextParseTarget - - public let features: WasmFeatureSet - public var offset: Int { - return stream.currentIndex - } - - public init(stream: Stream, features: WasmFeatureSet = .default) { - self.stream = stream - self.features = features - self.nextParseTarget = .header - self.limits = .default - } - - @usableFromInline - internal func makeError(_ message: WasmParserError.Message) -> WasmParserError { - return WasmParserError(message: message, offset: offset) - } -} - -extension Parser where Stream == StaticByteStream { - - /// Initialize a new parser with the given bytes - /// - /// - Parameters: - /// - bytes: The bytes of the WebAssembly binary file to parse - /// - features: Enabled WebAssembly features for parsing - public init(bytes: [UInt8], features: WasmFeatureSet = .default) { - self.init(stream: StaticByteStream(bytes: bytes), features: features) - } -} - extension Parser where Stream == FileHandleStream { /// Initialize a new parser with the given file handle @@ -85,1242 +39,6 @@ extension Parser where Stream == FileHandleStream { } } -@_documentation(visibility: internal) -public struct ExpressionParser { - /// The byte offset of the code in the module - let codeOffset: Int - /// The initial byte offset of the code buffer stream - /// NOTE: This might be different from `codeOffset` if the code buffer - /// is not a part of the initial `FileHandleStream` buffer - let initialStreamOffset: Int - @usableFromInline - var parser: Parser - - /// Whether the final `end` opcode has been returned. We track this explicitly - /// rather than checking `hasReachedEnd()` upfront because an exhausted stream - /// without a preceding `end` opcode is a validation error, not a normal exit. - @usableFromInline - var reachedEnd: Bool - - public var offset: Int { - self.codeOffset + self.parser.offset - self.initialStreamOffset - } - - public init(code: Code) { - self.parser = Parser( - stream: StaticByteStream(bytes: code.expression), - features: code.features - ) - self.codeOffset = code.offset - self.initialStreamOffset = self.parser.offset - self.reachedEnd = false - } - - /// Parse the next instruction. Returns nil when expression is complete (end opcode reached at top level). - @inlinable - public mutating func parse() throws(WasmParserError) -> Visit? { - if reachedEnd { return nil } - let instructionOffset = offset - let instruction = try parser.parseInstruction() - if case .end = instruction, try parser.stream.hasReachedEnd() { - reachedEnd = true - } - return Visit(instruction: instruction, offset: instructionOffset) - } - - /// A parsed instruction ready to be dispatched to a visitor. - public struct Visit { - @usableFromInline - let instruction: Instruction - @usableFromInline - let offset: Int - - @usableFromInline - init(instruction: Instruction, offset: Int) { - self.instruction = instruction - self.offset = offset - } - - @inlinable - public func callAsFunction( - visitor: inout V - ) throws(V.VisitorError) { - visitor.binaryOffset = offset - try dispatchInstruction(instruction, to: &visitor) - } - } -} - -let WASM_MAGIC: [UInt8] = [0x00, 0x61, 0x73, 0x6D] - -/// Flags for enabling/disabling WebAssembly features -public struct WasmFeatureSet: OptionSet, Sendable { - /// The raw value of the feature set - public let rawValue: Int - - /// Initialize a new feature set with the given raw value - public init(rawValue: Int) { - self.rawValue = rawValue - } - - /// The WebAssembly memory64 proposal - @_alwaysEmitIntoClient - public static var memory64: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 0) } - /// The WebAssembly reference types proposal - @_alwaysEmitIntoClient - public static var referenceTypes: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 1) } - /// The WebAssembly threads proposal - @_alwaysEmitIntoClient - public static var threads: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 2) } - /// The WebAssembly tail-call proposal - @_alwaysEmitIntoClient - public static var tailCall: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 3) } - /// The WebAssembly SIMD proposal - @_alwaysEmitIntoClient - public static var simd: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 4) } - /// The WebAssembly exception handling proposal - @_alwaysEmitIntoClient - public static var exceptionHandling: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 5) } - - /// The default feature set - public static let `default`: WasmFeatureSet = [.referenceTypes, .exceptionHandling] - /// The feature set with all features enabled - public static let all: WasmFeatureSet = [.memory64, .referenceTypes, .threads, .tailCall, .simd, .exceptionHandling] -} - -/// > Note: -/// -extension ByteStream { - @inlinable - func parseVector(content parser: () throws(WasmParserError) -> Content) throws(WasmParserError) -> [Content] { - var contents = [Content]() - let count: UInt32 = try parseUnsigned() - for _ in 0.. Note: -/// -extension ByteStream { - @inlinable - func parseUnsigned(_: T.Type = T.self) throws(WasmParserError) -> T { - try decodeLEB128(stream: self) - } - - @inlinable - func parseSigned() throws(WasmParserError) -> T { - try decodeLEB128(stream: self) - } - - @usableFromInline - func parseVarSigned33() throws(WasmParserError) -> Int64 { - try decodeLEB128(stream: self, bitWidth: 33) - } -} - -/// > Note: -/// -extension ByteStream { - package func parseName() throws(WasmParserError) -> String { - let bytes = try parseVector { () throws(WasmParserError) -> UInt8 in - try consumeAny() - } - - // TODO(optimize): Utilize ASCII fast path in UTF8 decoder - var name = "" - - var iterator = bytes.makeIterator() - var decoder = UTF8() - Decode: while true { - switch decoder.decode(&iterator) { - case .scalarValue(let scalar): name.append(Character(scalar)) - case .emptyInput: break Decode - case .error: throw WasmParserError(message: .invalidUTF8(bytes), offset: currentIndex) - } - } - - return name - } -} - -extension Parser { - @inlinable - func parseVector(content parser: () throws(WasmParserError) -> Content) throws(WasmParserError) -> [Content] { - try stream.parseVector(content: parser) - } - - @inline(__always) - @inlinable - func parseUnsigned(_: T.Type = T.self) throws(WasmParserError) -> T { - try stream.parseUnsigned(T.self) - } - - @inlinable - func parseInteger() throws(WasmParserError) -> T { - let signed: T.Signed = try stream.parseSigned() - return T(bitPattern: signed) - } - - func parseName() throws(WasmParserError) -> String { - try stream.parseName() - } -} - -/// > Note: -/// -extension Parser { - @usableFromInline - func parseFloat() throws(WasmParserError) -> UInt32 { - let consumedLittleEndian = try stream.consume(count: 4).reversed() - let bitPattern = consumedLittleEndian.reduce(UInt32(0)) { acc, byte in - acc << 8 + UInt32(byte) - } - return bitPattern - } - - @usableFromInline - func parseDouble() throws(WasmParserError) -> UInt64 { - let consumedLittleEndian = try stream.consume(count: 8).reversed() - let bitPattern = consumedLittleEndian.reduce(UInt64(0)) { acc, byte in - acc << 8 + UInt64(byte) - } - return bitPattern - } -} - -/// > Note: -/// -extension Parser { - /// > Note: - /// - @usableFromInline - func parseValueType() throws(WasmParserError) -> ValueType { - let b = try stream.consumeAny() - - switch b { - case 0x7F: return .i32 - case 0x7E: return .i64 - case 0x7D: return .f32 - case 0x7C: return .f64 - case 0x7B: return .v128 - default: - guard let refType = try parseReferenceType(byte: b) else { - throw makeError(.malformedValueType(b)) - } - return .ref(refType) - } - } - - /// - Returns: `nil` if the given `byte` discriminator is malformed - /// > Note: - /// - @usableFromInline - func parseReferenceType(byte: UInt8) throws(WasmParserError) -> ReferenceType? { - switch byte { - case 0x63: return try ReferenceType(isNullable: true, heapType: parseHeapType()) - case 0x64: return try ReferenceType(isNullable: false, heapType: parseHeapType()) - case 0x69: - guard features.contains(.exceptionHandling) else { return nil } - return .exnRef - case 0x6F: return .externRef - case 0x70: return .funcRef - default: return nil // invalid discriminator - } - } - - /// > Note: - /// - @usableFromInline - func parseHeapType() throws(WasmParserError) -> HeapType { - let b = try stream.peek() - switch b { - case 0x69: - _ = try stream.consumeAny() - return .exnRef - case 0x6F: - _ = try stream.consumeAny() - return .externRef - case 0x70: - _ = try stream.consumeAny() - return .funcRef - default: - let rawIndex = try stream.parseVarSigned33() - guard let index = TypeIndex(exactly: rawIndex) else { - throw makeError(.invalidFunctionType(rawIndex)) - } - return .concrete(typeIndex: index) - } - } - - /// > Note: - /// - @inlinable - func parseResultType() throws(WasmParserError) -> BlockType { - guard let nextByte = try stream.peek() else { - throw makeError(.unexpectedEnd) - } - switch nextByte { - case 0x40: - _ = try stream.consumeAny() - return .empty - case 0x7B...0x7F, 0x70, 0x6F, 0x69, 0x63, 0x64: - return try .type(parseValueType()) - default: - let rawIndex = try stream.parseVarSigned33() - guard let index = TypeIndex(exactly: rawIndex) else { - throw makeError(.invalidFunctionType(rawIndex)) - } - return .funcType(index) - } - } - - /// > Note: - /// - @inlinable - func parseFunctionType() throws(WasmParserError) -> FunctionType { - let opcode = try stream.consumeAny() - - // XXX: spectest expects the first byte should be parsed as a LEB128 with 1 byte limit - // but the spec itself doesn't require it, so just check the continue bit of LEB128 here. - guard opcode & 0b10000000 == 0 else { - throw makeError(.integerRepresentationTooLong) - } - guard opcode == 0x60 else { - throw makeError(.malformedFunctionType(opcode)) - } - - let parameters = try parseVector { () throws(WasmParserError) in try parseValueType() } - let results = try parseVector { () throws(WasmParserError) in try parseValueType() } - return FunctionType(parameters: parameters, results: results) - } - - /// > Note: - /// - @usableFromInline - func parseLimits() throws(WasmParserError) -> Limits { - let b = try stream.consumeAny() - let sharedMask: UInt8 = 0b0010 - let isMemory64Mask: UInt8 = 0b0100 - - let hasMax = b & 0b0001 != 0 - let shared = b & sharedMask != 0 - let isMemory64 = b & isMemory64Mask != 0 - - var flagMask: UInt8 = 0b0001 - if features.contains(.threads) { - flagMask |= sharedMask - } - if features.contains(.memory64) { - flagMask |= isMemory64Mask - } - guard (b & ~flagMask) == 0 else { - throw makeError(.malformedLimit(b)) - } - - let min: UInt64 - if isMemory64 { - min = try parseUnsigned(UInt64.self) - } else { - min = try UInt64(parseUnsigned(UInt32.self)) - } - var max: UInt64? - if hasMax { - if isMemory64 { - max = try parseUnsigned(UInt64.self) - } else { - max = try UInt64(parseUnsigned(UInt32.self)) - } - } - return Limits(min: min, max: max, isMemory64: isMemory64, shared: shared) - } - - /// > Note: - /// - func parseMemoryType() throws(WasmParserError) -> MemoryType { - return try parseLimits() - } - - /// > Note: - /// - @inlinable - func parseTableType() throws(WasmParserError) -> TableType { - let elementType: ReferenceType - let b = try stream.consumeAny() - - switch b { - case 0x70: - elementType = .funcRef - case 0x6F: - elementType = .externRef - default: - throw WasmParserError( - kind: .parserUnexpectedByte(b, expected: [0x6F, 0x70]), - offset: stream.currentIndex - ) - } - - let limits = try parseLimits() - return TableType(elementType: elementType, limits: limits) - } - - /// > Note: - /// - @inlinable - func parseGlobalType() throws(WasmParserError) -> GlobalType { - let valueType = try parseValueType() - let mutability = try parseMutability() - return GlobalType(mutability: mutability, valueType: valueType) - } - - @inlinable - func parseMutability() throws(WasmParserError) -> Mutability { - let b = try stream.consumeAny() - switch b { - case 0x00: - return .constant - case 0x01: - return .variable - default: - throw makeError(.malformedMutability(b)) - } - } - - /// > Note: - /// - @inlinable - func parseMemarg() throws(WasmParserError) -> MemArg { - let align: UInt32 = try parseUnsigned() - let offset: UInt64 = try features.contains(.memory64) ? parseUnsigned(UInt64.self) : UInt64(parseUnsigned(UInt32.self)) - return MemArg(offset: offset, align: align) - } - - @inlinable func parseVectorBytes() throws(WasmParserError) -> ArraySlice { - let count: UInt32 = try parseUnsigned() - return try stream.consume(count: Int(count)) - } -} - -/// > Note: -/// -extension Parser: BinaryInstructionDecoder { - @inlinable func parseMemoryIndex() throws(WasmParserError) -> UInt32 { - let zero = try stream.consumeAny() - guard zero == 0x00 else { - throw makeError(.zeroExpected(actual: zero)) - } - return 0 - } - - @inlinable func throwUnknown(_ opcode: [UInt8]) throws(WasmParserError) -> Never { - throw makeError(.illegalOpcode(opcode)) - } - - @inlinable func visitUnknown(_ opcode: [UInt8]) throws(WasmParserError) -> Bool { - try throwUnknown(opcode) - } - - @inlinable mutating func visitBlock() throws(WasmParserError) -> BlockType { try parseResultType() } - @inlinable mutating func visitLoop() throws(WasmParserError) -> BlockType { try parseResultType() } - @inlinable mutating func visitIf() throws(WasmParserError) -> BlockType { try parseResultType() } - @inlinable mutating func visitBr() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitBrIf() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitBrTable() throws(WasmParserError) -> BrTable { - let labelIndices: [UInt32] = try parseVector { () throws(WasmParserError) in try parseUnsigned() } - let labelIndex: UInt32 = try parseUnsigned() - return BrTable(labelIndices: labelIndices, defaultIndex: labelIndex) - } - @inlinable mutating func visitThrow() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitThrowRef() throws(WasmParserError) { /* no immediates */ } - @inlinable mutating func visitTryTable() throws(WasmParserError) -> (blockType: BlockType, tryCatch: TryCatch) { - let blockType = try parseResultType() - let catches: [CatchClause] = try parseVector { () throws(WasmParserError) in - let clauseId: UInt8 = try parseUnsigned() - switch clauseId { - case 0x00: - let tagIndex: UInt32 = try parseUnsigned() - let label: UInt32 = try parseUnsigned() - return .catch(tagIndex: tagIndex, labelIndex: label) - case 0x01: - let tagIndex: UInt32 = try parseUnsigned() - let label: UInt32 = try parseUnsigned() - return .catchRef(tagIndex: tagIndex, labelIndex: label) - case 0x02: - let label: UInt32 = try parseUnsigned() - return .catchAll(labelIndex: label) - case 0x03: - let label: UInt32 = try parseUnsigned() - return .catchAllRef(labelIndex: label) - default: - throw makeError(.invalidCatchClauseId(clauseId)) - } - } - return (blockType, TryCatch(catches: catches)) - } - @inlinable mutating func visitCall() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitCallRef() throws(WasmParserError) -> UInt32 { - // TODO reference types checks - // traps on nil - try parseUnsigned() - } - - @inlinable mutating func visitCallIndirect() throws(WasmParserError) -> (typeIndex: UInt32, tableIndex: UInt32) { - let typeIndex: TypeIndex = try parseUnsigned() - let peek = try stream.peek() - - if !features.contains(.referenceTypes) && peek != 0 { - // Check that reserved byte is zero when reference-types is disabled - throw makeError(.malformedIndirectCall) - } - let tableIndex: TableIndex = try parseUnsigned() - return (typeIndex, tableIndex) - } - - @inlinable mutating func visitReturnCall() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - - @inlinable mutating func visitReturnCallIndirect() throws(WasmParserError) -> (typeIndex: UInt32, tableIndex: UInt32) { - let typeIndex: TypeIndex = try parseUnsigned() - let tableIndex: TableIndex = try parseUnsigned() - return (typeIndex, tableIndex) - } - - @inlinable mutating func visitReturnCallRef() throws(WasmParserError) -> UInt32 { - return 0 - } - - @inlinable mutating func visitTypedSelect() throws(WasmParserError) -> WasmTypes.ValueType { - let results = try parseVector { () throws(WasmParserError) in try parseValueType() } - guard results.count == 1 else { - throw makeError(.invalidResultArity(expected: 1, actual: results.count)) - } - return results[0] - } - - @inlinable mutating func visitLocalGet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitLocalSet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitLocalTee() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitGlobalGet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitGlobalSet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitLoad(_: Instruction.Load) throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitStore(_: Instruction.Store) throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitMemorySize() throws(WasmParserError) -> UInt32 { - try parseMemoryIndex() - } - @inlinable mutating func visitMemoryGrow() throws(WasmParserError) -> UInt32 { - try parseMemoryIndex() - } - @inlinable mutating func visitI32Const() throws(WasmParserError) -> Int32 { - let n: UInt32 = try parseInteger() - return Int32(bitPattern: n) - } - @inlinable mutating func visitI64Const() throws(WasmParserError) -> Int64 { - let n: UInt64 = try parseInteger() - return Int64(bitPattern: n) - } - @inlinable mutating func visitF32Const() throws(WasmParserError) -> IEEE754.Float32 { - let n = try parseFloat() - return IEEE754.Float32(bitPattern: n) - } - @inlinable mutating func visitF64Const() throws(WasmParserError) -> IEEE754.Float64 { - let n = try parseDouble() - return IEEE754.Float64(bitPattern: n) - } - @inlinable mutating func visitRefNull() throws(WasmParserError) -> WasmTypes.HeapType { - return try parseHeapType() - } - @inlinable mutating func visitBrOnNull() throws(WasmParserError) -> UInt32 { - return 0 - } - @inlinable mutating func visitBrOnNonNull() throws(WasmParserError) -> UInt32 { - return 0 - } - - @inlinable mutating func visitRefFunc() throws(WasmParserError) -> UInt32 { try parseUnsigned() } - @inlinable mutating func visitMemoryInit() throws(WasmParserError) -> UInt32 { - let dataIndex: DataIndex = try parseUnsigned() - _ = try parseMemoryIndex() - return dataIndex - } - - @inlinable mutating func visitDataDrop() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - - @inlinable mutating func visitMemoryCopy() throws(WasmParserError) -> (dstMem: UInt32, srcMem: UInt32) { - _ = try parseMemoryIndex() - _ = try parseMemoryIndex() - return (0, 0) - } - - @inlinable mutating func visitMemoryFill() throws(WasmParserError) -> UInt32 { - let zero = try stream.consumeAny() - guard zero == 0x00 else { - throw makeError(.zeroExpected(actual: zero)) - } - return 0 - } - - @inlinable mutating func visitTableInit() throws(WasmParserError) -> (elemIndex: UInt32, table: UInt32) { - let elementIndex: ElementIndex = try parseUnsigned() - let tableIndex: TableIndex = try parseUnsigned() - return (elementIndex, tableIndex) - } - @inlinable mutating func visitElemDrop() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - @inlinable mutating func visitTableCopy() throws(WasmParserError) -> (dstTable: UInt32, srcTable: UInt32) { - let destination: TableIndex = try parseUnsigned() - let source: TableIndex = try parseUnsigned() - return (destination, source) - } - @inlinable mutating func visitTableFill() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - @inlinable mutating func visitTableGet() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - @inlinable mutating func visitTableSet() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - @inlinable mutating func visitTableGrow() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - @inlinable mutating func visitTableSize() throws(WasmParserError) -> UInt32 { - try parseUnsigned() - } - @inlinable mutating func visitMemoryAtomicNotify() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitMemoryAtomicWait32() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitMemoryAtomicWait64() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmwAdd() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmwAdd() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw8AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw16AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw8AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw16AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw32AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmwSub() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmwSub() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw8SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw16SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw8SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw16SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw32SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmwAnd() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmwAnd() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw8AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw16AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw8AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw16AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw32AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmwOr() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmwOr() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw8OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw16OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw8OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw16OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw32OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmwXor() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmwXor() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw8XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw16XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw8XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw16XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw32XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmwXchg() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmwXchg() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw8XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw16XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw8XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw16XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw32XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmwCmpxchg() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmwCmpxchg() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw8CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI32AtomicRmw16CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw8CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw16CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitI64AtomicRmw32CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } - @inlinable mutating func visitV128Const() throws(WasmParserError) -> V128 { - return V128(bytes: Array(try stream.consume(count: V128.byteCount))) - } - @inlinable mutating func visitI8x16Shuffle() throws(WasmParserError) -> V128ShuffleMask { - return V128ShuffleMask(lanes: Array(try stream.consume(count: V128ShuffleMask.laneCount))) - } - @inlinable mutating func visitSimdLane(_: Instruction.SimdLane) throws(WasmParserError) -> UInt8 { - return try stream.consumeAny() - } - @inlinable mutating func visitSimdMemLane(_: Instruction.SimdMemLane) throws(WasmParserError) -> (memarg: MemArg, lane: UInt8) { - let memarg = try parseMemarg() - let lane = try stream.consumeAny() - return (memarg: memarg, lane: lane) - } - @inlinable func claimNextByte() throws(WasmParserError) -> UInt8 { - return try stream.consumeAny() - } - - /// Parse a single binary instruction. - @inline(__always) - @inlinable - mutating func parseInstruction() throws(WasmParserError) -> Instruction { - return try parseBinaryInstruction(decoder: &self) - } - - @usableFromInline - mutating func parseConstExpression() throws(WasmParserError) -> ConstExpression { - var insts: [Instruction] = [] - while true { - let instruction = try self.parseInstruction() - insts.append(instruction) - if case .end = instruction { break } - } - return insts - } -} - -/// > Note: -/// -extension Parser { - /// > Note: - /// - @usableFromInline - func parseCustomSection(size: UInt32) throws(WasmParserError) -> CustomSection { - let preNameIndex = stream.currentIndex - let name = try parseName() - let nameSize = stream.currentIndex - preNameIndex - let contentSize = Int(size) - nameSize - - guard contentSize >= 0 else { - throw makeError(.invalidSectionSize(size)) - } - - let bytes = try stream.consume(count: contentSize) - - return CustomSection(name: name, bytes: bytes) - } - - /// > Note: - /// - @inlinable - func parseTypeSection() throws(WasmParserError) -> [FunctionType] { - return try parseVector { () throws(WasmParserError) in try parseFunctionType() } - } - - /// > Note: - /// - @usableFromInline - func parseImportSection() throws(WasmParserError) -> [Import] { - return try parseVector { () throws(WasmParserError) in - let module = try parseName() - let name = try parseName() - let descriptor = try parseImportDescriptor() - return Import(module: module, name: name, descriptor: descriptor) - } - } - - /// > Note: - /// - func parseImportDescriptor() throws(WasmParserError) -> ImportDescriptor { - let maxKind: UInt8 = features.contains(.exceptionHandling) ? 0x04 : 0x03 - let b = try stream.consume(Set(0x00...maxKind)) - switch b { - case 0x00: return try .function(parseUnsigned()) - case 0x01: return try .table(parseTableType()) - case 0x02: return try .memory(parseMemoryType()) - case 0x03: return try .global(parseGlobalType()) - case 0x04: - let attribute: UInt8 = try parseUnsigned() - guard attribute == 0 else { throw makeError(.invalidTagAttribute(attribute)) } - return try .tag(parseUnsigned()) - default: - preconditionFailure("should never reach here") - } - } - - /// > Note: - /// - @inlinable - func parseFunctionSection() throws(WasmParserError) -> [TypeIndex] { - return try parseVector { () throws(WasmParserError) in try parseUnsigned() } - } - - /// > Note: - /// - @usableFromInline - func parseTableSection() throws(WasmParserError) -> [Table] { - return try parseVector { () throws(WasmParserError) in try Table(type: parseTableType()) } - } - - /// > Note: - /// - @usableFromInline - func parseMemorySection() throws(WasmParserError) -> [Memory] { - return try parseVector { () throws(WasmParserError) in try Memory(type: parseLimits()) } - } - - /// > Note: - /// - @usableFromInline - mutating func parseGlobalSection() throws(WasmParserError) -> [Global] { - return try parseVector { () throws(WasmParserError) in - let type = try parseGlobalType() - let expression = try parseConstExpression() - return Global(type: type, initializer: expression) - } - } - - /// > Note: - /// - @usableFromInline - func parseTagSection() throws(WasmParserError) -> [Tag] { - return try parseVector { () throws(WasmParserError) in - let attribute: UInt8 = try parseUnsigned() - guard attribute == 0 else { throw makeError(.invalidTagAttribute(attribute)) } - let typeIndex: TypeIndex = try parseUnsigned() - return Tag(type: typeIndex) - } - } - - /// > Note: - /// - @usableFromInline - func parseExportSection() throws(WasmParserError) -> [Export] { - return try parseVector { () throws(WasmParserError) in - let name = try parseName() - let descriptor = try parseExportDescriptor() - return Export(name: name, descriptor: descriptor) - } - } - - /// > Note: - /// - func parseExportDescriptor() throws(WasmParserError) -> ExportDescriptor { - let maxKind: UInt8 = features.contains(.exceptionHandling) ? 0x04 : 0x03 - let b = try stream.consume(Set(0x00...maxKind)) - switch b { - case 0x00: return try .function(parseUnsigned()) - case 0x01: return try .table(parseUnsigned()) - case 0x02: return try .memory(parseUnsigned()) - case 0x03: return try .global(parseUnsigned()) - case 0x04: return try .tag(parseUnsigned()) - default: - preconditionFailure("should never reach here") - } - } - - /// > Note: - /// - @usableFromInline - func parseStartSection() throws(WasmParserError) -> FunctionIndex { - return try parseUnsigned() - } - - /// > Note: - /// - @inlinable - mutating func parseElementSection() throws(WasmParserError) -> [ElementSegment] { - return try parseVector { () throws(WasmParserError) in - let flag = try ElementSegment.Flag(rawValue: parseUnsigned()) - - let type: ReferenceType - let initializer: [ConstExpression] - let mode: ElementSegment.Mode - - if flag.contains(.isPassiveOrDeclarative) { - if flag.contains(.isDeclarative) { - mode = .declarative - } else { - mode = .passive - } - } else { - let table: TableIndex - - if flag.contains(.hasTableIndex) { - table = try parseUnsigned() - } else { - table = 0 - } - - let offset = try parseConstExpression() - mode = .active(table: table, offset: offset) - } - - if flag.segmentHasRefType { - let valueType = try parseValueType() - - guard case .ref(let refType) = valueType else { - throw makeError(.expectedRefType(actual: valueType)) - } - - type = refType - } else { - type = .funcRef - } - - if flag.segmentHasElemKind { - // `elemkind` parsing as defined in the spec - let elemKind = try parseUnsigned() as UInt32 - guard elemKind == 0x00 else { - throw makeError(.unexpectedElementKind(expected: 0x00, actual: elemKind)) - } - } - - if flag.contains(.usesExpressions) { - initializer = try parseVector { () throws(WasmParserError) in try parseConstExpression() } - } else { - initializer = try parseVector { () throws(WasmParserError) in - try [Instruction.refFunc(functionIndex: parseUnsigned() as UInt32)] - } - } - - return ElementSegment(type: type, initializer: initializer, mode: mode) - } - } - - /// > Note: - /// - @inlinable - func parseCodeSection() throws(WasmParserError) -> [Code] { - return try parseVector { () throws(WasmParserError) in - let size = try parseUnsigned() as UInt32 - let bodyStart = stream.currentIndex - let localTypes = try parseVector { () throws(WasmParserError) -> (n: UInt32, type: ValueType) in - let n: UInt32 = try parseUnsigned() - let t = try parseValueType() - return (n, t) - } - let totalLocals = localTypes.reduce(UInt64(0)) { $0 + UInt64($1.n) } - guard totalLocals < limits.maxFunctionLocals else { - throw makeError(.tooManyLocals(totalLocals, limit: limits.maxFunctionLocals)) - } - - let locals = localTypes.flatMap { (n: UInt32, type: ValueType) in - return Array(repeating: type, count: Int(n)) - } - let expressionStart = stream.currentIndex - let expressionBytes = try stream.consume( - count: Int(size) - (expressionStart - bodyStart) - ) - return Code( - locals: locals, expression: expressionBytes, - offset: expressionStart, features: features - ) - } - } - - /// > Note: - /// - @inlinable - mutating func parseDataSection() throws(WasmParserError) -> [DataSegment] { - return try parseVector { () throws(WasmParserError) in - let kind: UInt32 = try parseUnsigned() - switch kind { - case 0: - let offset = try parseConstExpression() - let initializer = try parseVectorBytes() - return .active(.init(index: 0, offset: offset, initializer: initializer)) - - case 1: - return try .passive(parseVectorBytes()) - - case 2: - let index: UInt32 = try parseUnsigned() - let offset = try parseConstExpression() - let initializer = try parseVectorBytes() - return .active(.init(index: index, offset: offset, initializer: initializer)) - default: - throw makeError(.malformedDataSegmentKind(kind)) - } - } - } - - /// > Note: - /// - @usableFromInline - func parseDataCountSection() throws(WasmParserError) -> UInt32 { - return try parseUnsigned() - } -} - -public enum ParsingPayload { - case header(version: [UInt8]) - case customSection(CustomSection) - case typeSection([FunctionType]) - case importSection([Import]) - case functionSection([TypeIndex]) - case tableSection([Table]) - case memorySection([Memory]) - case globalSection([Global]) - case tagSection([Tag]) - case exportSection([Export]) - case startSection(FunctionIndex) - case elementSection([ElementSegment]) - case codeSection([Code]) - case dataSection([DataSegment]) - case dataCount(UInt32) -} - -/// > Note: -/// -extension Parser { - /// > Note: - /// - @usableFromInline - func parseMagicNumber() throws(WasmParserError) { - let magicNumber = try stream.consume(count: 4) - guard magicNumber.elementsEqual(WASM_MAGIC) else { - throw makeError(.invalidMagicNumber(.init(magicNumber))) - } - } - - /// > Note: - /// - @usableFromInline - func parseVersion() throws(WasmParserError) -> [UInt8] { - let version = try Array(stream.consume(count: 4)) - guard version == [0x01, 0x00, 0x00, 0x00] else { - throw makeError(.unknownVersion(.init(version))) - } - return version - } - - @usableFromInline - struct OrderTracking { - @usableFromInline - enum Order: UInt8 { - case initial = 0 - case type - case _import - case function - case table - case memory - case tag - case global - case export - case start - case element - case dataCount - case code - case data - } - - @usableFromInline - var last: Order = .initial - - @inlinable - mutating func track(order: Order, parser: Parser) throws(WasmParserError) { - guard last.rawValue < order.rawValue else { - throw parser.makeError(.sectionOutOfOrder) - } - last = order - } - } - - /// Attempts to parse a chunk of the Wasm binary stream. - /// - /// - Returns: A `ParsingPayload` if the parsing was successful, otherwise `nil`. - /// - /// > Note: - /// - /// - /// The following example demonstrates how to use the `Parser` to parse a Wasm binary stream: - /// - /// ```swift - /// import WasmParser - /// - /// var parser = Parser(bytes: [ - /// 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, - /// 0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01, 0x03, - /// 0x66, 0x61, 0x63, 0x00, 0x00, 0x0a, 0x17, 0x01, 0x15, 0x00, 0x20, 0x00, - /// 0x50, 0x04, 0x7e, 0x42, 0x01, 0x05, 0x20, 0x00, 0x20, 0x00, 0x42, 0x01, - /// 0x7d, 0x10, 0x00, 0x7e, 0x0b, 0x0b - /// ]) - /// - /// while let payload = try parser.parseNext() { - /// switch payload { - /// case .header(let version): - /// print("Wasm version: \(version)") - /// default: break - /// } - /// } - /// ``` - @inlinable - public mutating func parseNext() throws(WasmParserError) -> ParsingPayload? { - switch nextParseTarget { - case .header: - try parseMagicNumber() - let version = try parseVersion() - self.nextParseTarget = .section - return .header(version: version) - case .section: - guard try !stream.hasReachedEnd() else { - return nil - } - let sectionID = try stream.consumeAny() - let sectionSize: UInt32 = try parseUnsigned() - let sectionStart = stream.currentIndex - - let payload: ParsingPayload - let order: OrderTracking.Order? - switch sectionID { - case 0: - order = nil - payload = .customSection(try parseCustomSection(size: sectionSize)) - case 1: - order = .type - payload = .typeSection(try parseTypeSection()) - case 2: - order = ._import - payload = .importSection(try parseImportSection()) - case 3: - order = .function - payload = .functionSection(try parseFunctionSection()) - case 4: - order = .table - payload = .tableSection(try parseTableSection()) - case 5: - order = .memory - payload = .memorySection(try parseMemorySection()) - case 6: - order = .global - payload = .globalSection(try parseGlobalSection()) - case 7: - order = .export - payload = .exportSection(try parseExportSection()) - case 8: - order = .start - payload = .startSection(try parseStartSection()) - case 9: - order = .element - payload = .elementSection(try parseElementSection()) - case 10: - order = .code - payload = .codeSection(try parseCodeSection()) - case 11: - order = .data - payload = .dataSection(try parseDataSection()) - case 12: - order = .dataCount - payload = .dataCount(try parseDataCountSection()) - case 13 where features.contains(.exceptionHandling): - order = .tag - payload = .tagSection(try parseTagSection()) - default: - throw makeError(.malformedSectionID(sectionID)) - } - if let order = order { - try orderTracking.track(order: order, parser: self) - } - let expectedSectionEnd = sectionStart + Int(sectionSize) - guard expectedSectionEnd == stream.currentIndex else { - throw makeError( - .sectionSizeMismatch( - sectionID: sectionID, - expected: expectedSectionEnd, - actual: offset - ) - ) - } - return payload - } - } -} - -/// A map of names by its index. -public typealias NameMap = [UInt32: String] - -/// Parsed names from a name section subsection. -public enum ParsedNames { - /// Subsection 0: Module name. - case moduleName(String) - /// Subsection 1: Function names. - case functions(NameMap) - /// Subsection 2: Local names (funcIndex → [localIndex → name]). - case locals([UInt32: NameMap]) - /// Subsection 3: Label names (funcIndex → [labelIndex → name]). - case labels([UInt32: NameMap]) - /// Subsection 4: Type names. - case types(NameMap) - /// Subsection 5: Table names. - case tables(NameMap) - /// Subsection 6: Memory names. - case memories(NameMap) - /// Subsection 7: Global names. - case globals(NameMap) - /// Subsection 8: Element segment names. - case elements(NameMap) - /// Subsection 9: Data segment names. - case dataSegments(NameMap) -} - -/// A parser for the name custom section. -/// -/// > Note: -public struct NameSectionParser { - let stream: Stream - - public init(stream: Stream) { - self.stream = stream - } - - /// Parses the entire name section. - /// - /// - Throws: If the stream is malformed or the section is invalid. - /// - Returns: A list of parsed names. - public func parseAll() throws(WasmParserError) -> [ParsedNames] { - var results: [ParsedNames] = [] - while try !stream.hasReachedEnd() { - let id = try stream.consumeAny() - guard let result = try parseNameSubsection(type: id) else { - continue - } - results.append(result) - } - return results - } - - func parseNameSubsection(type: UInt8) throws(WasmParserError) -> ParsedNames? { - let size = try stream.parseUnsigned(UInt32.self) - switch type { - case 0: return .moduleName(try stream.parseName()) - case 1: return .functions(try parseNameMap()) - case 2: return .locals(try parseIndirectNameMap()) - case 3: return .labels(try parseIndirectNameMap()) - case 4: return .types(try parseNameMap()) - case 5: return .tables(try parseNameMap()) - case 6: return .memories(try parseNameMap()) - case 7: return .globals(try parseNameMap()) - case 8: return .elements(try parseNameMap()) - case 9: return .dataSegments(try parseNameMap()) - default: - _ = try stream.consume(count: Int(size)) - return nil - } - } - - func parseNameMap() throws(WasmParserError) -> NameMap { - var nameMap: NameMap = [:] - _ = try stream.parseVector { () throws(WasmParserError) in - let index = try stream.parseUnsigned(UInt32.self) - let name = try stream.parseName() - nameMap[index] = name - } - return nameMap - } - - func parseIndirectNameMap() throws(WasmParserError) -> [UInt32: NameMap] { - var map: [UInt32: NameMap] = [:] - _ = try stream.parseVector { () throws(WasmParserError) in - let outerIndex = try stream.parseUnsigned(UInt32.self) - map[outerIndex] = try parseNameMap() - } - return map - } -} - // MARK: - File Type Detection /// The type of a WebAssembly binary file. diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParserCore/BinaryInstructionDecoder.swift similarity index 100% rename from Sources/WasmParser/BinaryInstructionDecoder.swift rename to Sources/WasmParserCore/BinaryInstructionDecoder.swift diff --git a/Sources/WasmParser/ComponentParser.swift b/Sources/WasmParserCore/ComponentParser.swift similarity index 100% rename from Sources/WasmParser/ComponentParser.swift rename to Sources/WasmParserCore/ComponentParser.swift diff --git a/Sources/WasmParser/InstructionVisitor.swift b/Sources/WasmParserCore/InstructionVisitor.swift similarity index 100% rename from Sources/WasmParser/InstructionVisitor.swift rename to Sources/WasmParserCore/InstructionVisitor.swift diff --git a/Sources/WasmParser/LEB.swift b/Sources/WasmParserCore/LEB.swift similarity index 100% rename from Sources/WasmParser/LEB.swift rename to Sources/WasmParserCore/LEB.swift diff --git a/Sources/WasmParser/ParsingLimits.swift b/Sources/WasmParserCore/ParsingLimits.swift similarity index 100% rename from Sources/WasmParser/ParsingLimits.swift rename to Sources/WasmParserCore/ParsingLimits.swift diff --git a/Sources/WasmParser/Stream/ByteStream.swift b/Sources/WasmParserCore/Stream/ByteStream.swift similarity index 100% rename from Sources/WasmParser/Stream/ByteStream.swift rename to Sources/WasmParserCore/Stream/ByteStream.swift diff --git a/Sources/WasmParserCore/WasmParserCore.swift b/Sources/WasmParserCore/WasmParserCore.swift new file mode 100644 index 00000000..7c6aefa9 --- /dev/null +++ b/Sources/WasmParserCore/WasmParserCore.swift @@ -0,0 +1,1292 @@ +import WasmTypes + +/// A streaming parser for WebAssembly binary format. +/// +/// The parser is designed to be used to incrementally parse a WebAssembly binary bytestream. +public struct Parser { + @usableFromInline + let stream: Stream + @usableFromInline let limits: ParsingLimits + @usableFromInline var orderTracking = OrderTracking() + + @usableFromInline + enum NextParseTarget { + case header + case section + } + @usableFromInline + var nextParseTarget: NextParseTarget + + public let features: WasmFeatureSet + public var offset: Int { + return stream.currentIndex + } + + public init(stream: Stream, features: WasmFeatureSet = .default) { + self.stream = stream + self.features = features + self.nextParseTarget = .header + self.limits = .default + } + + @usableFromInline + internal func makeError(_ message: WasmParserError.Message) -> WasmParserError { + return WasmParserError(message: message, offset: offset) + } +} + +extension Parser where Stream == StaticByteStream { + + /// Initialize a new parser with the given bytes + /// + /// - Parameters: + /// - bytes: The bytes of the WebAssembly binary file to parse + /// - features: Enabled WebAssembly features for parsing + public init(bytes: [UInt8], features: WasmFeatureSet = .default) { + self.init(stream: StaticByteStream(bytes: bytes), features: features) + } +} + +@_documentation(visibility: internal) +public struct ExpressionParser { + /// The byte offset of the code in the module + let codeOffset: Int + /// The initial byte offset of the code buffer stream + /// NOTE: This might be different from `codeOffset` if the code buffer + /// is not a part of the initial `FileHandleStream` buffer + let initialStreamOffset: Int + @usableFromInline + var parser: Parser + + /// Whether the final `end` opcode has been returned. We track this explicitly + /// rather than checking `hasReachedEnd()` upfront because an exhausted stream + /// without a preceding `end` opcode is a validation error, not a normal exit. + @usableFromInline + var reachedEnd: Bool + + public var offset: Int { + self.codeOffset + self.parser.offset - self.initialStreamOffset + } + + public init(code: Code) { + self.parser = Parser( + stream: StaticByteStream(bytes: code.expression), + features: code.features + ) + self.codeOffset = code.offset + self.initialStreamOffset = self.parser.offset + self.reachedEnd = false + } + + /// Parse the next instruction. Returns nil when expression is complete (end opcode reached at top level). + @inlinable + public mutating func parse() throws(WasmParserError) -> Visit? { + if reachedEnd { return nil } + let instructionOffset = offset + let instruction = try parser.parseInstruction() + if case .end = instruction, try parser.stream.hasReachedEnd() { + reachedEnd = true + } + return Visit(instruction: instruction, offset: instructionOffset) + } + + /// A parsed instruction ready to be dispatched to a visitor. + public struct Visit { + @usableFromInline + let instruction: Instruction + @usableFromInline + let offset: Int + + @usableFromInline + init(instruction: Instruction, offset: Int) { + self.instruction = instruction + self.offset = offset + } + + @inlinable + public func callAsFunction( + visitor: inout V + ) throws(V.VisitorError) { + visitor.binaryOffset = offset + try dispatchInstruction(instruction, to: &visitor) + } + } +} + +package let WASM_MAGIC: [UInt8] = [0x00, 0x61, 0x73, 0x6D] + +/// Flags for enabling/disabling WebAssembly features +public struct WasmFeatureSet: OptionSet, Sendable { + /// The raw value of the feature set + public let rawValue: Int + + /// Initialize a new feature set with the given raw value + public init(rawValue: Int) { + self.rawValue = rawValue + } + + /// The WebAssembly memory64 proposal + @_alwaysEmitIntoClient + public static var memory64: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 0) } + /// The WebAssembly reference types proposal + @_alwaysEmitIntoClient + public static var referenceTypes: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 1) } + /// The WebAssembly threads proposal + @_alwaysEmitIntoClient + public static var threads: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 2) } + /// The WebAssembly tail-call proposal + @_alwaysEmitIntoClient + public static var tailCall: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 3) } + /// The WebAssembly SIMD proposal + @_alwaysEmitIntoClient + public static var simd: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 4) } + /// The WebAssembly exception handling proposal + @_alwaysEmitIntoClient + public static var exceptionHandling: WasmFeatureSet { WasmFeatureSet(rawValue: 1 << 5) } + + /// The default feature set + public static let `default`: WasmFeatureSet = [.referenceTypes, .exceptionHandling] + /// The feature set with all features enabled + public static let all: WasmFeatureSet = [.memory64, .referenceTypes, .threads, .tailCall, .simd, .exceptionHandling] +} + +/// > Note: +/// +extension ByteStream { + @inlinable + func parseVector(content parser: () throws(WasmParserError) -> Content) throws(WasmParserError) -> [Content] { + var contents = [Content]() + let count: UInt32 = try parseUnsigned() + for _ in 0.. Note: +/// +extension ByteStream { + @inlinable + func parseUnsigned(_: T.Type = T.self) throws(WasmParserError) -> T { + try decodeLEB128(stream: self) + } + + @inlinable + func parseSigned() throws(WasmParserError) -> T { + try decodeLEB128(stream: self) + } + + @usableFromInline + func parseVarSigned33() throws(WasmParserError) -> Int64 { + try decodeLEB128(stream: self, bitWidth: 33) + } +} + +/// > Note: +/// +extension ByteStream { + package func parseName() throws(WasmParserError) -> String { + let bytes = try parseVector { () throws(WasmParserError) -> UInt8 in + try consumeAny() + } + + #if $Embedded + // Embedded Swift fast path: create String directly from UTF-8 bytes. + // Avoids the character-by-character append loop which uses Unicode scalar + // handling and pulls in NFC normalization machinery (~31 KB of tables). + guard let name = String(validating: bytes, as: UTF8.self) else { + throw WasmParserError(message: .invalidUTF8(bytes), offset: currentIndex) + } + return name + #else + // TODO(optimize): Utilize ASCII fast path in UTF8 decoder + var name = "" + var iterator = bytes.makeIterator() + var decoder = UTF8() + Decode: while true { + switch decoder.decode(&iterator) { + case .scalarValue(let scalar): name.append(Character(scalar)) + case .emptyInput: break Decode + case .error: throw WasmParserError(message: .invalidUTF8(bytes), offset: currentIndex) + } + } + return name + #endif + } +} + +extension Parser { + @inlinable + func parseVector(content parser: () throws(WasmParserError) -> Content) throws(WasmParserError) -> [Content] { + try stream.parseVector(content: parser) + } + + @inline(__always) + @inlinable + func parseUnsigned(_: T.Type = T.self) throws(WasmParserError) -> T { + try stream.parseUnsigned(T.self) + } + + @inlinable + func parseInteger() throws(WasmParserError) -> T { + let signed: T.Signed = try stream.parseSigned() + return T(bitPattern: signed) + } + + func parseName() throws(WasmParserError) -> String { + try stream.parseName() + } +} + +/// > Note: +/// +extension Parser { + @usableFromInline + func parseFloat() throws(WasmParserError) -> UInt32 { + let consumedLittleEndian = try stream.consume(count: 4).reversed() + let bitPattern = consumedLittleEndian.reduce(UInt32(0)) { acc, byte in + acc << 8 + UInt32(byte) + } + return bitPattern + } + + @usableFromInline + func parseDouble() throws(WasmParserError) -> UInt64 { + let consumedLittleEndian = try stream.consume(count: 8).reversed() + let bitPattern = consumedLittleEndian.reduce(UInt64(0)) { acc, byte in + acc << 8 + UInt64(byte) + } + return bitPattern + } +} + +/// > Note: +/// +extension Parser { + /// > Note: + /// + @usableFromInline + func parseValueType() throws(WasmParserError) -> ValueType { + let b = try stream.consumeAny() + + switch b { + case 0x7F: return .i32 + case 0x7E: return .i64 + case 0x7D: return .f32 + case 0x7C: return .f64 + case 0x7B: return .v128 + default: + guard let refType = try parseReferenceType(byte: b) else { + throw makeError(.malformedValueType(b)) + } + return .ref(refType) + } + } + + /// - Returns: `nil` if the given `byte` discriminator is malformed + /// > Note: + /// + @usableFromInline + func parseReferenceType(byte: UInt8) throws(WasmParserError) -> ReferenceType? { + switch byte { + case 0x63: return try ReferenceType(isNullable: true, heapType: parseHeapType()) + case 0x64: return try ReferenceType(isNullable: false, heapType: parseHeapType()) + case 0x69: + guard features.contains(.exceptionHandling) else { return nil } + return .exnRef + case 0x6F: return .externRef + case 0x70: return .funcRef + default: return nil // invalid discriminator + } + } + + /// > Note: + /// + @usableFromInline + func parseHeapType() throws(WasmParserError) -> HeapType { + let b = try stream.peek() + switch b { + case 0x69: + _ = try stream.consumeAny() + return .exnRef + case 0x6F: + _ = try stream.consumeAny() + return .externRef + case 0x70: + _ = try stream.consumeAny() + return .funcRef + default: + let rawIndex = try stream.parseVarSigned33() + guard let index = TypeIndex(exactly: rawIndex) else { + throw makeError(.invalidFunctionType(rawIndex)) + } + return .concrete(typeIndex: index) + } + } + + /// > Note: + /// + @inlinable + func parseResultType() throws(WasmParserError) -> BlockType { + guard let nextByte = try stream.peek() else { + throw makeError(.unexpectedEnd) + } + switch nextByte { + case 0x40: + _ = try stream.consumeAny() + return .empty + case 0x7B...0x7F, 0x70, 0x6F, 0x69, 0x63, 0x64: + return try .type(parseValueType()) + default: + let rawIndex = try stream.parseVarSigned33() + guard let index = TypeIndex(exactly: rawIndex) else { + throw makeError(.invalidFunctionType(rawIndex)) + } + return .funcType(index) + } + } + + /// > Note: + /// + @inlinable + func parseFunctionType() throws(WasmParserError) -> FunctionType { + let opcode = try stream.consumeAny() + + // XXX: spectest expects the first byte should be parsed as a LEB128 with 1 byte limit + // but the spec itself doesn't require it, so just check the continue bit of LEB128 here. + guard opcode & 0b10000000 == 0 else { + throw makeError(.integerRepresentationTooLong) + } + guard opcode == 0x60 else { + throw makeError(.malformedFunctionType(opcode)) + } + + let parameters = try parseVector { () throws(WasmParserError) in try parseValueType() } + let results = try parseVector { () throws(WasmParserError) in try parseValueType() } + return FunctionType(parameters: parameters, results: results) + } + + /// > Note: + /// + @usableFromInline + func parseLimits() throws(WasmParserError) -> Limits { + let b = try stream.consumeAny() + let sharedMask: UInt8 = 0b0010 + let isMemory64Mask: UInt8 = 0b0100 + + let hasMax = b & 0b0001 != 0 + let shared = b & sharedMask != 0 + let isMemory64 = b & isMemory64Mask != 0 + + var flagMask: UInt8 = 0b0001 + if features.contains(.threads) { + flagMask |= sharedMask + } + if features.contains(.memory64) { + flagMask |= isMemory64Mask + } + guard (b & ~flagMask) == 0 else { + throw makeError(.malformedLimit(b)) + } + + let min: UInt64 + if isMemory64 { + min = try parseUnsigned(UInt64.self) + } else { + min = try UInt64(parseUnsigned(UInt32.self)) + } + var max: UInt64? + if hasMax { + if isMemory64 { + max = try parseUnsigned(UInt64.self) + } else { + max = try UInt64(parseUnsigned(UInt32.self)) + } + } + return Limits(min: min, max: max, isMemory64: isMemory64, shared: shared) + } + + /// > Note: + /// + func parseMemoryType() throws(WasmParserError) -> MemoryType { + return try parseLimits() + } + + /// > Note: + /// + @inlinable + func parseTableType() throws(WasmParserError) -> TableType { + let elementType: ReferenceType + let b = try stream.consumeAny() + + switch b { + case 0x70: + elementType = .funcRef + case 0x6F: + elementType = .externRef + default: + throw WasmParserError( + kind: .parserUnexpectedByte(b, expected: [0x6F, 0x70]), + offset: stream.currentIndex + ) + } + + let limits = try parseLimits() + return TableType(elementType: elementType, limits: limits) + } + + /// > Note: + /// + @inlinable + func parseGlobalType() throws(WasmParserError) -> GlobalType { + let valueType = try parseValueType() + let mutability = try parseMutability() + return GlobalType(mutability: mutability, valueType: valueType) + } + + @inlinable + func parseMutability() throws(WasmParserError) -> Mutability { + let b = try stream.consumeAny() + switch b { + case 0x00: + return .constant + case 0x01: + return .variable + default: + throw makeError(.malformedMutability(b)) + } + } + + /// > Note: + /// + @inlinable + func parseMemarg() throws(WasmParserError) -> MemArg { + let align: UInt32 = try parseUnsigned() + let offset: UInt64 = try features.contains(.memory64) ? parseUnsigned(UInt64.self) : UInt64(parseUnsigned(UInt32.self)) + return MemArg(offset: offset, align: align) + } + + @inlinable func parseVectorBytes() throws(WasmParserError) -> ArraySlice { + let count: UInt32 = try parseUnsigned() + return try stream.consume(count: Int(count)) + } +} + +/// > Note: +/// +extension Parser: BinaryInstructionDecoder { + @inlinable func parseMemoryIndex() throws(WasmParserError) -> UInt32 { + let zero = try stream.consumeAny() + guard zero == 0x00 else { + throw makeError(.zeroExpected(actual: zero)) + } + return 0 + } + + @inlinable func throwUnknown(_ opcode: [UInt8]) throws(WasmParserError) -> Never { + throw makeError(.illegalOpcode(opcode)) + } + + @inlinable func visitUnknown(_ opcode: [UInt8]) throws(WasmParserError) -> Bool { + try throwUnknown(opcode) + } + + @inlinable mutating func visitBlock() throws(WasmParserError) -> BlockType { try parseResultType() } + @inlinable mutating func visitLoop() throws(WasmParserError) -> BlockType { try parseResultType() } + @inlinable mutating func visitIf() throws(WasmParserError) -> BlockType { try parseResultType() } + @inlinable mutating func visitBr() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitBrIf() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitBrTable() throws(WasmParserError) -> BrTable { + let labelIndices: [UInt32] = try parseVector { () throws(WasmParserError) in try parseUnsigned() } + let labelIndex: UInt32 = try parseUnsigned() + return BrTable(labelIndices: labelIndices, defaultIndex: labelIndex) + } + @inlinable mutating func visitThrow() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitThrowRef() throws(WasmParserError) { /* no immediates */ } + @inlinable mutating func visitTryTable() throws(WasmParserError) -> (blockType: BlockType, tryCatch: TryCatch) { + let blockType = try parseResultType() + let catches: [CatchClause] = try parseVector { () throws(WasmParserError) in + let clauseId: UInt8 = try parseUnsigned() + switch clauseId { + case 0x00: + let tagIndex: UInt32 = try parseUnsigned() + let label: UInt32 = try parseUnsigned() + return .catch(tagIndex: tagIndex, labelIndex: label) + case 0x01: + let tagIndex: UInt32 = try parseUnsigned() + let label: UInt32 = try parseUnsigned() + return .catchRef(tagIndex: tagIndex, labelIndex: label) + case 0x02: + let label: UInt32 = try parseUnsigned() + return .catchAll(labelIndex: label) + case 0x03: + let label: UInt32 = try parseUnsigned() + return .catchAllRef(labelIndex: label) + default: + throw makeError(.invalidCatchClauseId(clauseId)) + } + } + return (blockType, TryCatch(catches: catches)) + } + @inlinable mutating func visitCall() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitCallRef() throws(WasmParserError) -> UInt32 { + // TODO reference types checks + // traps on nil + try parseUnsigned() + } + + @inlinable mutating func visitCallIndirect() throws(WasmParserError) -> (typeIndex: UInt32, tableIndex: UInt32) { + let typeIndex: TypeIndex = try parseUnsigned() + let peek = try stream.peek() + + if !features.contains(.referenceTypes) && peek != 0 { + // Check that reserved byte is zero when reference-types is disabled + throw makeError(.malformedIndirectCall) + } + let tableIndex: TableIndex = try parseUnsigned() + return (typeIndex, tableIndex) + } + + @inlinable mutating func visitReturnCall() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + + @inlinable mutating func visitReturnCallIndirect() throws(WasmParserError) -> (typeIndex: UInt32, tableIndex: UInt32) { + let typeIndex: TypeIndex = try parseUnsigned() + let tableIndex: TableIndex = try parseUnsigned() + return (typeIndex, tableIndex) + } + + @inlinable mutating func visitReturnCallRef() throws(WasmParserError) -> UInt32 { + return 0 + } + + @inlinable mutating func visitTypedSelect() throws(WasmParserError) -> WasmTypes.ValueType { + let results = try parseVector { () throws(WasmParserError) in try parseValueType() } + guard results.count == 1 else { + throw makeError(.invalidResultArity(expected: 1, actual: results.count)) + } + return results[0] + } + + @inlinable mutating func visitLocalGet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitLocalSet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitLocalTee() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitGlobalGet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitGlobalSet() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitLoad(_: Instruction.Load) throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitStore(_: Instruction.Store) throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitMemorySize() throws(WasmParserError) -> UInt32 { + try parseMemoryIndex() + } + @inlinable mutating func visitMemoryGrow() throws(WasmParserError) -> UInt32 { + try parseMemoryIndex() + } + @inlinable mutating func visitI32Const() throws(WasmParserError) -> Int32 { + let n: UInt32 = try parseInteger() + return Int32(bitPattern: n) + } + @inlinable mutating func visitI64Const() throws(WasmParserError) -> Int64 { + let n: UInt64 = try parseInteger() + return Int64(bitPattern: n) + } + @inlinable mutating func visitF32Const() throws(WasmParserError) -> IEEE754.Float32 { + let n = try parseFloat() + return IEEE754.Float32(bitPattern: n) + } + @inlinable mutating func visitF64Const() throws(WasmParserError) -> IEEE754.Float64 { + let n = try parseDouble() + return IEEE754.Float64(bitPattern: n) + } + @inlinable mutating func visitRefNull() throws(WasmParserError) -> WasmTypes.HeapType { + return try parseHeapType() + } + @inlinable mutating func visitBrOnNull() throws(WasmParserError) -> UInt32 { + return 0 + } + @inlinable mutating func visitBrOnNonNull() throws(WasmParserError) -> UInt32 { + return 0 + } + + @inlinable mutating func visitRefFunc() throws(WasmParserError) -> UInt32 { try parseUnsigned() } + @inlinable mutating func visitMemoryInit() throws(WasmParserError) -> UInt32 { + let dataIndex: DataIndex = try parseUnsigned() + _ = try parseMemoryIndex() + return dataIndex + } + + @inlinable mutating func visitDataDrop() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + + @inlinable mutating func visitMemoryCopy() throws(WasmParserError) -> (dstMem: UInt32, srcMem: UInt32) { + _ = try parseMemoryIndex() + _ = try parseMemoryIndex() + return (0, 0) + } + + @inlinable mutating func visitMemoryFill() throws(WasmParserError) -> UInt32 { + let zero = try stream.consumeAny() + guard zero == 0x00 else { + throw makeError(.zeroExpected(actual: zero)) + } + return 0 + } + + @inlinable mutating func visitTableInit() throws(WasmParserError) -> (elemIndex: UInt32, table: UInt32) { + let elementIndex: ElementIndex = try parseUnsigned() + let tableIndex: TableIndex = try parseUnsigned() + return (elementIndex, tableIndex) + } + @inlinable mutating func visitElemDrop() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableCopy() throws(WasmParserError) -> (dstTable: UInt32, srcTable: UInt32) { + let destination: TableIndex = try parseUnsigned() + let source: TableIndex = try parseUnsigned() + return (destination, source) + } + @inlinable mutating func visitTableFill() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableGet() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableSet() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableGrow() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitTableSize() throws(WasmParserError) -> UInt32 { + try parseUnsigned() + } + @inlinable mutating func visitMemoryAtomicNotify() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitMemoryAtomicWait32() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitMemoryAtomicWait64() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmwAdd() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmwAdd() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw8AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw16AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw8AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw16AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw32AddU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmwSub() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmwSub() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw8SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw16SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw8SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw16SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw32SubU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmwAnd() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmwAnd() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw8AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw16AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw8AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw16AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw32AndU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmwOr() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmwOr() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw8OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw16OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw8OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw16OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw32OrU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmwXor() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmwXor() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw8XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw16XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw8XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw16XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw32XorU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmwXchg() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmwXchg() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw8XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw16XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw8XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw16XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw32XchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmwCmpxchg() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmwCmpxchg() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw8CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI32AtomicRmw16CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw8CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw16CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitI64AtomicRmw32CmpxchgU() throws(WasmParserError) -> MemArg { try parseMemarg() } + @inlinable mutating func visitV128Const() throws(WasmParserError) -> V128 { + return V128(bytes: Array(try stream.consume(count: V128.byteCount))) + } + @inlinable mutating func visitI8x16Shuffle() throws(WasmParserError) -> V128ShuffleMask { + return V128ShuffleMask(lanes: Array(try stream.consume(count: V128ShuffleMask.laneCount))) + } + @inlinable mutating func visitSimdLane(_: Instruction.SimdLane) throws(WasmParserError) -> UInt8 { + return try stream.consumeAny() + } + @inlinable mutating func visitSimdMemLane(_: Instruction.SimdMemLane) throws(WasmParserError) -> (memarg: MemArg, lane: UInt8) { + let memarg = try parseMemarg() + let lane = try stream.consumeAny() + return (memarg: memarg, lane: lane) + } + @inlinable func claimNextByte() throws(WasmParserError) -> UInt8 { + return try stream.consumeAny() + } + + /// Parse a single binary instruction. + @inline(__always) + @inlinable + mutating func parseInstruction() throws(WasmParserError) -> Instruction { + return try parseBinaryInstruction(decoder: &self) + } + + @usableFromInline + mutating func parseConstExpression() throws(WasmParserError) -> ConstExpression { + var insts: [Instruction] = [] + while true { + let instruction = try self.parseInstruction() + insts.append(instruction) + if case .end = instruction { break } + } + return insts + } +} + +/// > Note: +/// +extension Parser { + /// > Note: + /// + @usableFromInline + func parseCustomSection(size: UInt32) throws(WasmParserError) -> CustomSection { + let preNameIndex = stream.currentIndex + let name = try parseName() + let nameSize = stream.currentIndex - preNameIndex + let contentSize = Int(size) - nameSize + + guard contentSize >= 0 else { + throw makeError(.invalidSectionSize(size)) + } + + let bytes = try stream.consume(count: contentSize) + + return CustomSection(name: name, bytes: bytes) + } + + /// > Note: + /// + @inlinable + func parseTypeSection() throws(WasmParserError) -> [FunctionType] { + return try parseVector { () throws(WasmParserError) in try parseFunctionType() } + } + + /// > Note: + /// + @usableFromInline + func parseImportSection() throws(WasmParserError) -> [Import] { + return try parseVector { () throws(WasmParserError) in + let module = try parseName() + let name = try parseName() + let descriptor = try parseImportDescriptor() + return Import(module: module, name: name, descriptor: descriptor) + } + } + + /// > Note: + /// + func parseImportDescriptor() throws(WasmParserError) -> ImportDescriptor { + let maxKind: UInt8 = features.contains(.exceptionHandling) ? 0x04 : 0x03 + let b = try stream.consume(Set(0x00...maxKind)) + switch b { + case 0x00: return try .function(parseUnsigned()) + case 0x01: return try .table(parseTableType()) + case 0x02: return try .memory(parseMemoryType()) + case 0x03: return try .global(parseGlobalType()) + case 0x04: + let attribute: UInt8 = try parseUnsigned() + guard attribute == 0 else { throw makeError(.invalidTagAttribute(attribute)) } + return try .tag(parseUnsigned()) + default: + preconditionFailure("should never reach here") + } + } + + /// > Note: + /// + @inlinable + func parseFunctionSection() throws(WasmParserError) -> [TypeIndex] { + return try parseVector { () throws(WasmParserError) in try parseUnsigned() } + } + + /// > Note: + /// + @usableFromInline + func parseTableSection() throws(WasmParserError) -> [Table] { + return try parseVector { () throws(WasmParserError) in try Table(type: parseTableType()) } + } + + /// > Note: + /// + @usableFromInline + func parseMemorySection() throws(WasmParserError) -> [Memory] { + return try parseVector { () throws(WasmParserError) in try Memory(type: parseLimits()) } + } + + /// > Note: + /// + @usableFromInline + mutating func parseGlobalSection() throws(WasmParserError) -> [Global] { + return try parseVector { () throws(WasmParserError) in + let type = try parseGlobalType() + let expression = try parseConstExpression() + return Global(type: type, initializer: expression) + } + } + + /// > Note: + /// + @usableFromInline + func parseTagSection() throws(WasmParserError) -> [Tag] { + return try parseVector { () throws(WasmParserError) in + let attribute: UInt8 = try parseUnsigned() + guard attribute == 0 else { throw makeError(.invalidTagAttribute(attribute)) } + let typeIndex: TypeIndex = try parseUnsigned() + return Tag(type: typeIndex) + } + } + + /// > Note: + /// + @usableFromInline + func parseExportSection() throws(WasmParserError) -> [Export] { + return try parseVector { () throws(WasmParserError) in + let name = try parseName() + let descriptor = try parseExportDescriptor() + return Export(name: name, descriptor: descriptor) + } + } + + /// > Note: + /// + func parseExportDescriptor() throws(WasmParserError) -> ExportDescriptor { + let maxKind: UInt8 = features.contains(.exceptionHandling) ? 0x04 : 0x03 + let b = try stream.consume(Set(0x00...maxKind)) + switch b { + case 0x00: return try .function(parseUnsigned()) + case 0x01: return try .table(parseUnsigned()) + case 0x02: return try .memory(parseUnsigned()) + case 0x03: return try .global(parseUnsigned()) + case 0x04: return try .tag(parseUnsigned()) + default: + preconditionFailure("should never reach here") + } + } + + /// > Note: + /// + @usableFromInline + func parseStartSection() throws(WasmParserError) -> FunctionIndex { + return try parseUnsigned() + } + + /// > Note: + /// + @inlinable + mutating func parseElementSection() throws(WasmParserError) -> [ElementSegment] { + return try parseVector { () throws(WasmParserError) in + let flag = try ElementSegment.Flag(rawValue: parseUnsigned()) + + let type: ReferenceType + let initializer: [ConstExpression] + let mode: ElementSegment.Mode + + if flag.contains(.isPassiveOrDeclarative) { + if flag.contains(.isDeclarative) { + mode = .declarative + } else { + mode = .passive + } + } else { + let table: TableIndex + + if flag.contains(.hasTableIndex) { + table = try parseUnsigned() + } else { + table = 0 + } + + let offset = try parseConstExpression() + mode = .active(table: table, offset: offset) + } + + if flag.segmentHasRefType { + let valueType = try parseValueType() + + guard case .ref(let refType) = valueType else { + throw makeError(.expectedRefType(actual: valueType)) + } + + type = refType + } else { + type = .funcRef + } + + if flag.segmentHasElemKind { + // `elemkind` parsing as defined in the spec + let elemKind = try parseUnsigned() as UInt32 + guard elemKind == 0x00 else { + throw makeError(.unexpectedElementKind(expected: 0x00, actual: elemKind)) + } + } + + if flag.contains(.usesExpressions) { + initializer = try parseVector { () throws(WasmParserError) in try parseConstExpression() } + } else { + initializer = try parseVector { () throws(WasmParserError) in + try [Instruction.refFunc(functionIndex: parseUnsigned() as UInt32)] + } + } + + return ElementSegment(type: type, initializer: initializer, mode: mode) + } + } + + /// > Note: + /// + @inlinable + func parseCodeSection() throws(WasmParserError) -> [Code] { + return try parseVector { () throws(WasmParserError) in + let size = try parseUnsigned() as UInt32 + let bodyStart = stream.currentIndex + let localTypes = try parseVector { () throws(WasmParserError) -> (n: UInt32, type: ValueType) in + let n: UInt32 = try parseUnsigned() + let t = try parseValueType() + return (n, t) + } + let totalLocals = localTypes.reduce(UInt64(0)) { $0 + UInt64($1.n) } + guard totalLocals < limits.maxFunctionLocals else { + throw makeError(.tooManyLocals(totalLocals, limit: limits.maxFunctionLocals)) + } + + let locals = localTypes.flatMap { (n: UInt32, type: ValueType) in + return Array(repeating: type, count: Int(n)) + } + let expressionStart = stream.currentIndex + let expressionBytes = try stream.consume( + count: Int(size) - (expressionStart - bodyStart) + ) + return Code( + locals: locals, expression: expressionBytes, + offset: expressionStart, features: features + ) + } + } + + /// > Note: + /// + @inlinable + mutating func parseDataSection() throws(WasmParserError) -> [DataSegment] { + return try parseVector { () throws(WasmParserError) in + let kind: UInt32 = try parseUnsigned() + switch kind { + case 0: + let offset = try parseConstExpression() + let initializer = try parseVectorBytes() + return .active(.init(index: 0, offset: offset, initializer: initializer)) + + case 1: + return try .passive(parseVectorBytes()) + + case 2: + let index: UInt32 = try parseUnsigned() + let offset = try parseConstExpression() + let initializer = try parseVectorBytes() + return .active(.init(index: index, offset: offset, initializer: initializer)) + default: + throw makeError(.malformedDataSegmentKind(kind)) + } + } + } + + /// > Note: + /// + @usableFromInline + func parseDataCountSection() throws(WasmParserError) -> UInt32 { + return try parseUnsigned() + } +} + +public enum ParsingPayload { + case header(version: [UInt8]) + case customSection(CustomSection) + case typeSection([FunctionType]) + case importSection([Import]) + case functionSection([TypeIndex]) + case tableSection([Table]) + case memorySection([Memory]) + case globalSection([Global]) + case tagSection([Tag]) + case exportSection([Export]) + case startSection(FunctionIndex) + case elementSection([ElementSegment]) + case codeSection([Code]) + case dataSection([DataSegment]) + case dataCount(UInt32) +} + +/// > Note: +/// +extension Parser { + /// > Note: + /// + @usableFromInline + func parseMagicNumber() throws(WasmParserError) { + let magicNumber = try stream.consume(count: 4) + guard magicNumber.elementsEqual(WASM_MAGIC) else { + throw makeError(.invalidMagicNumber(.init(magicNumber))) + } + } + + /// > Note: + /// + @usableFromInline + func parseVersion() throws(WasmParserError) -> [UInt8] { + let version = try Array(stream.consume(count: 4)) + guard version == [0x01, 0x00, 0x00, 0x00] else { + throw makeError(.unknownVersion(.init(version))) + } + return version + } + + @usableFromInline + struct OrderTracking { + @usableFromInline + enum Order: UInt8 { + case initial = 0 + case type + case _import + case function + case table + case memory + case tag + case global + case export + case start + case element + case dataCount + case code + case data + } + + @usableFromInline + var last: Order = .initial + + @inlinable + mutating func track(order: Order, parser: Parser) throws(WasmParserError) { + guard last.rawValue < order.rawValue else { + throw parser.makeError(.sectionOutOfOrder) + } + last = order + } + } + + /// Attempts to parse a chunk of the Wasm binary stream. + /// + /// - Returns: A `ParsingPayload` if the parsing was successful, otherwise `nil`. + /// + /// > Note: + /// + /// + /// The following example demonstrates how to use the `Parser` to parse a Wasm binary stream: + /// + /// ```swift + /// import WasmParserCore + /// + /// var parser = Parser(bytes: [ + /// 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, + /// 0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01, 0x03, + /// 0x66, 0x61, 0x63, 0x00, 0x00, 0x0a, 0x17, 0x01, 0x15, 0x00, 0x20, 0x00, + /// 0x50, 0x04, 0x7e, 0x42, 0x01, 0x05, 0x20, 0x00, 0x20, 0x00, 0x42, 0x01, + /// 0x7d, 0x10, 0x00, 0x7e, 0x0b, 0x0b + /// ]) + /// + /// while let payload = try parser.parseNext() { + /// switch payload { + /// case .header(let version): + /// print("Wasm version: \(version)") + /// default: break + /// } + /// } + /// ``` + @inlinable + public mutating func parseNext() throws(WasmParserError) -> ParsingPayload? { + switch nextParseTarget { + case .header: + try parseMagicNumber() + let version = try parseVersion() + self.nextParseTarget = .section + return .header(version: version) + case .section: + guard try !stream.hasReachedEnd() else { + return nil + } + let sectionID = try stream.consumeAny() + let sectionSize: UInt32 = try parseUnsigned() + let sectionStart = stream.currentIndex + + let payload: ParsingPayload + let order: OrderTracking.Order? + switch sectionID { + case 0: + order = nil + payload = .customSection(try parseCustomSection(size: sectionSize)) + case 1: + order = .type + payload = .typeSection(try parseTypeSection()) + case 2: + order = ._import + payload = .importSection(try parseImportSection()) + case 3: + order = .function + payload = .functionSection(try parseFunctionSection()) + case 4: + order = .table + payload = .tableSection(try parseTableSection()) + case 5: + order = .memory + payload = .memorySection(try parseMemorySection()) + case 6: + order = .global + payload = .globalSection(try parseGlobalSection()) + case 7: + order = .export + payload = .exportSection(try parseExportSection()) + case 8: + order = .start + payload = .startSection(try parseStartSection()) + case 9: + order = .element + payload = .elementSection(try parseElementSection()) + case 10: + order = .code + payload = .codeSection(try parseCodeSection()) + case 11: + order = .data + payload = .dataSection(try parseDataSection()) + case 12: + order = .dataCount + payload = .dataCount(try parseDataCountSection()) + case 13 where features.contains(.exceptionHandling): + order = .tag + payload = .tagSection(try parseTagSection()) + default: + throw makeError(.malformedSectionID(sectionID)) + } + if let order = order { + try orderTracking.track(order: order, parser: self) + } + let expectedSectionEnd = sectionStart + Int(sectionSize) + guard expectedSectionEnd == stream.currentIndex else { + throw makeError( + .sectionSizeMismatch( + sectionID: sectionID, + expected: expectedSectionEnd, + actual: offset + ) + ) + } + return payload + } + } +} + +/// A map of names by its index. +public typealias NameMap = [UInt32: String] + +/// Parsed names from a name section subsection. +public enum ParsedNames { + /// Subsection 0: Module name. + case moduleName(String) + /// Subsection 1: Function names. + case functions(NameMap) + /// Subsection 2: Local names (funcIndex → [localIndex → name]). + case locals([UInt32: NameMap]) + /// Subsection 3: Label names (funcIndex → [labelIndex → name]). + case labels([UInt32: NameMap]) + /// Subsection 4: Type names. + case types(NameMap) + /// Subsection 5: Table names. + case tables(NameMap) + /// Subsection 6: Memory names. + case memories(NameMap) + /// Subsection 7: Global names. + case globals(NameMap) + /// Subsection 8: Element segment names. + case elements(NameMap) + /// Subsection 9: Data segment names. + case dataSegments(NameMap) +} + +/// A parser for the name custom section. +/// +/// > Note: +public struct NameSectionParser { + let stream: Stream + + public init(stream: Stream) { + self.stream = stream + } + + /// Parses the entire name section. + /// + /// - Throws: If the stream is malformed or the section is invalid. + /// - Returns: A list of parsed names. + public func parseAll() throws(WasmParserError) -> [ParsedNames] { + var results: [ParsedNames] = [] + while try !stream.hasReachedEnd() { + let id = try stream.consumeAny() + guard let result = try parseNameSubsection(type: id) else { + continue + } + results.append(result) + } + return results + } + + func parseNameSubsection(type: UInt8) throws(WasmParserError) -> ParsedNames? { + let size = try stream.parseUnsigned(UInt32.self) + switch type { + case 0: return .moduleName(try stream.parseName()) + case 1: return .functions(try parseNameMap()) + case 2: return .locals(try parseIndirectNameMap()) + case 3: return .labels(try parseIndirectNameMap()) + case 4: return .types(try parseNameMap()) + case 5: return .tables(try parseNameMap()) + case 6: return .memories(try parseNameMap()) + case 7: return .globals(try parseNameMap()) + case 8: return .elements(try parseNameMap()) + case 9: return .dataSegments(try parseNameMap()) + default: + _ = try stream.consume(count: Int(size)) + return nil + } + } + + func parseNameMap() throws(WasmParserError) -> NameMap { + var nameMap: NameMap = [:] + _ = try stream.parseVector { () throws(WasmParserError) in + let index = try stream.parseUnsigned(UInt32.self) + let name = try stream.parseName() + nameMap[index] = name + } + return nameMap + } + + func parseIndirectNameMap() throws(WasmParserError) -> [UInt32: NameMap] { + var map: [UInt32: NameMap] = [:] + _ = try stream.parseVector { () throws(WasmParserError) in + let outerIndex = try stream.parseUnsigned(UInt32.self) + map[outerIndex] = try parseNameMap() + } + return map + } +} diff --git a/Sources/WasmParser/WasmParserError.swift b/Sources/WasmParserCore/WasmParserError.swift similarity index 99% rename from Sources/WasmParser/WasmParserError.swift rename to Sources/WasmParserCore/WasmParserError.swift index b83a1756..db1e095a 100644 --- a/Sources/WasmParser/WasmParserError.swift +++ b/Sources/WasmParserCore/WasmParserError.swift @@ -47,6 +47,7 @@ extension WasmParserError { } } +#if !$Embedded extension BinaryInteger { var hexString: String { "0x\(String(self, radix: 16))" @@ -86,6 +87,7 @@ extension WasmParserError: CustomStringConvertible { } } } +#endif // !$Embedded extension WasmParserError.Message { @usableFromInline diff --git a/Sources/WasmParser/WasmTypes.swift b/Sources/WasmParserCore/WasmTypes.swift similarity index 99% rename from Sources/WasmParser/WasmTypes.swift rename to Sources/WasmParserCore/WasmTypes.swift index a7c2b34b..dbc3afc7 100644 --- a/Sources/WasmParser/WasmTypes.swift +++ b/Sources/WasmParserCore/WasmTypes.swift @@ -1,4 +1,4 @@ -import WasmTypes +@_exported import WasmTypes /// Function code in a module /// > Note: diff --git a/Sources/_CWasmKit/include/_CWasmKit.h b/Sources/_CWasmKit/include/_CWasmKit.h index 5fe96997..6fd8e347 100644 --- a/Sources/_CWasmKit/include/_CWasmKit.h +++ b/Sources/_CWasmKit/include/_CWasmKit.h @@ -4,8 +4,13 @@ #include #include #include +// stdio.h and stdlib.h are only available on OS-bearing platforms. +// On bare-metal targets (e.g. RISC-V ESP32-C6 with Embedded Swift) there is no +// file I/O, so we skip these and provide a no-op stub for wasmkit_fwrite_stderr. +#if !defined(__riscv) || defined(__linux__) #include #include +#endif #include "Platform.h" @@ -92,11 +97,30 @@ static inline void wasmkit_tc_start( ) { exec(sp, pc, md, ms, state); } -#endif +#else // !WASMKIT_USE_DIRECT_THREADED_CODE + +// On platforms that don't support direct threaded code (e.g. bare-metal +// RISC-V with Embedded Swift), provide stub types so Swift source files that +// reference `wasmkit_tc_exec` still compile. The code paths that use these +// types are never reached when the token threading model is selected. +typedef void (*wasmkit_tc_exec)(void); +static inline void wasmkit_tc_start( + wasmkit_tc_exec exec, Sp sp, Pc pc, Md md, Ms ms, void *_Nullable state +) { (void)exec; (void)sp; (void)pc; (void)md; (void)ms; (void)state; } + +#endif // WASMKIT_USE_DIRECT_THREADED_CODE + +#if !defined(__riscv) || defined(__linux__) static inline void wasmkit_fwrite_stderr(const char *_Nonnull str, size_t len) { fwrite(str, 1, len, stderr); } +#else +// Bare-metal: no file I/O; output is handled by the firmware's UART/USB. +static inline void wasmkit_fwrite_stderr(const char *_Nonnull str, size_t len) { + (void)str; (void)len; +} +#endif int wasmkit_address_sanitizer_enabled(void); diff --git a/Tests/WasmParserTests/LEBTests.swift b/Tests/WasmParserTests/LEBTests.swift index d275a117..2f5feccc 100644 --- a/Tests/WasmParserTests/LEBTests.swift +++ b/Tests/WasmParserTests/LEBTests.swift @@ -1,6 +1,7 @@ import Testing @testable import WasmParser +@testable import WasmParserCore @Suite struct LEBTest { @Test func unsigned() throws {