// 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"
)

// ExpandReference is a reference implementation of an expander function
// that translates object mark bits into a bitmap of one bit per word of
// marked object, assuming the object is of the provided size class.
func ExpandReference(sizeClass int, packed *gc.ObjMask, unpacked *gc.PtrMask) {
	// Look up the size and derive the number of objects in a span.
	// We're only concerned with small objects in single-page spans,
	// and gc.PtrMask enforces this by being statically sized to
	// accommodate only such spans.
	size := uintptr(gc.SizeClassToSize[sizeClass])
	nObj := uintptr(gc.SizeClassToNPages[sizeClass]) * gc.PageSize / size

	// f is the expansion factor. For example, if our objects are of size 48,
	// then each mark bit will translate into 6 (48/8 = 6) set bits in the
	// pointer bitmap.
	f := size / goarch.PtrSize
	for i := range nObj {
		// Check if the object is marked.
		if packed[i/goarch.PtrBits]&(uintptr(1)<<(i%goarch.PtrBits)) == 0 {
			continue
		}
		// Propagate that mark into the destination into one bit per the
		// expansion factor f, offset to the object's offset within the span.
		for j := range f {
			b := i*f + j // i*f is the start bit for the object, j indexes into each corresponding word after.
			unpacked[b/goarch.PtrBits] |= uintptr(1) << (b % goarch.PtrBits)
		}
	}
}
