-
Notifications
You must be signed in to change notification settings - Fork 695
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
wasm64, >4 GiB indexing, and a 64-bit lock-free guarantee #336
Conversation
According to clang, all common 64-bit CPUs, x86-64, arm64, mips64, ppc64, sparcv9, and systemz (and bpf, if that counts) support a 64-bit integer type as "lock free". In the spirit of #327, this is a significant agreement among 64-bit architectures, but not 32-bit architectures. I propose we think about the >4GiB linear memory feature as belonging to a distinct "architecture" called *wasm64*, when we need to distinguish it from *wasm32*. This will allow us to say that wasm64 has up to 64-bit lock-free integers, while wasm32 only has up to 32-bit lock-free integers. If we add signal handling it could also let us say that wasm64 has up to 64-bit signal-atomic integers (sig_atomic_t). It would also make it obvious what types to use around page_size and resize_memory. Except where it makes sense to make them different, wasm32 and wasm64 would otherwise be kept identical. In particular, wasm32 would still have 64-bit integers. The main negative consequence of this distinction is that wasm64 code would not be supported on many popular 32-bit CPUs. This is unfortunate, but it would already be the case that code using 64-bit pointers wouldn't run as efficiently as code using 32-bit pointers on 32-bit platforms. There's a desire to leave open the possibility of having both 32-bit and 64-bit linear memory addressing within a single instance. wasm64 could still be made to support mixing 64-bit indices and 32-bit indices if we choose, for example. We could potentially even permit wasm32 libraries to be linked into wasm64 applications (though there would of course be ABI complications at the C/C++ level, non-C/C++ code might be able to take advantage of this).
I think the biggest downside to this is requiring shared modules to be either wasm32 or wasm64. The instance already has to declare peak address space requirements up front, so it's obvious whether a statically linked program can use 32-bit addresses or not up front, but it's not so obvious for a shared module. One way to hide the lack of universal 64-bit atomics is by adding a pointer type to WASM that is always 64-bits, but allows 32-bit runtimes to ignore the top 32-bits. Lock-free atomics on pointers could be guaranteed by allowing 32-bit runtimes to use 32-bit atomics on the lower half of the 64-bits allocated for the pointer in memory. There would be a few downsides:
But the upside is that then WASM only needs a single architecture. 64-bit runtimes don't need to support 32-bit pointers, and 32-bit runtimes can use any module as long as an instance doesn't need too much memory. I think that's worth some superfluous pointer bits. |
@AndrewScheidecker: Doubling the pointer size means a significant regression in performance, probably comparable to the x32/x86-64 difference which is 5-8% in throughput, in addition to using significantly more memory. |
No way to allow feature detection for code to provide fallback or exit early? |
The cost should be less than x32 vs x86-64, since pointers could still be 32-bit values when not stored in memory. I don't know if that saves a lot, but the cost should limited to the additional memory use and less effective use of the cache+memory bandwidth. (I'm assuming that there will be a pointer type for local and intermediate values to distinguish them from specifically sized integers) This is just my opinion, but I would be fine with losing 10% throughput on 32-bit runtimes if it enabled a single wasm "architecture". You could also keep the wasm32/wasm64 distinction and just use this trick to support wasm64 on 32-bit runtimes. But I think if wasm64 is universally supported with ok performance, then nearly everybody will use it over wasm32. |
@AndrewScheidecker wasm64 with index masking already gives you these 'pointers'. When the linear memory size is within 32 bits the top 32 bits are masked off and the compiler can optimize the code when running on 32 bit runtimes to often use 32 bit ops. The storage will still be 64 bits. I expect a lot of apps will not need wasm64 and will continue to use wasm32 if only for lower memory usage. If there is good support for global constants that can be initialized based on the linear memory size then perhaps the code could adapt to the storage size of pointers, at least in part. |
@sunfishcode Generally lgtm, though I think it'd be good phrase |
As discussed offline, this lgtm. I expect that we'll refine our thinking as we implement more, but this seems like a good step forward. |
Updated to include a mention that wasm64 is just a mode bit present in the module. |
Updated to add a mention of a feature-test API. |
|
||
## Why have wasm32 and wasm64, instead of just using 8 bytes for storing pointers? | ||
|
||
A great number of applications that don't ever need as much as 4 GiB of memory. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/that //
Looks great, thanks! The Knuth quote is a nice cherry on top. |
lgtm, I fixed @lukewagner's nit and will now merge. Agreed on the Knuth quote, very nice :-) |
wasm64, >4 GiB indexing, and a 64-bit lock-free guarantee
According to clang, all common 64-bit CPUs, x86-64, arm64, mips64, ppc64, sparcv9, and systemz (and bpf, if that counts) support a 64-bit integer type as "lock free". In the spirit of #327, this is a significant agreement among 64-bit architectures, but not 32-bit architectures.
I propose we think about the >4GiB linear memory feature as belonging to a distinct "architecture" called wasm64, when we need to distinguish it from wasm32. This will allow us to say that wasm64 has up to 64-bit lock-free integers, while wasm32 only has up to 32-bit lock-free integers. If we add signal handling it could also let us say that wasm64 has up to 64-bit signal-atomic integers (sig_atomic_t). It would also make it obvious what types to use around page_size and resize_memory.
Except where it makes sense to make them different, wasm32 and wasm64 would otherwise be kept identical. In particular, wasm32 would still have 64-bit integers.
The main negative consequence of this distinction is that wasm64 code would not be supported on many popular 32-bit CPUs. This is unfortunate, but it would already be the case that code using 64-bit pointers wouldn't run as efficiently as code using 32-bit pointers on 32-bit platforms.
There's a desire to leave open the possibility of having both 32-bit and 64-bit linear memory addressing within a single instance. wasm64 could still be made to support mixing 64-bit indices and 32-bit indices if we choose, for example. We could potentially even permit wasm32 libraries to be linked into wasm64 applications (though there would of course be ABI complications at the C/C++ level, non-C/C++ code might be able to take advantage of this).