// barriers, which will slow down both the mutator and the GC, we always grey
// the ptr object regardless of the slot's color.
//
+// Another place where we intentionally omit memory barriers is when
+// accessing mheap_.arena_used to check if a pointer points into the
+// heap. On relaxed memory machines, it's possible for a mutator to
+// extend the size of the heap by updating arena_used, allocate an
+// object from this new region, and publish a pointer to that object,
+// but for tracing running on another processor to observe the pointer
+// but use the old value of arena_used. In this case, tracing will not
+// mark the object, even though it's reachable. However, the mutator
+// is guaranteed to execute a write barrier when it publishes the
+// pointer, so it will take care of marking the object. A general
+// consequence of this is that the garbage collector may cache the
+// value of mheap_.arena_used. (See issue #9984.)
+//
//
// Stack writes:
//
// object (it ignores n).
//go:nowritebarrier
func scanobject(b uintptr, gcw *gcWork) {
+ // Note that arena_used may change concurrently during
+ // scanobject and hence scanobject may encounter a pointer to
+ // a newly allocated heap object that is *not* in
+ // [start,used). It will not mark this object; however, we
+ // know that it was just installed by a mutator, which means
+ // that mutator will execute a write barrier and take care of
+ // marking it. This is even more pronounced on relaxed memory
+ // architectures since we access arena_used without barriers
+ // or synchronization, but the same logic applies.
arena_start := mheap_.arena_start
arena_used := mheap_.arena_used