blob: 05eca98df7abaf19bd5cddf9d32009143a68b0ad [file] [log] [blame] [edit]
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package scan
import (
"internal/goarch"
"internal/runtime/gc"
"unsafe"
)
// ScanSpanPackedReference is the reference implementation of ScanScanPacked. It prioritizes clarity over performance.
//
// Concretely, ScanScanPacked functions read pointers from mem, assumed to be gc.PageSize-aligned and gc.PageSize in size,
// and writes them to bufp, which is large enough to guarantee that even if pointer-word of mem is a pointer, it will fit.
// Therefore bufp, is always at least gc.PageSize in size.
//
// ScanSpanPacked is supposed to identify pointers by first filtering words by objMarks, where each bit of the mask
// represents gc.SizeClassToSize[sizeClass] bytes of memory, and then filtering again by the bits in ptrMask.
func ScanSpanPackedReference(mem unsafe.Pointer, bufp *uintptr, objMarks *gc.ObjMask, sizeClass uintptr, ptrMask *gc.PtrMask) (count int32) {
buf := unsafe.Slice(bufp, gc.PageWords)
expandBy := uintptr(gc.SizeClassToSize[sizeClass]) / goarch.PtrSize
for word := range gc.PageWords {
objI := uintptr(word) / expandBy
if objMarks[objI/goarch.PtrBits]&(1<<(objI%goarch.PtrBits)) == 0 {
continue
}
if ptrMask[word/goarch.PtrBits]&(1<<(word%goarch.PtrBits)) == 0 {
continue
}
ptr := *(*uintptr)(unsafe.Add(mem, word*goarch.PtrSize))
if ptr == 0 {
continue
}
buf[count] = ptr
count++
}
return count
}