From 6e9d2c48944da67b240cb0ec9189e8cfcc2e635b Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Mon, 29 Apr 2024 22:47:16 -0400 Subject: [PATCH 01/10] Drop foundation, lower min OS --- Package.swift | 7 +++-- Sources/CLI/Run/Run.swift | 5 +++- Sources/Spectest/Spectest.swift | 3 ++ Sources/WASI/FileSystem.swift | 1 - Sources/WASI/Platform/File.swift | 26 ++++++---------- Sources/WASI/WASI.swift | 30 ++++++++----------- Sources/WITExtractor/ModuleTranslation.swift | 1 + Sources/WITExtractor/SourceSummary.swift | 1 + Sources/WITExtractor/SwiftAPIDigester.swift | 1 + Sources/WITExtractor/TypeMapping.swift | 1 + Sources/WITExtractor/WITExtractor.swift | 4 +++ Sources/WITTool/WITTool.swift | 4 +++ .../WasmKit/Execution/Runtime/Profiler.swift | 4 +++ Sources/WasmKit/ModuleParser.swift | 6 ++-- .../WasmParser/Stream/FileHandleStream.swift | 21 +++++++++---- Sources/WasmParser/WasmParser.swift | 2 -- 16 files changed, 68 insertions(+), 49 deletions(-) diff --git a/Package.swift b/Package.swift index 67631c48..0beedca5 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ import class Foundation.ProcessInfo let package = Package( name: "WasmKit", - platforms: [.macOS(.v11), .iOS(.v14)], + platforms: [.macOS(.v10_13), .iOS(.v13)], products: [ .library( name: "WasmKit", @@ -58,7 +58,10 @@ let package = Package( ), .target( name: "WasmParser", - dependencies: ["WasmTypes"] + dependencies: [ + "WasmTypes", + .product(name: "SystemPackage", package: "swift-system"), + ] ), .target( name: "WasmKitWASI", diff --git a/Sources/CLI/Run/Run.swift b/Sources/CLI/Run/Run.swift index d928da5b..d0d8bc00 100644 --- a/Sources/CLI/Run/Run.swift +++ b/Sources/CLI/Run/Run.swift @@ -76,8 +76,11 @@ struct Run: ParsableCommand { log("Finished invoking function \"\(path)\": \(invokeTime)", verbose: true) } - func deriveInterceptor() throws -> (interceptor: GuestTimeProfiler, finalize: () -> Void)? { + func deriveInterceptor() throws -> (interceptor: RuntimeInterceptor, finalize: () -> Void)? { guard let outputPath = self.profileOutput else { return nil } + guard #available(macOS 11, *) else { + fatalError("Interceptor requires macOS 11+") + } FileManager.default.createFile(atPath: outputPath, contents: nil) let fileHandle = try FileHandle(forWritingTo: URL(fileURLWithPath: outputPath)) let profiler = GuestTimeProfiler { data in diff --git a/Sources/Spectest/Spectest.swift b/Sources/Spectest/Spectest.swift index 5c7885ce..a115693b 100644 --- a/Sources/Spectest/Spectest.swift +++ b/Sources/Spectest/Spectest.swift @@ -21,6 +21,9 @@ struct Spectest: AsyncParsableCommand { var parallel: Bool = true func run() async throws { + guard #available(macOS 11, *) else { + fatalError("Spectest requires macOS 11+") + } let printVerbose = self.verbose @Sendable func log(_ message: String, verbose: Bool = false) { if !verbose || printVerbose { diff --git a/Sources/WASI/FileSystem.swift b/Sources/WASI/FileSystem.swift index 97b7b34d..95ed2c47 100644 --- a/Sources/WASI/FileSystem.swift +++ b/Sources/WASI/FileSystem.swift @@ -1,4 +1,3 @@ -import Foundation import SystemPackage struct FileAccessMode: OptionSet { diff --git a/Sources/WASI/Platform/File.swift b/Sources/WASI/Platform/File.swift index 9c9ad8c8..08c261bd 100644 --- a/Sources/WASI/Platform/File.swift +++ b/Sources/WASI/Platform/File.swift @@ -1,4 +1,3 @@ -import Foundation import SystemPackage protocol FdWASIEntry: WASIEntry { @@ -31,11 +30,10 @@ extension FdWASIFile { throw WASIAbi.Errno.EBADF } // TODO: Use `writev` - let handle = FileHandle(fileDescriptor: fd.rawValue) var bytesWritten: UInt32 = 0 for iovec in buffer { try iovec.withHostBufferPointer { - try handle.write(contentsOf: $0) + _ = try fd.writeAll($0) } bytesWritten += iovec.length } @@ -45,18 +43,16 @@ extension FdWASIFile { @inlinable func pwrite(vectored buffer: Buffer, offset: WASIAbi.FileSize) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec { // TODO: Use `pwritev` - let handle = FileHandle(fileDescriptor: fd.rawValue) - let savedOffset = try handle.offset() - try handle.seek(toOffset: offset) + let savedOffset = try fd.seek(offset: 0, from: .current) + try fd.seek(offset: Int64(offset), from: .start) let nwritten = try write(vectored: buffer) - try handle.seek(toOffset: savedOffset) + try fd.seek(offset: savedOffset, from: .start) return nwritten } @inlinable func read(into buffer: Buffer) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec { // TODO: Use `readv` - let handle = FileHandle(fileDescriptor: fd.rawValue) var nread: UInt32 = 0 for iovec in buffer { try iovec.buffer.withHostPointer(count: Int(iovec.length)) { rawBufferStart in @@ -66,11 +62,8 @@ extension FdWASIFile { let bufferEnd = bufferStart + Int(iovec.length) while bufferStart < bufferEnd { let remaining = bufferEnd - bufferStart - guard let bytes = try handle.read(upToCount: remaining) else { - break - } - bytes.copyBytes(to: bufferStart, count: bytes.count) - bufferStart += bytes.count + let remainingBuffer = UnsafeMutableRawBufferPointer(start: bufferStart, count: remaining) + bufferStart += try fd.read(into: remainingBuffer) } nread += iovec.length - UInt32(bufferEnd - bufferStart) } @@ -81,11 +74,10 @@ extension FdWASIFile { @inlinable func pread(into buffer: Buffer, offset: WASIAbi.FileSize) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec { // TODO: Use `preadv` - let handle = FileHandle(fileDescriptor: fd.rawValue) - let savedOffset = try handle.offset() - try handle.seek(toOffset: offset) + let savedOffset = try fd.seek(offset: 0, from: .current) + try fd.seek(offset: Int64(offset), from: .start) let nread = try read(into: buffer) - try handle.seek(toOffset: savedOffset) + try fd.seek(offset: savedOffset, from: .start) return nread } } diff --git a/Sources/WASI/WASI.swift b/Sources/WASI/WASI.swift index 77fd95b0..27279fed 100644 --- a/Sources/WASI/WASI.swift +++ b/Sources/WASI/WASI.swift @@ -1,4 +1,3 @@ -import Foundation import SystemExtras import SystemPackage import WasmTypes @@ -835,8 +834,7 @@ extension WASI { count: length ) return try pointer.withHostPointer { hostBuffer in - guard let baseAddress = hostBuffer.baseAddress, - memchr(baseAddress, 0x00, Int(pointer.count)) == nil + guard hostBuffer.firstIndex(of: 0x00) == nil else { // If byte sequence contains null byte in the middle, it's illegal string // TODO: This restriction should be only applied to strings that can be interpreted as platform-string, which is expected to be null-terminated @@ -1379,12 +1377,7 @@ public class WASIBridgeToHost: WASI { for (guestPath, hostPath) in preopens { let fd = try hostPath.withCString { cHostPath in - let fd = open(cHostPath, O_DIRECTORY) - if fd < 0 { - let errno = errno - throw POSIXError(POSIXErrorCode(rawValue: errno)!) - } - return FileDescriptor(rawValue: fd) + try FileDescriptor.open(cHostPath, .readOnly, options: .directory) } if try fd.attributes().fileType.isDirectory { _ = try fdTable.push(.directory(DirEntry(preopenPath: guestPath, fd: fd))) @@ -1409,8 +1402,8 @@ public class WASIBridgeToHost: WASI { offsets += 1 let count = arg.utf8CString.withUnsafeBytes { bytes in let count = UInt32(bytes.count) - _ = buffer.raw.withHostPointer(count: bytes.count) { hostDestBuffer in - bytes.copyBytes(to: hostDestBuffer) + buffer.raw.withHostPointer(count: bytes.count) { hostDestBuffer in + hostDestBuffer.copyMemory(from: bytes) } return count } @@ -1434,8 +1427,8 @@ public class WASIBridgeToHost: WASI { offsets += 1 let count = "\(key)=\(value)".utf8CString.withUnsafeBytes { bytes in let count = UInt32(bytes.count) - _ = buffer.raw.withHostPointer(count: bytes.count) { hostDestBuffer in - bytes.copyBytes(to: hostDestBuffer) + buffer.raw.withHostPointer(count: bytes.count) { hostDestBuffer in + hostDestBuffer.copyMemory(from: bytes) } return count } @@ -1589,8 +1582,8 @@ public class WASIBridgeToHost: WASI { guard bytes.count <= maxPathLength else { throw WASIAbi.Errno.ENAMETOOLONG } - _ = path.withHostPointer(count: Int(maxPathLength)) { buffer in - bytes.copyBytes(to: buffer) + path.withHostPointer(count: Int(maxPathLength)) { buffer in + UnsafeMutableRawBufferPointer(buffer).copyMemory(from: UnsafeRawBufferPointer(bytes)) } } } @@ -1650,8 +1643,11 @@ public class WASIBridgeToHost: WASI { let copyingBytes = min(entry.dirNameLen, totalBufferSize - bufferUsed) let rangeStart = buffer.baseAddress.raw.advanced(by: bufferUsed) name.withUTF8 { bytes in - _ = rangeStart.withHostPointer(count: Int(copyingBytes)) { hostBuffer in - bytes.copyBytes(to: hostBuffer, count: Int(copyingBytes)) + rangeStart.withHostPointer(count: Int(copyingBytes)) { hostBuffer in + hostBuffer.copyMemory(from: UnsafeRawBufferPointer( + start: UnsafeRawPointer(bytes.baseAddress), + count: Int(copyingBytes) + )) } } bufferUsed += copyingBytes diff --git a/Sources/WITExtractor/ModuleTranslation.swift b/Sources/WITExtractor/ModuleTranslation.swift index b08b9249..2a870b2a 100644 --- a/Sources/WITExtractor/ModuleTranslation.swift +++ b/Sources/WITExtractor/ModuleTranslation.swift @@ -1,3 +1,4 @@ +@available(macOS 11, *) struct ModuleTranslation { let diagnostics: DiagnosticCollection let typeMapping: TypeMapping diff --git a/Sources/WITExtractor/SourceSummary.swift b/Sources/WITExtractor/SourceSummary.swift index d9ca457f..6e783911 100644 --- a/Sources/WITExtractor/SourceSummary.swift +++ b/Sources/WITExtractor/SourceSummary.swift @@ -49,6 +49,7 @@ public struct SwiftFunctionSource { let name: String } +@available(macOS 11, *) struct SourceSummaryBuilder { let diagnostics: DiagnosticCollection let typeMapping: TypeMapping diff --git a/Sources/WITExtractor/SwiftAPIDigester.swift b/Sources/WITExtractor/SwiftAPIDigester.swift index f8c42f1e..794776c8 100644 --- a/Sources/WITExtractor/SwiftAPIDigester.swift +++ b/Sources/WITExtractor/SwiftAPIDigester.swift @@ -116,6 +116,7 @@ struct SwiftAPIDigester { typealias SDKNodeType = SDKNodeInherit typealias SDKNodeTypeNominal = SDKNodeInherit + @available(macOS 11, *) func dumpSDK(moduleName: String, arguments: [String]) throws -> Output { var args = [ "-dump-sdk", diff --git a/Sources/WITExtractor/TypeMapping.swift b/Sources/WITExtractor/TypeMapping.swift index 9da4f018..82ad2cb6 100644 --- a/Sources/WITExtractor/TypeMapping.swift +++ b/Sources/WITExtractor/TypeMapping.swift @@ -1,3 +1,4 @@ +@available(macOS 11, *) struct TypeMapping { typealias DeclScope = [SwiftAPIDigester.SDKNodeDecl] struct DeclSource { diff --git a/Sources/WITExtractor/WITExtractor.swift b/Sources/WITExtractor/WITExtractor.swift index cacc2f0d..504dd612 100644 --- a/Sources/WITExtractor/WITExtractor.swift +++ b/Sources/WITExtractor/WITExtractor.swift @@ -31,6 +31,9 @@ public struct WITExtractor { } public func run(moduleName: String) throws -> Output { + guard #available(macOS 11, *) else { + fatalError("WITExtractor requires macOS 11+") + } let header = """ // DO NOT EDIT. // @@ -42,6 +45,7 @@ public struct WITExtractor { return output } + @available(macOS 11, *) func runWithoutHeader(moduleName: String) throws -> Output { let output = try digester.dumpSDK(moduleName: moduleName, arguments: extraDigesterArguments) var typeMapping = TypeMapping() diff --git a/Sources/WITTool/WITTool.swift b/Sources/WITTool/WITTool.swift index de5148ea..9a7faf9b 100644 --- a/Sources/WITTool/WITTool.swift +++ b/Sources/WITTool/WITTool.swift @@ -123,6 +123,10 @@ struct ExtractWIT: ParsableCommand { var digesterArgs: [String] = [] func run() throws { + guard #available(macOS 11, *) else { + fatalError("ExtractWIT requires macOS 11+") + } + let extractor = WITExtractor( namespace: namespace, packageName: packageName, diff --git a/Sources/WasmKit/Execution/Runtime/Profiler.swift b/Sources/WasmKit/Execution/Runtime/Profiler.swift index c13bef90..15067991 100644 --- a/Sources/WasmKit/Execution/Runtime/Profiler.swift +++ b/Sources/WasmKit/Execution/Runtime/Profiler.swift @@ -1,3 +1,5 @@ +#if DEBUG + import Foundation import SystemExtras import SystemPackage @@ -85,3 +87,5 @@ public class GuestTimeProfiler: RuntimeInterceptor { output("\n]".data(using: .utf8)!) } } + +#endif diff --git a/Sources/WasmKit/ModuleParser.swift b/Sources/WasmKit/ModuleParser.swift index 6e6e77f4..a16a2782 100644 --- a/Sources/WasmKit/ModuleParser.swift +++ b/Sources/WasmKit/ModuleParser.swift @@ -1,11 +1,10 @@ -import Foundation import SystemPackage import WasmParser /// Parse a given file as a WebAssembly binary format file /// > Note: public func parseWasm(filePath: FilePath, features: WasmFeatureSet = .default) throws -> Module { - let fileHandle = try FileHandle(forReadingFrom: URL(fileURLWithPath: filePath.string)) + let fileHandle = try FileDescriptor.open(filePath, .readOnly) defer { try? fileHandle.close() } let stream = try FileHandleStream(fileHandle: fileHandle) let module = try parseModule(stream: stream, features: features) @@ -126,7 +125,8 @@ func parseModule(stream: Stream, features: WasmFeatureSet = memoryTypes: module.memories.map { $0.type }, tables: module.tables ) - let enableAssertDefault = _slowPath(getenv("WASMKIT_ENABLE_ASSERT") != nil) + #warning("Get env without foundation") + let enableAssertDefault = false // _slowPath(getenv("WASMKIT_ENABLE_ASSERT") != nil) let functions = codes.enumerated().map { [hasDataCount = parser.hasDataCount, features] index, code in let funcTypeIndex = typeIndices[index] let funcType = module.types[Int(funcTypeIndex)] diff --git a/Sources/WasmParser/Stream/FileHandleStream.swift b/Sources/WasmParser/Stream/FileHandleStream.swift index 8e70e540..e564b615 100644 --- a/Sources/WasmParser/Stream/FileHandleStream.swift +++ b/Sources/WasmParser/Stream/FileHandleStream.swift @@ -1,16 +1,16 @@ -import Foundation +import SystemPackage public final class FileHandleStream: ByteStream { private(set) public var currentIndex: Int = 0 - private let fileHandle: FileHandle + private let fileHandle: FileDescriptor private let bufferLength: Int private var endOffset: Int = 0 private var startOffset: Int = 0 private var bytes: [UInt8] = [] - public init(fileHandle: FileHandle, bufferLength: Int = 1024 * 8) throws { + public init(fileHandle: FileDescriptor, bufferLength: Int = 1024 * 8) throws { self.fileHandle = fileHandle self.bufferLength = bufferLength @@ -21,7 +21,7 @@ public final class FileHandleStream: ByteStream { guard Int(endOffset) == currentIndex else { return } startOffset = currentIndex - let data = try fileHandle.read(upToCount: bufferLength) ?? Foundation.Data() + let data = try fileHandle.read(upToCount: bufferLength) bytes = [UInt8](data) endOffset = startOffset + bytes.count @@ -58,11 +58,12 @@ public final class FileHandleStream: ByteStream { return result } - guard let data = try fileHandle.read(upToCount: bytesToRead), data.count == bytesToRead else { + let data = try fileHandle.read(upToCount: bytesToRead) + guard data.count == bytesToRead else { throw StreamError.unexpectedEnd(expected: nil) } - bytes.append(contentsOf: [UInt8](data)) + bytes.append(contentsOf: data) endOffset = endOffset + data.count let bytesIndex = currentIndex - startOffset @@ -84,3 +85,11 @@ public final class FileHandleStream: ByteStream { return bytes[index] } } + +extension FileDescriptor { + func read(upToCount maxLength: Int) throws -> [UInt8] { + try [UInt8](unsafeUninitializedCapacity: maxLength) { buffer, outCount in + outCount = try read(into: UnsafeMutableRawBufferPointer(buffer)) + } + } +} diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 5a7741de..724903dc 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -1,5 +1,3 @@ -import Foundation - public struct Parser { let stream: Stream public private(set) var hasDataCount: Bool = false From 05f94655bb492d700a673b8546745fba49117c8d Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Mon, 29 Apr 2024 22:51:49 -0400 Subject: [PATCH 02/10] Fix compilation --- Sources/WASI/RandomBufferGenerator.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WASI/RandomBufferGenerator.swift b/Sources/WASI/RandomBufferGenerator.swift index a0a7d420..6035634c 100644 --- a/Sources/WASI/RandomBufferGenerator.swift +++ b/Sources/WASI/RandomBufferGenerator.swift @@ -22,7 +22,7 @@ extension RandomBufferGenerator where Self: RandomNumberGenerator { withUnsafeBytes(of: random) { randomBytes in let startOffset = i * 8 let destination = UnsafeMutableBufferPointer(rebasing: buffer[startOffset..<(startOffset + 8)]) - randomBytes.copyBytes(to: destination) + UnsafeMutableRawBufferPointer(destination).copyMemory(from: randomBytes) } } @@ -33,7 +33,7 @@ extension RandomBufferGenerator where Self: RandomNumberGenerator { withUnsafeBytes(of: random) { randomBytes in let startOffset = count * 8 let destination = UnsafeMutableBufferPointer(rebasing: buffer[startOffset..<(startOffset + remaining)]) - randomBytes.copyBytes(to: destination) + UnsafeMutableRawBufferPointer(destination).copyMemory(from: randomBytes) } } } From 651fe85d0cfe04c8d6638d0e27aae289f3b04147 Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Tue, 30 Apr 2024 13:45:07 -0400 Subject: [PATCH 03/10] Fix build, tests --- Sources/Spectest/Spectest.swift | 4 +--- Sources/WASI/RandomBufferGenerator.swift | 4 +++- Sources/WasmKit/Execution/Runtime/Stack.swift | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/Spectest/Spectest.swift b/Sources/Spectest/Spectest.swift index a115693b..54f1d6ef 100644 --- a/Sources/Spectest/Spectest.swift +++ b/Sources/Spectest/Spectest.swift @@ -20,10 +20,8 @@ struct Spectest: AsyncParsableCommand { @Flag(inversion: .prefixedNo) var parallel: Bool = true + @available(macOS 11, *) func run() async throws { - guard #available(macOS 11, *) else { - fatalError("Spectest requires macOS 11+") - } let printVerbose = self.verbose @Sendable func log(_ message: String, verbose: Bool = false) { if !verbose || printVerbose { diff --git a/Sources/WASI/RandomBufferGenerator.swift b/Sources/WASI/RandomBufferGenerator.swift index 6035634c..0148e1cd 100644 --- a/Sources/WASI/RandomBufferGenerator.swift +++ b/Sources/WASI/RandomBufferGenerator.swift @@ -33,7 +33,9 @@ extension RandomBufferGenerator where Self: RandomNumberGenerator { withUnsafeBytes(of: random) { randomBytes in let startOffset = count * 8 let destination = UnsafeMutableBufferPointer(rebasing: buffer[startOffset..<(startOffset + remaining)]) - UnsafeMutableRawBufferPointer(destination).copyMemory(from: randomBytes) + UnsafeMutableRawBufferPointer(destination).copyMemory( + from: UnsafeRawBufferPointer(start: randomBytes.baseAddress, count: remaining) + ) } } } diff --git a/Sources/WasmKit/Execution/Runtime/Stack.swift b/Sources/WasmKit/Execution/Runtime/Stack.swift index a77fffb3..1fd752aa 100644 --- a/Sources/WasmKit/Execution/Runtime/Stack.swift +++ b/Sources/WasmKit/Execution/Runtime/Stack.swift @@ -157,7 +157,7 @@ struct ValueStack { } extension ValueStack: Sequence { - func makeIterator() -> some IteratorProtocol { + func makeIterator() -> UnsafeMutableBufferPointer.SubSequence.Iterator { self.values[.. { } extension FixedSizeStack: Sequence { - func makeIterator() -> some IteratorProtocol { + func makeIterator() -> UnsafeMutableBufferPointer.SubSequence.Iterator { self.buffer[.. Date: Tue, 30 Apr 2024 13:50:29 -0400 Subject: [PATCH 04/10] fix spectest --- Sources/Spectest/Spectest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Spectest/Spectest.swift b/Sources/Spectest/Spectest.swift index 54f1d6ef..2fed3c8f 100644 --- a/Sources/Spectest/Spectest.swift +++ b/Sources/Spectest/Spectest.swift @@ -4,6 +4,7 @@ import SystemPackage import WasmKit @main +@available(macOS 11, *) struct Spectest: AsyncParsableCommand { @Argument var path: String @@ -20,7 +21,6 @@ struct Spectest: AsyncParsableCommand { @Flag(inversion: .prefixedNo) var parallel: Bool = true - @available(macOS 11, *) func run() async throws { let printVerbose = self.verbose @Sendable func log(_ message: String, verbose: Bool = false) { From 3540654bf11fc0e335c43d6593ca5e5f0c3ae821 Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Tue, 30 Apr 2024 14:19:08 -0400 Subject: [PATCH 05/10] Fixes --- Sources/CLI/Run/Run.swift | 6 ++- .../WasmKit/Execution/Runtime/Profiler.swift | 39 ++++++++++++------- Sources/WasmParser/CMakeLists.txt | 2 +- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Sources/CLI/Run/Run.swift b/Sources/CLI/Run/Run.swift index d0d8bc00..bfa6c562 100644 --- a/Sources/CLI/Run/Run.swift +++ b/Sources/CLI/Run/Run.swift @@ -76,14 +76,14 @@ struct Run: ParsableCommand { log("Finished invoking function \"\(path)\": \(invokeTime)", verbose: true) } - func deriveInterceptor() throws -> (interceptor: RuntimeInterceptor, finalize: () -> Void)? { + func deriveInterceptor() throws -> (interceptor: GuestTimeProfiler, finalize: () -> Void)? { guard let outputPath = self.profileOutput else { return nil } guard #available(macOS 11, *) else { fatalError("Interceptor requires macOS 11+") } FileManager.default.createFile(atPath: outputPath, contents: nil) let fileHandle = try FileHandle(forWritingTo: URL(fileURLWithPath: outputPath)) - let profiler = GuestTimeProfiler { data in + let profiler = GuestTimeProfiler(encoder: JSONEncoder()) { data in try? fileHandle.write(contentsOf: data) } return ( @@ -167,3 +167,5 @@ struct Run: ParsableCommand { } } } + +extension JSONEncoder: GuestTimeProfilerJSONEncoder {} diff --git a/Sources/WasmKit/Execution/Runtime/Profiler.swift b/Sources/WasmKit/Execution/Runtime/Profiler.swift index 15067991..23102054 100644 --- a/Sources/WasmKit/Execution/Runtime/Profiler.swift +++ b/Sources/WasmKit/Execution/Runtime/Profiler.swift @@ -1,6 +1,3 @@ -#if DEBUG - -import Foundation import SystemExtras import SystemPackage @@ -19,28 +16,32 @@ public class GuestTimeProfiler: RuntimeInterceptor { let ts: Int } - private var output: (Data) -> Void + private let encode: (any Encodable) throws -> [UInt8] + private let output: ([UInt8]) -> Void private var hasFirstEvent: Bool = false - private let encoder = JSONEncoder() private let startTime: UInt64 - public init(output: @escaping (Data) -> Void) { + public init( + encoder: some GuestTimeProfilerJSONEncoder, + output: @escaping ([UInt8]) -> Void + ) { + self.encode = { try [UInt8](encoder.encode($0)) } self.output = output self.startTime = Self.getTimestamp() } - private func eventLine(_ event: Event) -> Data? { - return try? encoder.encode(event) + private func eventLine(_ event: Event) -> [UInt8]? { + return try? encode(event) } private func addEventLine(_ event: Event) { guard let line = eventLine(event) else { return } if !hasFirstEvent { - self.output("[\n".data(using: .utf8)!) + self.output(Array("[\n".utf8)) self.output(line) hasFirstEvent = true } else { - self.output(",\n".data(using: .utf8)!) + self.output(Array(",\n".utf8)) self.output(line) } } @@ -67,7 +68,7 @@ public class GuestTimeProfiler: RuntimeInterceptor { let functionName = try? store.nameRegistry.lookup(address) let event = Event( ph: .begin, pid: 1, - name: functionName ?? "unknown function(\(String(format: "0x%x", address)))", + name: functionName ?? "unknown function(0x\(String(address, radix: 16)))", ts: getDurationSinceStart() ) addEventLine(event) @@ -77,15 +78,25 @@ public class GuestTimeProfiler: RuntimeInterceptor { let functionName = try? store.nameRegistry.lookup(address) let event = Event( ph: .end, pid: 1, - name: functionName ?? "unknown function(\(String(format: "0x%x", address)))", + name: functionName ?? "unknown function(0x\(String(address, radix: 16)))", ts: getDurationSinceStart() ) addEventLine(event) } public func finalize() { - output("\n]".data(using: .utf8)!) + output(Array("\n]".utf8)) } } -#endif +/// A top-level JSON encoder. +/// +/// If you depend on `Foundation`, you can add a trivial conformance to this with +/// ```swift +/// extension JSONEncoder: GuestTimeProfilerJSONEncoder {} +/// ``` +@_documentation(visibility: internal) +public protocol GuestTimeProfilerJSONEncoder { + associatedtype Bytes: Collection + func encode(_ output: some Encodable) throws -> Bytes +} diff --git a/Sources/WasmParser/CMakeLists.txt b/Sources/WasmParser/CMakeLists.txt index bd989ec1..50cea92b 100644 --- a/Sources/WasmParser/CMakeLists.txt +++ b/Sources/WasmParser/CMakeLists.txt @@ -10,4 +10,4 @@ add_wasmkit_library(WasmParser ) target_link_wasmkit_libraries(WasmParser PUBLIC - WasmTypes) + WasmTypes SystemExtras) From 5907621566debc16a25e5e6abacf0ee6286a558a Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Tue, 30 Apr 2024 14:20:07 -0400 Subject: [PATCH 06/10] Lower iOS dep target --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 0beedca5..d843a105 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ import class Foundation.ProcessInfo let package = Package( name: "WasmKit", - platforms: [.macOS(.v10_13), .iOS(.v13)], + platforms: [.macOS(.v10_13), .iOS(.v12)], products: [ .library( name: "WasmKit", From dd81c902d039dd2144fd517d63008d8a0cff45a9 Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Tue, 30 Apr 2024 15:23:12 -0400 Subject: [PATCH 07/10] Improve Stack Iterator encapsulation --- Sources/WasmKit/Execution/Runtime/Stack.swift | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Sources/WasmKit/Execution/Runtime/Stack.swift b/Sources/WasmKit/Execution/Runtime/Stack.swift index 1fd752aa..a7f96a66 100644 --- a/Sources/WasmKit/Execution/Runtime/Stack.swift +++ b/Sources/WasmKit/Execution/Runtime/Stack.swift @@ -157,8 +157,16 @@ struct ValueStack { } extension ValueStack: Sequence { - func makeIterator() -> UnsafeMutableBufferPointer.SubSequence.Iterator { - self.values[...SubSequence.Iterator + + mutating func next() -> Value? { + base.next() + } + } + + func makeIterator() -> Iterator { + Iterator(base: self.values[.. { } extension FixedSizeStack: Sequence { - func makeIterator() -> UnsafeMutableBufferPointer.SubSequence.Iterator { - self.buffer[...SubSequence.Iterator + + mutating func next() -> Element? { + base.next() + } + } + + func makeIterator() -> Iterator { + Iterator(base: self.buffer[.. Date: Wed, 1 May 2024 02:29:28 -0400 Subject: [PATCH 08/10] tweaks --- Sources/WasmKit/Execution/Runtime/Profiler.swift | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Sources/WasmKit/Execution/Runtime/Profiler.swift b/Sources/WasmKit/Execution/Runtime/Profiler.swift index b1976a33..ae4553d7 100644 --- a/Sources/WasmKit/Execution/Runtime/Profiler.swift +++ b/Sources/WasmKit/Execution/Runtime/Profiler.swift @@ -116,15 +116,3 @@ private enum JSON { return output } } - -/// A top-level JSON encoder. -/// -/// If you depend on `Foundation`, you can add a trivial conformance to this with -/// ```swift -/// extension JSONEncoder: GuestTimeProfilerJSONEncoder {} -/// ``` -@_documentation(visibility: internal) -public protocol GuestTimeProfilerJSONEncoder { - associatedtype Bytes: Collection - func encode(_ output: some Encodable) throws -> Bytes -} From 6019a08425fff0b8772efefc39259e39d510669d Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Wed, 1 May 2024 03:17:05 -0400 Subject: [PATCH 09/10] Stick to memchr --- Sources/WASI/WASI.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/WASI/WASI.swift b/Sources/WASI/WASI.swift index fac7ca4d..f2f68070 100644 --- a/Sources/WASI/WASI.swift +++ b/Sources/WASI/WASI.swift @@ -843,7 +843,8 @@ extension WASI { count: length ) return try pointer.withHostPointer { hostBuffer in - guard hostBuffer.firstIndex(of: 0x00) == nil + guard let baseAddress = hostBuffer.baseAddress, + memchr(baseAddress, 0x00, Int(pointer.count)) == nil else { // If byte sequence contains null byte in the middle, it's illegal string // TODO: This restriction should be only applied to strings that can be interpreted as platform-string, which is expected to be null-terminated From 5494bfb21d9f7727e40b9004ac9b1b6b5be4c3ee Mon Sep 17 00:00:00 2001 From: Kabir Oberai Date: Wed, 1 May 2024 03:17:56 -0400 Subject: [PATCH 10/10] reduce diff --- Sources/WasmParser/Stream/FileHandleStream.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WasmParser/Stream/FileHandleStream.swift b/Sources/WasmParser/Stream/FileHandleStream.swift index 41091d19..5bb9f551 100644 --- a/Sources/WasmParser/Stream/FileHandleStream.swift +++ b/Sources/WasmParser/Stream/FileHandleStream.swift @@ -63,7 +63,7 @@ public final class FileHandleStream: ByteStream { throw StreamError.unexpectedEnd(expected: nil) } - bytes.append(contentsOf: data) + bytes.append(contentsOf: [UInt8](data)) endOffset = endOffset + data.count let bytesIndex = currentIndex - startOffset