Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Added a reference to C/C++ and to Rust. #145

Merged
merged 4 commits into from
Sep 28, 2016
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions MEMMODEL_CONSTRAINTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ may perceive in that statement.)
for memory used for atomics. The situation is somewhat better in
well-typed C++ but reality is complicated.

## Implementation targeting C and C++ or LLVM

* _Targeting C or C++_: it should be possible to implement
SharedArrayBuffer using C or C++. The C/C++11 memory model allows
accesses with a number of orderings, and there should be a mapping
from SharedArrayBuffer accesses to C/C++11 orderings. Racy
SharedArrayBuffer accesses are required to produce defined values,
so cannot be implemented using C/C++ non-atomics.
* _Targeting LLVM_: implementations may also decide to target
LLVM, which may provide for more optimization than targeting C/C++
and compiling to LLVM. In particular, LLVM allows unordered access,
which does not require per-variable sequential consistency.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this conveys accurate information: users of C/C++ would use the language's _Atomic, std::mutex and std::atomic primitives, these would then compile to ShardArrayBuffer. Non-atomic access in these languages are racy if not synchronized properly, the same will be true with SharedArrayBuffer.

The difference SAB tries to hit is in guaranteeing values observed when races do occur.

I've outlined details of the differences here: #88

LLVM isn't that different from the C++ memory model, except it's on a per-access basis and also supports a Java-oriented memory access (which we should ignore here). I'd also mention other compilers if we're to mention LLVM.

I think it's worth mentioning languages such as Rust which have a pretty different memory model (which under the covers can lower to something like LLV IR).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I reworded this paragraph.

I'm not sure all C/C++ users will use the locking primitives, some programs may implement lock-free data structures using atomic accesses, which would then compile to SAB accesses.

I'm also not sure we'll want to ignore LLVM unordered, we could map SAB non-atomic to LLVM unordered, depending on whether SAB non-atomics are required to be coherent.

AFAIK the Rust memory model is built on top of the LLVM model (with extra guarantees for safe code).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure all C/C++ users will use the locking primitives, some programs may implement lock-free data structures using atomic accesses, which would then compile to SAB accesses.

Lock-free data structures use std::atomic. Others use std::mutex. This all maps to SAB. I'm not sure I understand what you're disagreeing with.

I'm also not sure we'll want to ignore LLVM unordered, we could map SAB non-atomic to LLVM unordered, depending on whether SAB non-atomics are required to be coherent.

It's premature to consider unordered since SAB doesn't support anything but seq_cst.

AFAIK the Rust memory model is built on top of the LLVM model (with extra guarantees for safe code).

Would be good to get @pcwalton's in put on this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, good point re std::atomic.

SAB only uses SC, but GetValueFromBuffer can call ReadSharedMemory with accessAtomic set to false, and so result in non-atomic access. I don't think there's a coherence requirement for these non-atomics, is there?

I'm talking to @nikomatsakis about Rust's model, and especially the model for unsafe code, tomorrow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SAB only uses SC, but GetValueFromBuffer can call ReadSharedMemory with accessAtomic set to false, and so result in non-atomic access. I don't think there's a coherence requirement for these non-atomics, is there?

Correct. To be more precise: we likely want to enable most optimizations which JS engines already do or could do when accessing SAB non-atomically, except where that would cause races in a SAB where no race existed before (this can happen e.g. when the optimizer speculates).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we map SAB non-atomic accesses to LLVM's unordered, I think this all the same optimizations as LLVM non-atomic. Slightly annoyingly, C11's relaxed blocks some optimizations due to coherence.

unordered isn't the same as LLVM's non-atomics.

Indeed, I'm asking whether we can implement SAB non-atomic as LLVM unordered? (In particular, is there a requirement that SAB non-atomics are coherent?)

relaxed basically only enforces same-address writes are seen in a thread's write order. You can totally reorder them, fuse them, move them around, eliminate dead ones, etc, and there's no guarantee that a relaxed write will ever be observed without synchronization actions occurring.

Relaxed operations can't be reordered as much as unordered operations, due to the requirement of coherence. For example, x=1;x=2;x=3 can't be optimized to x=2;x=1;x=3 for relaxed writes, but can for unordered.

    Targeting C or C++: it should be possible to implement
        SharedArrayBuffer using C or C++. The C/C++11 memory model allows

