Skip to content

Commit 7d9d015

Browse files
committed
Change wasm versioning approach
1 parent 7b16cbd commit 7d9d015

File tree

3 files changed

+28
-53
lines changed

3 files changed

+28
-53
lines changed

tools/swift-plugin-server/Sources/swift-wasm-plugin-server/JSCWasmEngine.swift

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ async (wasmData, imports) => {
2727
const api = instance.exports;
2828
return {
2929
api,
30-
customSections: (name) => WebAssembly.Module.customSections(mod, name),
3130
read: (off, size) => new Uint8Array(new Uint8Array(api.memory.buffer, off, size)).buffer,
3231
write: (buf, off, size) => new Uint8Array(api.memory.buffer, off, size).set(new Uint8Array(buf)),
3332
};
@@ -79,20 +78,18 @@ final class JSCWasmEngine: WasmEngine {
7978
memory = JSCGuestMemory(getMemory: getMemory, setMemory: setMemory)
8079
}
8180

82-
func customSections(named name: String) throws -> [ArraySlice<UInt8>] {
83-
guard let array = runner.invokeMethod("customSections", withArguments: [name]),
84-
let length = array.objectForKeyedSubscript("length")?.toUInt32() else { return [] }
85-
return (0..<length)
86-
.compactMap { array.objectAtIndexedSubscript(Int($0)) }
87-
.map { $0.withUnsafeArrayBuffer { Array($0)[...] } }
88-
}
89-
90-
func invoke(_ method: String, _ args: [UInt32]) throws -> [UInt32] {
91-
let result = api.invokeMethod(method, withArguments: args)!
92-
if let exception = api.context.exception {
93-
throw JSCWasmError(message: "Call to \(method) failed", value: exception)
81+
func function(named name: String) throws -> WasmFunction? {
82+
guard let export = api.objectForKeyedSubscript(name), export.isObject else {
83+
return nil
84+
}
85+
return { [api] args in
86+
let result = export.call(withArguments: args)
87+
if let exception = api.context.exception {
88+
throw JSCWasmError(message: "Call to '\(name)' failed", value: exception)
89+
}
90+
guard let result else { return [] }
91+
return result.isUndefined ? [] : [result.toUInt32()]
9492
}
95-
return result.isUndefined ? [] : [result.toUInt32()]
9693
}
9794
}
9895

tools/swift-plugin-server/Sources/swift-wasm-plugin-server/WasmEngine.swift

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import WASI
1414
import WasmTypes
1515
import SystemPackage
1616

17+
typealias WasmFunction = ([UInt32]) throws -> [UInt32]
18+
1719
protocol WasmEngine {
1820
init(path: FilePath, imports: WASIBridgeToHost) async throws
1921

20-
func customSections(named name: String) throws -> [ArraySlice<UInt8>]
21-
22-
func invoke(_ method: String, _ args: [UInt32]) throws -> [UInt32]
22+
func function(named name: String) throws -> WasmFunction?
2323
}
2424

2525
typealias DefaultWasmPlugin = WasmEnginePlugin<DefaultWasmEngine>
@@ -28,6 +28,7 @@ typealias DefaultWasmPlugin = WasmEnginePlugin<DefaultWasmEngine>
2828
struct WasmEnginePlugin<Engine: WasmEngine>: WasmPlugin {
2929
private let hostToPlugin: FileDescriptor
3030
private let pluginToHost: FileDescriptor
31+
private let pumpFunction: WasmFunction
3132
let engine: Engine
3233

3334
init(path: FilePath) async throws {
@@ -42,39 +43,17 @@ struct WasmEnginePlugin<Engine: WasmEngine>: WasmPlugin {
4243
stderr: .standardError
4344
)
4445
engine = try await Engine(path: path, imports: bridge)
45-
try checkABIVersion()
46-
_ = try engine.invoke("_start", [])
47-
}
4846

49-
private func checkABIVersion() throws {
50-
let abiVersion = try abiVersion()
51-
guard abiVersion == 1 else {
52-
throw WasmEngineError(message: "Wasm plugin has unsupported ABI version: \(abiVersion)")
47+
let exportName = "swift_wasm_macro_v1_pump"
48+
guard let pump = try engine.function(named: exportName) else {
49+
throw WasmEngineError(message: "Wasm plugin has an unknown ABI (could not find '\(exportName)')")
5350
}
54-
}
51+
self.pumpFunction = pump
5552

56-
private func abiVersion() throws -> UInt32 {
57-
let sectionName = "swift_wasm_macro_abi"
58-
let sections = try engine.customSections(named: sectionName)
59-
switch sections.count {
60-
case 0:
61-
throw WasmEngineError(message: "Wasm macro is missing a '\(sectionName)' section")
62-
case 1:
63-
break
64-
default:
65-
throw WasmEngineError(message: "Wasm macro has too many '\(sectionName)' sections. Expected one, got \(sections.count)")
66-
}
67-
let section = sections[0]
68-
guard section.count == 4 else {
69-
throw WasmEngineError(message: """
70-
Wasm macro has incorrect '\(sectionName)' section length. Expected 4 bytes, got \(section.count).
71-
""")
72-
}
73-
return section.withUnsafeBufferPointer { buffer in
74-
buffer.withMemoryRebound(to: UInt32.self) {
75-
UInt32(littleEndian: $0.baseAddress!.pointee)
76-
}
53+
guard let start = try engine.function(named: "_start") else {
54+
throw WasmEngineError(message: "Wasm plugin does not have a '_start' entrypoint")
7755
}
56+
_ = try start([])
7857
}
7958

8059
func handleMessage(_ json: [UInt8]) async throws -> [UInt8] {
@@ -83,7 +62,7 @@ struct WasmEnginePlugin<Engine: WasmEngine>: WasmPlugin {
8362
}
8463
try hostToPlugin.writeAll(json)
8564

86-
_ = try engine.invoke("swift_wasm_macro_pump", [])
65+
_ = try pumpFunction([])
8766

8867
let lengthRaw = try withUnsafeTemporaryAllocation(of: UInt8.self, capacity: 8) { buffer in
8968
let lengthCount = try pluginToHost.read(into: UnsafeMutableRawBufferPointer(buffer))

tools/swift-plugin-server/Sources/swift-wasm-plugin-server/WasmKitEngine.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,11 @@ struct WasmKitEngine: WasmEngine {
3232
instance = try runtime.instantiate(module: module)
3333
}
3434

35-
func customSections(named name: String) throws -> [ArraySlice<UInt8>] {
36-
module.customSections.filter { $0.name == name }.map(\.bytes)
37-
}
38-
39-
func invoke(_ method: String, _ args: [UInt32]) throws -> [UInt32] {
40-
try runtime.invoke(instance, function: method, with: args.map(Value.i32)).map(\.i32)
35+
func function(named name: String) throws -> WasmFunction? {
36+
guard case let .function(function) = instance.exportInstances.first(where: { $0.name == name })?.value else {
37+
return nil
38+
}
39+
return { args in try function.invoke(args.map(Value.i32), runtime: runtime).map(\.i32) }
4140
}
4241
}
4342

0 commit comments

Comments
 (0)