Skip to content

Commit de3a3c9

Browse files
committed
runtime: make zeroing of large objects containing pointers preemptible
This change makes it possible for the runtime to preempt the zeroing of large objects that contain pointers. It turns out this is fairly straightforward with allocation headers, since we can just temporarily tell the GC that there's nothing to scan for a large object with a single pointer write (as opposed to trying to zero a whole bunch of bits, as we would've had to do once upon a time). Fixes #31222. Change-Id: I10d0dcfa3938c383282a3eb485a6f00070d07bd2 Reviewed-on: https://go-review.googlesource.com/c/go/+/577495 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 9f3f4c6 commit de3a3c9

File tree

2 files changed

+21
-13
lines changed

2 files changed

+21
-13
lines changed

src/runtime/malloc.go

+17-13
Original file line numberDiff line numberDiff line change
@@ -1165,17 +1165,15 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
11651165
size = span.elemsize
11661166
x = unsafe.Pointer(span.base())
11671167
if needzero && span.needzero != 0 {
1168-
if noscan {
1169-
delayedZeroing = true
1170-
} else {
1171-
memclrNoHeapPointers(x, size)
1172-
}
1168+
delayedZeroing = true
11731169
}
11741170
if !noscan {
1171+
// Tell the GC not to look at this yet.
1172+
span.largeType = nil
11751173
header = &span.largeType
11761174
}
11771175
}
1178-
if !noscan {
1176+
if !noscan && !delayedZeroing {
11791177
c.scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span)
11801178
}
11811179

@@ -1243,17 +1241,23 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
12431241
mp.mallocing = 0
12441242
releasem(mp)
12451243

1246-
// Pointerfree data can be zeroed late in a context where preemption can occur.
1244+
// Objects can be zeroed late in a context where preemption can occur.
1245+
// If the object contains pointers, its pointer data must be cleared
1246+
// or otherwise indicate that the GC shouldn't scan it.
12471247
// x will keep the memory alive.
12481248
if delayedZeroing {
1249-
if !noscan {
1250-
throw("delayed zeroing on data that may contain pointers")
1251-
}
1252-
if header != nil {
1253-
throw("unexpected malloc header in delayed zeroing of large object")
1254-
}
12551249
// N.B. size == fullSize always in this case.
12561250
memclrNoHeapPointersChunked(size, x) // This is a possible preemption point: see #47302
1251+
1252+
// Finish storing the type information for this case.
1253+
if !noscan {
1254+
mp := acquirem()
1255+
getMCache(mp).scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span)
1256+
1257+
// Publish the type information with the zeroed memory.
1258+
publicationBarrier()
1259+
releasem(mp)
1260+
}
12571261
}
12581262

12591263
if debug.malloc {

src/runtime/mbitmap.go

+4
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ func (span *mspan) typePointersOfUnchecked(addr uintptr) typePointers {
192192
addr += mallocHeaderSize
193193
} else {
194194
typ = span.largeType
195+
if typ == nil {
196+
// Allow a nil type here for delayed zeroing. See mallocgc.
197+
return typePointers{}
198+
}
195199
}
196200
gcdata := typ.GCData
197201
return typePointers{elem: addr, addr: addr, mask: readUintptr(gcdata), typ: typ}

0 commit comments

Comments
 (0)