Skip to content

Reach the weak table's unlocked words through std::atomic - #406

Open
DTW-Thalion wants to merge 1 commit into
gnustep:masterfrom
DTW-Thalion:fix/weak-table-std-atomic
Open

Reach the weak table's unlocked words through std::atomic#406
DTW-Thalion wants to merge 1 commit into
gnustep:masterfrom
DTW-Thalion:fix/weak-table-std-atomic

Conversation

@DTW-Thalion

Copy link
Copy Markdown
Contributor

arc.mm reached two words through the atomic builtins while the reference count
word went through std::atomic. Both are on the weak-table paths: the isa word of
a control block, read without a lock by asWeakRef, and the slot of a weak
variable, written and read under whichever stripe lock owns the block it points
at.

Neither can be declared as an atomic object. The isa word has to stay layout
compatible with an object so a control block can be handed out as an id, and the
slot belongs to the caller and arrives as id* from objc_storeWeak. Both now go
through an atomic pointer instead, which is how the reference count word has
been reached since #399.

The value type is void* rather than id because an Objective-C object pointer is
not a permitted atomic value type. That is what the casts to void** in the
previous code were for.

The orderings are unchanged: relaxed on the isa publish and read, acquire and
release on the slot. arc.mm compiles to the same instructions as before, byte
for byte in the disassembly, and the 198 tests pass.

The isa word of a weak-reference control block and the slot of a weak variable
are both reached without a lock, and neither can be declared as an atomic
object: the isa word has to stay layout compatible with an object so the block
can be handed out as an id, and the slot belongs to the caller.  Both now go
through an atomic pointer, as the reference count word does, rather than
through the atomic builtins.  The value type is void* because an Objective-C
object pointer is not a permitted atomic value type.  The orderings are
unchanged and arc.mm compiles to the same instructions.
@davidchisnall

Copy link
Copy Markdown
Member

The C++ spec is actually a bit more complex here than it needs to be and there's work ongoing to simplify it. All being well, C++29 will require that all non-atomic loads and stores of primitive types behave as if they were relaxed-consistency atomic. This is, it turns out, what all compilers do anyway.

GCC accidentally forced _Atomic(T) and T to have the same representations and C++26 mandated that _Atomic(T) and std::atomic<T> must be compatible, so we're largely stuck with that. Making isa a std::atomic<void*> is technically wrong, but the set of constraints that make it technically wrong are therefore being fixed in the next version of the standard and it makes the code easier to read.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants