From 8bf446b5ce1071ec5d82e13d6f15c697c4c9a6f9 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 8 Dec 2024 09:47:34 +0000 Subject: [PATCH] Fix empty TypedArray creation --- Runtime/src/index.ts | 9 +++++++++ Sources/JavaScriptKit/Runtime/index.js | 9 +++++++++ Sources/JavaScriptKit/Runtime/index.mjs | 9 +++++++++ .../JavaScriptKitTests/JSTypedArrayTests.swift | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 Tests/JavaScriptKitTests/JSTypedArrayTests.swift diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index d6d82c04..73f56411 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -536,6 +536,15 @@ export class SwiftRuntime { ) => { const ArrayType: TypedArray = this.memory.getObject(constructor_ref); + if (length == 0) { + // The elementsPtr can be unaligned in Swift's Array + // implementation when the array is empty. However, + // TypedArray requires the pointer to be aligned. + // So, we need to create a new empty array without + // using the elementsPtr. + // See https://github.com/swiftwasm/swift/issues/5599 + return this.memory.retain(new ArrayType()); + } const array = new ArrayType( this.memory.rawMemory.buffer, elementsPtr, diff --git a/Sources/JavaScriptKit/Runtime/index.js b/Sources/JavaScriptKit/Runtime/index.js index 9d29b432..223fed3e 100644 --- a/Sources/JavaScriptKit/Runtime/index.js +++ b/Sources/JavaScriptKit/Runtime/index.js @@ -451,6 +451,15 @@ }, swjs_create_typed_array: (constructor_ref, elementsPtr, length) => { const ArrayType = this.memory.getObject(constructor_ref); + if (length == 0) { + // The elementsPtr can be unaligned in Swift's Array + // implementation when the array is empty. However, + // TypedArray requires the pointer to be aligned. + // So, we need to create a new empty array without + // using the elementsPtr. + // See https://github.com/swiftwasm/swift/issues/5599 + return this.memory.retain(new ArrayType()); + } const array = new ArrayType(this.memory.rawMemory.buffer, elementsPtr, length); // Call `.slice()` to copy the memory return this.memory.retain(array.slice()); diff --git a/Sources/JavaScriptKit/Runtime/index.mjs b/Sources/JavaScriptKit/Runtime/index.mjs index 9201b771..34e4dd13 100644 --- a/Sources/JavaScriptKit/Runtime/index.mjs +++ b/Sources/JavaScriptKit/Runtime/index.mjs @@ -445,6 +445,15 @@ class SwiftRuntime { }, swjs_create_typed_array: (constructor_ref, elementsPtr, length) => { const ArrayType = this.memory.getObject(constructor_ref); + if (length == 0) { + // The elementsPtr can be unaligned in Swift's Array + // implementation when the array is empty. However, + // TypedArray requires the pointer to be aligned. + // So, we need to create a new empty array without + // using the elementsPtr. + // See https://github.com/swiftwasm/swift/issues/5599 + return this.memory.retain(new ArrayType()); + } const array = new ArrayType(this.memory.rawMemory.buffer, elementsPtr, length); // Call `.slice()` to copy the memory return this.memory.retain(array.slice()); diff --git a/Tests/JavaScriptKitTests/JSTypedArrayTests.swift b/Tests/JavaScriptKitTests/JSTypedArrayTests.swift new file mode 100644 index 00000000..87b81ae1 --- /dev/null +++ b/Tests/JavaScriptKitTests/JSTypedArrayTests.swift @@ -0,0 +1,18 @@ +import XCTest +import JavaScriptKit + +final class JSTypedArrayTests: XCTestCase { + func testEmptyArray() { + _ = JSTypedArray([]) + _ = JSTypedArray([]) + _ = JSTypedArray([Int8]()) + _ = JSTypedArray([UInt8]()) + _ = JSUInt8ClampedArray([UInt8]()) + _ = JSTypedArray([Int16]()) + _ = JSTypedArray([UInt16]()) + _ = JSTypedArray([Int32]()) + _ = JSTypedArray([UInt32]()) + _ = JSTypedArray([Float32]()) + _ = JSTypedArray([Float64]()) + } +}