-
Notifications
You must be signed in to change notification settings - Fork 57
Interaction with the memory model & atomic operations #78
Comments
Thanks for raising this issue; not sure how it fell off my radar. FWIW memory model/atomics behavior is currently "handled" because ValidateSharedIntegerTypedArray would throw on a BigInt64Array/BigUint64Array, and all atomic operations are prohibited. For the memory model, because BigUint64 and BigInt64 are not on the noTear list in SetValueInBuffer, which means that the semantics you're suggesting in (1) is already the specification. Seems like supporting most of the atomics would be just a matter of removing the prohibition on BigUint64 and BigInt64 and making sure BigInts are handled separately from Numbers. I don't see any other changes that would be needed, but I don't understand all the memory model details, if any changes are needed there. For Atomics.wait/Atomics.wake, I'm not sure what the semantics are supposed to be. If you do a 64-bit wait, and wake one or both of the 32-bit segments contained in it, what happens? Does it wait for both of them? Does a 64-bit wake wake all 32-bit waiters on each half? Does Wasm have consensus on whether it will introduce an i64 wait? In WebAssembly/threads#7 , it sounded like there wasn't consensus one way or the other. For (3), presumably by a sort of AR.[[IsLockFree8]], right? This would return false on MIPS32 then and true on x86, for example. |
I believe, like you, that it would be easy to fix the atomics. (Also I think it's desirable to do so.) SetValueInBuffer might need a little more work but I don't think it'll be bad. I mostly want to make sure we don't spec something we can't afford to implement.
Since wasm operates on byte addresses it's the address that you wait on that matters, and that's the address the two different-sized waits and the wake must agree on. If one agent performs a 64-bit wait on address A and the other performs a wake on A+4 (or A+3 for that matter, as it can) then there is no wakeup. Indeed after the cell value has been checked the size of the wait is irrelevant, only the byte address matters. In JS we could expose that behavior to explain the corner cases, since, by and large, everyone will use the same element size to wake on as they used to wait on and won't have to worry about it. It would be legal to wake on either an int32 array or int64 array but if you don't use the same element size for waking as you did for waiting you have to take care.
I believe so.
Indeed, but there was an in-person meeting in July, and the issue was settled IIRC, anyway the instruction for int64 wait is in the wasm threads proposal and I'm seeing no pushback. It's a useful feature.
I think so. |
Previously, it was left up for future integration details to allow BigInt64Array and BigUint64Array to use atomic operations. This patch spells out the details of how these should work. The semantics of Atomics.wait/wake are based on doing the wait/wake on the relevant index of the underlying memory. For example, a 64-bit wait would be woken up by a 32-bit wake at twice the index. Non-atomic writes to BigInt64Arrays can be torn, following the memory model for Float64Array. In some places in internal spec names, `Int64` is replaced by `BigInt64` for consistency. Addresses #78
Previously, it was left up for future integration details to allow BigInt64Array and BigUint64Array to use atomic operations. This patch spells out the details of how these should work. The semantics of Atomics.wait/wake are based on doing the wait/wake on the relevant index of the underlying memory. For example, a 64-bit wait would be woken up by a 32-bit wake at twice the index. Non-atomic writes to BigInt64Arrays can be torn, following the memory model for Float64Array. In some places in internal spec names, `Int64` is replaced by `BigInt64` for consistency. Addresses #78
Previously, it was left up for future integration details to allow BigInt64Array and BigUint64Array to use atomic operations. This patch spells out the details of how these should work. The semantics of Atomics.wait/wake are based on doing the wait/wake on the relevant index of the underlying memory. For example, a 64-bit wait would be woken up by a 32-bit wake at twice the index. Non-atomic writes to BigInt64Arrays can be torn, following the memory model for Float64Array. In some places in internal spec names, `Int64` is replaced by `BigInt64` for consistency. Addresses #78
This should be fixed now; please reopen if you see any missing details. The semantics were reviewed at the September 2017 TC39 meeting, reached consensus, and the patch was merged as a result. |
It seems the Also, |
Good point, we need an [[IsLockFree8]] property and one more step in Atomics.isLockFree. As for the store (and presumably the same problem in Atomics.load?) one could fix this by passing another parameter |
@littledan, I'm not able to reopen this for some reason, can you perhaps do it? |
@jakobkummerow Thanks for these reports. I'll work on patches for these today. |
One more note about this: it took @jakobkummerow and myself quite a bit of digging through the spec, this issue, the meeting notes, etc., to get to the point where we understood the intent of the spec. I think it would have been useful to have a non-normative note somewhere explaining the intent is to have no guarantees about tearing for non-atomic operations, but support for Int64 and Uint64 atomic ops. I know it can be tricky to figure out where to put such notes, but thought it was worth a mention. |
@ajklein Feel free to contact me any time if you're wondering about the intent of this specification. As for a note in the specification, there already was the following note:
I'm not sure what else to write besides this. Would it be meaningful to write atomic writes should be atomic, and that any deviation from that is a bug in the specification? |
@littledan Thanks for the pointer to the existing text. That indeed seems like it covers the non-atomic side pretty well. For the atomic side, I think additions to the existing non-normative text in the "Agents" section around |
@ajklein Thanks for the suggestion. Added a note under |
The patch with the specification fixes have landed, and I haven't heard any more concerns about this issue, so closing. Please feel free to post any more concerns here and we can reopen it if they come up. |
(Surely you saw this coming? :-)
I assume that BigInt64 and BigUint64 TypedArrays can also be applied to SharedArrayBuffers. This raises the issue of how valus of these views are loaded and stored in shared memory.
(1) Currently the memory model guarantees that certain racy accesses are executed as-if atomic, specifically, if you have racy writes of the same size to the same location they are written one after another, parts of values are not interleaved (they do not "tear"). Reads that are performed during such a race will observe the value initially in memory, or one of the values written. Values will not fluctuate; once a value is written, the cell does not revert spontaneously to a previous value, at least not when viewed from a single observer.
Ideally we would simply extend this scheme to 64-bit integers. Doing so has some costs, however. On many 32-bit systems there are no simple non-tearing 64-bit access instructions, though one can emulate them expensively with full atomic operations; this is the case on x86 and on many ARMv7 models. On some 32-bit systems there are no non-tearing 64-bit access instructions at all; this is the case on MIPS32 and many ARMv6 models.
IMO it is possible to get away with allowing 64-bit integers to be loaded and stored racily in parts, ie, we guarantee non-tearing behavior up to 4 bytes, as JS has now, but after that nothing. (Anyone needing to store an int64 atomically would then use a lock.) Accessing int64 values atomically is nice, but in that case one should use an atomic operation. Which leads me to:
(2) Should the Atomics object be extended to loading and storing 64-bit values? (WebAssembly will provide 64-bit atomics, as well as a 64-bit version of Atomics.wait.) These are not constrained in the same way as the racy accesses, because they can use spinlocks behind the scenes on the few platforms that can't accomodate them directly (such as MIPS32).
(3) If we provide 64-bit atomic operations we also want to upgrade Atomics.isLockFree(8) to have a useful value, not always
false
as now.The text was updated successfully, but these errors were encountered: