Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base address of every empty array seems to be the same: issues where type alignment > word size #5599

Closed
ephemer opened this issue Dec 5, 2024 · 2 comments · Fixed by swiftwasm/JavaScriptKit#278

Comments

@ephemer
Copy link

ephemer commented Dec 5, 2024

Hi @kateinoigakukun,

Since Swift 6.0 (at the latest – I think we were previously using 5.7 with SwiftWasm) all empty arrays seem to point to the same base address.

A simpler reproducer is as follows:

    [Int]().withUnsafeBufferPointer { ptr in
        print(Int(bitPattern: ptr.baseAddress!)) // same
        print(Int(bitPattern: ptr.baseAddress!) % 8)
    }

    [Float]().withUnsafeBufferPointer { ptr in
        print(Int(bitPattern: ptr.baseAddress!)) // same
        print(Int(bitPattern: ptr.baseAddress!) % 8)
    }

    [Double]().withUnsafeBufferPointer { ptr in
        print(Int(bitPattern: ptr.baseAddress!)) // same
        print(Int(bitPattern: ptr.baseAddress!) % 8)
    }

The base address is always the same value in my testing (6.0.2 release SDK and toolchain) and is always indivisible by 8 (MemoryLayout<Double>.alignment).

In theory this is probably fine, but it breaks invariants in JavaScriptKit. Specifically, JSTypedArray([Double]()) passes the base address to new Float64Array, which cannot have a base address indivisible by 8. Double arrays that actually contain values do not have this issue, presumably because there the invariant is upheld by Swift itself (aligning the first value with a memory address divisible by MemoryLayout<Double>.alignment).

This behaviour does not seem to be unique to SwiftWasm (the base address also appears stable for all empty array types, even across multiple runs of a program), but on my machine the address is divisible by 8. I guess it's because my Mac is on arm64, meaning all pointers will be aligned to the word size of 8 bytes. I'm assuming on wasm (being a 32bit platform) all pointers, at the base level, are simply required to be aligned to the word length – that doesn't appear to be enough in all cases.

To work around this, it'd probably be enough to ensure the default address is aligned to 8 instead of 4, but I'm not sure of the implications of doing that otherwise.

We have run into this problem in a number of different cases, hindering our adoption of Swift 6 so far.

Do you have any ideas on how to fix this?

@ephemer ephemer changed the title Base address of every empty array seems to be the same Base address of every empty array seems to be the same: issues where type alignment > word size Dec 5, 2024
@kateinoigakukun
Copy link
Member

The alignment requirement in TypedArray is based on its element type, (e.g. Float32Array -> 4 bytes alignment, Float64Array -> 8 bytes alignment). But as you noticed, Swift's empty array shares the same storage for all element types, so baseAddress can be unaligned. I made a change to create empty arrays without referencing Swift pointer swiftwasm/JavaScriptKit#278

@ephemer
Copy link
Author

ephemer commented Dec 9, 2024

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants