github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/runtime/mbarrier.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Garbage collector: write barriers. 6 // 7 // For the concurrent garbage collector, the Go compiler implements 8 // updates to pointer-valued fields that may be in heap objects by 9 // emitting calls to write barriers. This file contains the actual write barrier 10 // implementation, gcmarkwb_m, and the various wrappers called by the 11 // compiler to implement pointer assignment, slice assignment, 12 // typed memmove, and so on. 13 14 package runtime 15 16 import ( 17 "runtime/internal/sys" 18 "unsafe" 19 ) 20 21 // gcmarkwb_m is the mark-phase write barrier, the only barrier we have. 22 // The rest of this file exists only to make calls to this function. 23 // 24 // This is a hybrid barrier that combines a Yuasa-style deletion 25 // barrier—which shades the object whose reference is being 26 // overwritten—with Dijkstra insertion barrier—which shades the object 27 // whose reference is being written. The insertion part of the barrier 28 // is necessary while the calling goroutine's stack is grey. In 29 // pseudocode, the barrier is: 30 // 31 // writePointer(slot, ptr): 32 // shade(*slot) 33 // if current stack is grey: 34 // shade(ptr) 35 // *slot = ptr 36 // 37 // slot is the destination in Go code. 38 // ptr is the value that goes into the slot in Go code. 39 // 40 // Shade indicates that it has seen a white pointer by adding the referent 41 // to wbuf as well as marking it. 42 // 43 // The two shades and the condition work together to prevent a mutator 44 // from hiding an object from the garbage collector: 45 // 46 // 1. shade(*slot) prevents a mutator from hiding an object by moving 47 // the sole pointer to it from the heap to its stack. If it attempts 48 // to unlink an object from the heap, this will shade it. 49 // 50 // 2. shade(ptr) prevents a mutator from hiding an object by moving 51 // the sole pointer to it from its stack into a black object in the 52 // heap. If it attempts to install the pointer into a black object, 53 // this will shade it. 54 // 55 // 3. Once a goroutine's stack is black, the shade(ptr) becomes 56 // unnecessary. shade(ptr) prevents hiding an object by moving it from 57 // the stack to the heap, but this requires first having a pointer 58 // hidden on the stack. Immediately after a stack is scanned, it only 59 // points to shaded objects, so it's not hiding anything, and the 60 // shade(*slot) prevents it from hiding any other pointers on its 61 // stack. 62 // 63 // For a detailed description of this barrier and proof of 64 // correctness, see https://github.com/golang/proposal/blob/master/design/17503-eliminate-rescan.md 65 // 66 // 67 // 68 // Dealing with memory ordering: 69 // 70 // Both the Yuasa and Dijkstra barriers can be made conditional on the 71 // color of the object containing the slot. We chose not to make these 72 // conditional because the cost of ensuring that the object holding 73 // the slot doesn't concurrently change color without the mutator 74 // noticing seems prohibitive. 75 // 76 // Consider the following example where the mutator writes into 77 // a slot and then loads the slot's mark bit while the GC thread 78 // writes to the slot's mark bit and then as part of scanning reads 79 // the slot. 80 // 81 // Initially both [slot] and [slotmark] are 0 (nil) 82 // Mutator thread GC thread 83 // st [slot], ptr st [slotmark], 1 84 // 85 // ld r1, [slotmark] ld r2, [slot] 86 // 87 // Without an expensive memory barrier between the st and the ld, the final 88 // result on most HW (including 386/amd64) can be r1==r2==0. This is a classic 89 // example of what can happen when loads are allowed to be reordered with older 90 // stores (avoiding such reorderings lies at the heart of the classic 91 // Peterson/Dekker algorithms for mutual exclusion). Rather than require memory 92 // barriers, which will slow down both the mutator and the GC, we always grey 93 // the ptr object regardless of the slot's color. 94 // 95 // Another place where we intentionally omit memory barriers is when 96 // accessing mheap_.arena_used to check if a pointer points into the 97 // heap. On relaxed memory machines, it's possible for a mutator to 98 // extend the size of the heap by updating arena_used, allocate an 99 // object from this new region, and publish a pointer to that object, 100 // but for tracing running on another processor to observe the pointer 101 // but use the old value of arena_used. In this case, tracing will not 102 // mark the object, even though it's reachable. However, the mutator 103 // is guaranteed to execute a write barrier when it publishes the 104 // pointer, so it will take care of marking the object. A general 105 // consequence of this is that the garbage collector may cache the 106 // value of mheap_.arena_used. (See issue #9984.) 107 // 108 // 109 // Stack writes: 110 // 111 // The compiler omits write barriers for writes to the current frame, 112 // but if a stack pointer has been passed down the call stack, the 113 // compiler will generate a write barrier for writes through that 114 // pointer (because it doesn't know it's not a heap pointer). 115 // 116 // One might be tempted to ignore the write barrier if slot points 117 // into to the stack. Don't do it! Mark termination only re-scans 118 // frames that have potentially been active since the concurrent scan, 119 // so it depends on write barriers to track changes to pointers in 120 // stack frames that have not been active. 121 // 122 // 123 // Global writes: 124 // 125 // The Go garbage collector requires write barriers when heap pointers 126 // are stored in globals. Many garbage collectors ignore writes to 127 // globals and instead pick up global -> heap pointers during 128 // termination. This increases pause time, so we instead rely on write 129 // barriers for writes to globals so that we don't have to rescan 130 // global during mark termination. 131 // 132 // 133 // Publication ordering: 134 // 135 // The write barrier is *pre-publication*, meaning that the write 136 // barrier happens prior to the *slot = ptr write that may make ptr 137 // reachable by some goroutine that currently cannot reach it. 138 // 139 // 140 //go:nowritebarrierrec 141 //go:systemstack 142 func gcmarkwb_m(slot *uintptr, ptr uintptr) { 143 if writeBarrier.needed { 144 // Note: This turns bad pointer writes into bad 145 // pointer reads, which could be confusing. We avoid 146 // reading from obviously bad pointers, which should 147 // take care of the vast majority of these. We could 148 // patch this up in the signal handler, or use XCHG to 149 // combine the read and the write. Checking inheap is 150 // insufficient since we need to track changes to 151 // roots outside the heap. 152 // 153 // Note: profbuf.go omits a barrier during signal handler 154 // profile logging; that's safe only because this deletion barrier exists. 155 // If we remove the deletion barrier, we'll have to work out 156 // a new way to handle the profile logging. 157 if slot1 := uintptr(unsafe.Pointer(slot)); slot1 >= minPhysPageSize { 158 if optr := *slot; optr != 0 { 159 shade(optr) 160 } 161 } 162 // TODO: Make this conditional on the caller's stack color. 163 if ptr != 0 && inheap(ptr) { 164 shade(ptr) 165 } 166 } 167 } 168 169 // writebarrierptr_prewrite1 invokes a write barrier for *dst = src 170 // prior to the write happening. 171 // 172 // Write barrier calls must not happen during critical GC and scheduler 173 // related operations. In particular there are times when the GC assumes 174 // that the world is stopped but scheduler related code is still being 175 // executed, dealing with syscalls, dealing with putting gs on runnable 176 // queues and so forth. This code cannot execute write barriers because 177 // the GC might drop them on the floor. Stopping the world involves removing 178 // the p associated with an m. We use the fact that m.p == nil to indicate 179 // that we are in one these critical section and throw if the write is of 180 // a pointer to a heap object. 181 //go:nosplit 182 func writebarrierptr_prewrite1(dst *uintptr, src uintptr) { 183 mp := acquirem() 184 if mp.inwb || mp.dying > 0 { 185 // We explicitly allow write barriers in startpanic_m, 186 // since we're going down anyway. Ignore them here. 187 releasem(mp) 188 return 189 } 190 systemstack(func() { 191 if mp.p == 0 && memstats.enablegc && !mp.inwb && inheap(src) { 192 throw("writebarrierptr_prewrite1 called with mp.p == nil") 193 } 194 mp.inwb = true 195 gcmarkwb_m(dst, src) 196 }) 197 mp.inwb = false 198 releasem(mp) 199 } 200 201 // NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer, 202 // but if we do that, Go inserts a write barrier on *dst = src. 203 //go:nosplit 204 func writebarrierptr(dst *uintptr, src uintptr) { 205 if writeBarrier.cgo { 206 cgoCheckWriteBarrier(dst, src) 207 } 208 if !writeBarrier.needed { 209 *dst = src 210 return 211 } 212 if src != 0 && src < minPhysPageSize { 213 systemstack(func() { 214 print("runtime: writebarrierptr *", dst, " = ", hex(src), "\n") 215 throw("bad pointer in write barrier") 216 }) 217 } 218 writebarrierptr_prewrite1(dst, src) 219 *dst = src 220 } 221 222 // writebarrierptr_prewrite is like writebarrierptr, but the store 223 // will be performed by the caller after this call. The caller must 224 // not allow preemption between this call and the write. 225 // 226 //go:nosplit 227 func writebarrierptr_prewrite(dst *uintptr, src uintptr) { 228 if writeBarrier.cgo { 229 cgoCheckWriteBarrier(dst, src) 230 } 231 if !writeBarrier.needed { 232 return 233 } 234 if src != 0 && src < minPhysPageSize { 235 systemstack(func() { throw("bad pointer in write barrier") }) 236 } 237 writebarrierptr_prewrite1(dst, src) 238 } 239 240 // typedmemmove copies a value of type t to dst from src. 241 // Must be nosplit, see #16026. 242 // 243 // TODO: Perfect for go:nosplitrec since we can't have a safe point 244 // anywhere in the bulk barrier or memmove. 245 // 246 //go:nosplit 247 func typedmemmove(typ *_type, dst, src unsafe.Pointer) { 248 if typ.kind&kindNoPointers == 0 { 249 bulkBarrierPreWrite(uintptr(dst), uintptr(src), typ.size) 250 } 251 // There's a race here: if some other goroutine can write to 252 // src, it may change some pointer in src after we've 253 // performed the write barrier but before we perform the 254 // memory copy. This safe because the write performed by that 255 // other goroutine must also be accompanied by a write 256 // barrier, so at worst we've unnecessarily greyed the old 257 // pointer that was in src. 258 memmove(dst, src, typ.size) 259 if writeBarrier.cgo { 260 cgoCheckMemmove(typ, dst, src, 0, typ.size) 261 } 262 } 263 264 //go:linkname reflect_typedmemmove reflect.typedmemmove 265 func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) { 266 if raceenabled { 267 raceWriteObjectPC(typ, dst, getcallerpc(), funcPC(reflect_typedmemmove)) 268 raceReadObjectPC(typ, src, getcallerpc(), funcPC(reflect_typedmemmove)) 269 } 270 if msanenabled { 271 msanwrite(dst, typ.size) 272 msanread(src, typ.size) 273 } 274 typedmemmove(typ, dst, src) 275 } 276 277 // typedmemmovepartial is like typedmemmove but assumes that 278 // dst and src point off bytes into the value and only copies size bytes. 279 //go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial 280 func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size uintptr) { 281 if writeBarrier.needed && typ.kind&kindNoPointers == 0 && size >= sys.PtrSize { 282 // Pointer-align start address for bulk barrier. 283 adst, asrc, asize := dst, src, size 284 if frag := -off & (sys.PtrSize - 1); frag != 0 { 285 adst = add(dst, frag) 286 asrc = add(src, frag) 287 asize -= frag 288 } 289 bulkBarrierPreWrite(uintptr(adst), uintptr(asrc), asize&^(sys.PtrSize-1)) 290 } 291 292 memmove(dst, src, size) 293 if writeBarrier.cgo { 294 cgoCheckMemmove(typ, dst, src, off, size) 295 } 296 } 297 298 // reflectcallmove is invoked by reflectcall to copy the return values 299 // out of the stack and into the heap, invoking the necessary write 300 // barriers. dst, src, and size describe the return value area to 301 // copy. typ describes the entire frame (not just the return values). 302 // typ may be nil, which indicates write barriers are not needed. 303 // 304 // It must be nosplit and must only call nosplit functions because the 305 // stack map of reflectcall is wrong. 306 // 307 //go:nosplit 308 func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr) { 309 if writeBarrier.needed && typ != nil && typ.kind&kindNoPointers == 0 && size >= sys.PtrSize { 310 bulkBarrierPreWrite(uintptr(dst), uintptr(src), size) 311 } 312 memmove(dst, src, size) 313 } 314 315 //go:nosplit 316 func typedslicecopy(typ *_type, dst, src slice) int { 317 // TODO(rsc): If typedslicecopy becomes faster than calling 318 // typedmemmove repeatedly, consider using during func growslice. 319 n := dst.len 320 if n > src.len { 321 n = src.len 322 } 323 if n == 0 { 324 return 0 325 } 326 dstp := dst.array 327 srcp := src.array 328 329 // The compiler emits calls to typedslicecopy before 330 // instrumentation runs, so unlike the other copying and 331 // assignment operations, it's not instrumented in the calling 332 // code and needs its own instrumentation. 333 if raceenabled { 334 callerpc := getcallerpc() 335 pc := funcPC(slicecopy) 336 racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc) 337 racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc) 338 } 339 if msanenabled { 340 msanwrite(dstp, uintptr(n)*typ.size) 341 msanread(srcp, uintptr(n)*typ.size) 342 } 343 344 if writeBarrier.cgo { 345 cgoCheckSliceCopy(typ, dst, src, n) 346 } 347 348 // Note: No point in checking typ.kind&kindNoPointers here: 349 // compiler only emits calls to typedslicecopy for types with pointers, 350 // and growslice and reflect_typedslicecopy check for pointers 351 // before calling typedslicecopy. 352 size := uintptr(n) * typ.size 353 if writeBarrier.needed { 354 bulkBarrierPreWrite(uintptr(dstp), uintptr(srcp), size) 355 } 356 // See typedmemmove for a discussion of the race between the 357 // barrier and memmove. 358 memmove(dstp, srcp, size) 359 return n 360 } 361 362 //go:linkname reflect_typedslicecopy reflect.typedslicecopy 363 func reflect_typedslicecopy(elemType *_type, dst, src slice) int { 364 if elemType.kind&kindNoPointers != 0 { 365 n := dst.len 366 if n > src.len { 367 n = src.len 368 } 369 if n == 0 { 370 return 0 371 } 372 373 size := uintptr(n) * elemType.size 374 if raceenabled { 375 callerpc := getcallerpc() 376 pc := funcPC(reflect_typedslicecopy) 377 racewriterangepc(dst.array, size, callerpc, pc) 378 racereadrangepc(src.array, size, callerpc, pc) 379 } 380 if msanenabled { 381 msanwrite(dst.array, size) 382 msanread(src.array, size) 383 } 384 385 memmove(dst.array, src.array, size) 386 return n 387 } 388 return typedslicecopy(elemType, dst, src) 389 } 390 391 // typedmemclr clears the typed memory at ptr with type typ. The 392 // memory at ptr must already be initialized (and hence in type-safe 393 // state). If the memory is being initialized for the first time, see 394 // memclrNoHeapPointers. 395 // 396 // If the caller knows that typ has pointers, it can alternatively 397 // call memclrHasPointers. 398 // 399 //go:nosplit 400 func typedmemclr(typ *_type, ptr unsafe.Pointer) { 401 if typ.kind&kindNoPointers == 0 { 402 bulkBarrierPreWrite(uintptr(ptr), 0, typ.size) 403 } 404 memclrNoHeapPointers(ptr, typ.size) 405 } 406 407 // memclrHasPointers clears n bytes of typed memory starting at ptr. 408 // The caller must ensure that the type of the object at ptr has 409 // pointers, usually by checking typ.kind&kindNoPointers. However, ptr 410 // does not have to point to the start of the allocation. 411 // 412 //go:nosplit 413 func memclrHasPointers(ptr unsafe.Pointer, n uintptr) { 414 bulkBarrierPreWrite(uintptr(ptr), 0, n) 415 memclrNoHeapPointers(ptr, n) 416 }