The wording is confusing: C/C++ should be mappable to SAB. Or are you saying that the implementation of SAB (e.g. a JS engine) is in C++? That's not really true either, because the SAB code is JIT-compiled.

I'm meaning the implementation of SAB (e.g. inside a JS engine). The question is, should it be possible to implement SAB in C++ or LLVM, or does the implementation have to be in hand-crafted asm? (This impacts my life, as someone who may be implementing the Servo interactions with SAB, if they end up being visible in the browser.)

    accesses with a number of orderings, and there should be a mapping
    from SharedArrayBuffer accesses to C/C++11 orderings. Racy

That's currently not true: only seq_cst is supported by SAB. There are issues open for other ones.

OK, what word should I use for non-atomic accesses to an SAB? Presumably non-atomic access is being mapped to something weaker than seq_cst.

    SharedArrayBuffer accesses are required to produce defined values,
    so cannot be implemented using C/C++ non-atomics.

That's not really accurate: they simply don't have the same semantics. C++ has much looser guarantees, both when it comes to races (they're simply UB) and alignment. As above I don't see SAB as being "implemented using C++".

Yes,. that's the point I'm trying to make here, SAB non-atomic accesses can't be mapped to C11 non-atomics, since racy non-atomics are UB in C11.

+* Targeting LLVM: implementations may also decide to target

    the LLVM memory model, for example by using a language such as
    Rust, which inherits its memory model from LLVM. LLVM has a very
    similar model to C/C++, but allows mixed-size access, and
    allows Java-like unordered access.

I still don't think this is accurate. Implementations of what? Are we talking about Rust -> LLVM -> SAB, or about ??? -> SAB -> LLVM?

??? -> SAB -> LLVM. This whole section is about how SAB can be implemented, not how to use it as a compilation target.

I'd also like to clarify what you mean by Rust. Sure it uses LLVM, but I don't think it's accurate to say that its memory model is LLVM's.

OK, I talked to @nikomatsakis, and the Rust memory model is still a work in progress, so while the current implementation is via LLVM (and so inherits its memory model) future implementations may provide weaker guarantees.

Copy link
Contributor

@jfbastien jfbastien Sep 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we map SAB non-atomic accesses to LLVM's unordered, I think this all the same optimizations as LLVM non-atomic. Slightly annoyingly, C11's relaxed blocks some optimizations due to coherence.

unordered isn't the same as LLVM's non-atomics.

Indeed, I'm asking whether we can implement SAB non-atomic as LLVM unordered? (In particular, is there a requirement that SAB non-atomics are coherent?)

What do you mean by "implement"?

Are you trying to compile asm.js / wasm code using SAB to LLVM IR, and trying to figure out which load / store type to use? (it sounds from your later reply that this is the case)

Or are you trying to figure out how to specify the semantics of SAB?

relaxed basically only enforces same-address writes are seen in a thread's write order. You can totally reorder them, fuse them, move them around, eliminate dead ones, etc, and there's no guarantee that a relaxed write will ever be observed without synchronization actions occurring.

Relaxed operations can't be reordered as much as unordered operations, due to the requirement of coherence. For example, x=1;x=2;x=3 can't be optimized to x=2;x=1;x=3 for relaxed writes, but can for unordered.

Sure, but that doesn't make my statement any less true:

  • Both can be optimized to x=3.
  • x+=1;y+=2;x+=3;y+=4; can be optimized to x+=4;y+=6; in both cases.

Targeting C or C++: it should be possible to implement
SharedArrayBuffer using C or C++. The C/C++11 memory model allows

The wording is confusing: C/C++ should be mappable to SAB. Or are you saying that the implementation of SAB (e.g. a JS engine) is in C++? That's not really true either, because the SAB code is JIT-compiled.

I'm meaning the implementation of SAB (e.g. inside a JS engine). The question is, should it be possible to implement SAB in C++ or LLVM, or does the implementation have to be in hand-crafted asm? (This impacts my life, as someone who may be implementing the Servo interactions with SAB, if they end up being visible in the browser.)

Implementing SAB -> LLVM IR -> x86/ARM/etc should totally be possible. As you point out it's not clear what restrictions the SAB spec is currently putting on what LLVM IR you can generate.

I'll go further to say: that shouldn't be a significant design criteria. It should be possible to lower SAB to efficient machine code, but whether LLVM is well suited or not is a fixable issue.

accesses with a number of orderings, and there should be a mapping
from SharedArrayBuffer accesses to C/C++11 orderings. Racy

That's currently not true: only seq_cst is supported by SAB. There are issues open for other ones.

OK, what word should I use for non-atomic accesses to an SAB? Presumably non-atomic access is being mapped to something weaker than seq_cst.

Now that I understand what you're trying to do (SAB -> LLVM IR -> ...) I think mentioning C++ is misleading.

Yes, SAB's non-atomics are weaker than seq_cst. It's still not well defined what that is, and exactly how it interacts with atomics.

SharedArrayBuffer accesses are required to produce defined values,
so cannot be implemented using C/C++ non-atomics.

That's not really accurate: they simply don't have the same semantics. C++ has much looser guarantees, both when it comes to races (they're simply UB) and alignment. As above I don't see SAB as being "implemented using C++".

Yes,. that's the point I'm trying to make here, SAB non-atomic accesses can't be mapped to C11 non-atomics, since racy non-atomics are UB in C11.

That's not quite right: an implementation ca decide to specify the UB we care about here. I think the question you're trying to get to is: does LLVM implement SAB's memory model so your job is simpler. I don't know because:

  • SAB's memory model isn't finalized (seq_cst is easy, non-atomics and their interactions aren't yet).
  • LLVM's optimization of atomics keep improving (maybe it does what you want now, but that may change in the future, because LLVM IR handles atomics for C++ and Java, not for SAB).

+* Targeting LLVM: implementations may also decide to target

the LLVM memory model, for example by using a language such as
Rust, which inherits its memory model from LLVM. LLVM has a very
similar model to C/C++, but allows mixed-size access, and
allows Java-like unordered access.

I still don't think this is accurate. Implementations of what? Are we talking about Rust -> LLVM -> SAB, or about ??? -> SAB -> LLVM?

??? -> SAB -> LLVM. This whole section is about how SAB can be implemented, not how to use it as a compilation target.

That wasn't clear at all to me. I'd appreciate it if you could clarify the wording.

I'd also like to clarify what you mean by Rust. Sure it uses LLVM, but I don't think it's accurate to say that its memory model is LLVM's.

OK, I talked to @nikomatsakis, and the Rust memory model is still a work in progress, so while the current implementation is via LLVM (and so inherits its memory model) future implementations may provide weaker guarantees.

I wouldn't mention it if it's a moving target. Further, if Rust's recommended parallelism datastructures are shared-nothing then this discussion is kinda misleading. I'd at least like a link referencing the Rust memory model you have in mind.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementing SAB -> LLVM IR -> x86/ARM/etc should totally be possible. As you point out it's not clear what restrictions the SAB spec is currently putting on what LLVM IR you can generate.

Yay, we seem to be on the same page now!

Now that I understand what you're trying to do (SAB -> LLVM IR -> ...) I think mentioning C++ is misleading.

OK, I can remove it and just talk about LLVM. Should I move the edits to being back under hardware if we're just talking about LLVM? Or would you still prefer a separate section?

That wasn't clear at all to me. I'd appreciate it if you could clarify the wording.

Will do.

I wouldn't mention it if it's a moving target. Further, if Rust's recommended parallelism datastructures are shared-nothing then this discussion is kinda misleading. I'd at least like a link referencing the Rust memory model you have in mind.

I'll remove Rust. If you're interested, the bit of Rust's stdlib that's of interest is the atomics, which are just a wrapper around LLVM's atomics: https://doc.rust-lang.org/std/sync/atomic/index.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you want is a section which talks about lowering from SAB to other languages, as an intermediate to some form of machine code. Given that the interactions between non-atomics and atomics aren't fully specified in SAB at the moment I think that section will be "todo" more than anything :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll give it a shot. I'm trying to provide the spec for the interaction between atomics and non-atomics over in https://github.com/asajeffrey/ecmascript_sharedmem/blob/master/MEMMODEL_WIP.md you can spot a lot of LLVM influence!


## Racy accesses and safety

* _Conflicts and races are safe_: Standard non-atomic accesses can be
Expand Down