From 03f4d9a608b4aa135c4fd7426a78496b6ed81f51 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 27 Jun 2025 12:06:08 +0900 Subject: [PATCH] Slice a bytes array when the underlying memory is shared TextDecoder does not support decoding shared memory slices directly on browsers, so we need to slice the Uint8Array --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 15 +++++++++++++-- .../BridgeJSToolTests/BridgeJSLinkTests.swift | 4 ++-- Plugins/PackageToJS/Sources/PackageToJS.swift | 9 +++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index f1605670..f9e15984 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -4,6 +4,17 @@ struct BridgeJSLink { /// The exported skeletons var exportedSkeletons: [ExportedSkeleton] = [] var importedSkeletons: [ImportedModuleSkeleton] = [] + let sharedMemory: Bool + + init( + exportedSkeletons: [ExportedSkeleton] = [], + importedSkeletons: [ImportedModuleSkeleton] = [], + sharedMemory: Bool + ) { + self.exportedSkeletons = exportedSkeletons + self.importedSkeletons = importedSkeletons + self.sharedMemory = sharedMemory + } mutating func addExportedSkeletonFile(data: Data) throws { let skeleton = try JSONDecoder().decode(ExportedSkeleton.self, from: data) @@ -118,7 +129,7 @@ struct BridgeJSLink { const bjs = {}; importObject["bjs"] = bjs; bjs["return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); + const bytes = new Uint8Array(memory.buffer, ptr, len)\(sharedMemory ? ".slice()" : ""); tmpRetString = textDecoder.decode(bytes); } bjs["init_memory"] = function(sourceId, bytesPtr) { @@ -127,7 +138,7 @@ struct BridgeJSLink { bytes.set(source); } bjs["make_jsstring"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); + const bytes = new Uint8Array(memory.buffer, ptr, len)\(sharedMemory ? ".slice()" : ""); return swift.memory.retain(textDecoder.decode(bytes)); } bjs["init_memory_with_result"] = function(ptr, len) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index e052ed42..3e65ca04 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -55,7 +55,7 @@ import Testing let encoder = JSONEncoder() encoder.outputFormatting = [.prettyPrinted, .sortedKeys] let outputSkeletonData = try encoder.encode(outputSkeleton) - var bridgeJSLink = BridgeJSLink() + var bridgeJSLink = BridgeJSLink(sharedMemory: false) try bridgeJSLink.addExportedSkeletonFile(data: outputSkeletonData) try snapshot(bridgeJSLink: bridgeJSLink, name: name + ".Export") } @@ -73,7 +73,7 @@ import Testing encoder.outputFormatting = [.prettyPrinted, .sortedKeys] let outputSkeletonData = try encoder.encode(importTS.skeleton) - var bridgeJSLink = BridgeJSLink() + var bridgeJSLink = BridgeJSLink(sharedMemory: false) try bridgeJSLink.addImportedSkeletonFile(data: outputSkeletonData) try snapshot(bridgeJSLink: bridgeJSLink, name: name + ".Import") } diff --git a/Plugins/PackageToJS/Sources/PackageToJS.swift b/Plugins/PackageToJS/Sources/PackageToJS.swift index 43e2c244..48f84e54 100644 --- a/Plugins/PackageToJS/Sources/PackageToJS.swift +++ b/Plugins/PackageToJS/Sources/PackageToJS.swift @@ -583,7 +583,8 @@ struct PackagingPlanner { let decoder = JSONDecoder() let data = try Data(contentsOf: URL(fileURLWithPath: scope.resolve(path: $0).path)) return try decoder.decode(ImportedModuleSkeleton.self, from: data) - } + }, + sharedMemory: Self.isSharedMemoryEnabled(triple: triple) ) let (outputJs, outputDts) = try link.link() try system.writeFile(atPath: scope.resolve(path: bridgeJs).path, content: Data(outputJs.utf8)) @@ -699,7 +700,7 @@ struct PackagingPlanner { let inputPath = selfPackageDir.appending(path: file) let conditions: [String: Bool] = [ - "USE_SHARED_MEMORY": triple == "wasm32-unknown-wasip1-threads", + "USE_SHARED_MEMORY": Self.isSharedMemoryEnabled(triple: triple), "IS_WASI": triple.hasPrefix("wasm32-unknown-wasi"), "USE_WASI_CDN": options.useCDN, "HAS_BRIDGE": exportedSkeletons.count > 0 || importedSkeletons.count > 0, @@ -742,6 +743,10 @@ struct PackagingPlanner { try system.writeFile(atPath: $1.resolve(path: $0.output).path, content: Data(content.utf8)) } } + + private static func isSharedMemoryEnabled(triple: String) -> Bool { + return triple == "wasm32-unknown-wasip1-threads" + } } // MARK: - Utilities