func (bv *gcBitvector) isPointer(addr uint64) bool {
	bit := (addr - bv.seg.addr) / bv.ptrSize
	if bit >= bv.nbits {
		return false
	}
	return ((uint8(bv.bits[bit/8]) >> (bit % 8)) & 1) != 0
}
isPointer reports whether addr contains a pointer.
Returns false if addr is outside the range of this bitvector.
package corefile
import (
	"bytes"
	"fmt"
	"sort"
)
func min(x, y uint64) uint64 {
	if x < y {
		return x
	}
	return y
}
func max(x, y uint64) uint64 {
	if x > y {
		return x
	}
	return y
}
func roundDown(x, align uint64) uint64 {
	return x - x%align
}
func roundUp(x, align uint64) uint64 {
	return align * ((x + align - 1) / align)
}
type programBitvector struct {
	chunks  []programBitvectorChunk
	ptrSize uint64  
}
type programBitvectorChunk struct {
	addr uint64    
	size uint64    
	bits []uint64  
}
func newProgramBitvector(p *Program) *programBitvector {
	bv := &programBitvector{
		ptrSize: uint64(p.RuntimeLibrary.Arch.PointerSize),
	}
	for _, s := range p.dataSegments {
		start := roundDown(s.addr, bv.ptrSize)
		end := roundUp(s.addr+s.size(), bv.ptrSize)
		chunk := programBitvectorChunk{
			addr: start,
			size: end - start,
			bits: make([]uint64, (end-start)/bv.ptrSize/8),
		}
		bv.chunks = append(bv.chunks, chunk)
	}
	return bv
}
func (bv *programBitvector) acquireRange(addr, size uint64) bool {
	if size == 0 {
		return false
	}
	k := sort.Search(len(bv.chunks), func(k int) bool {
		return addr < bv.chunks[k].addr
	})
	if k > 0 {
		k--
		if bv.chunks[k].addr+bv.chunks[k].size <= addr {
			k++
		}
	}
	end := addr + size - 1
	changed := false
	for ; k < len(bv.chunks) && bv.chunks[k].addr <= end; k++ {
		if bv.chunks[k].acquireRange(addr, size, bv.ptrSize) {
			changed = true
		}
	}
	return changed
}
func (chunk *programBitvectorChunk) acquireRange(addrStart, size, ptrSize uint64) bool {
	addrStart = max(addrStart, chunk.addr)
	addrEnd := min(addrStart+size, chunk.addr+chunk.size)
	offsetStart := addrStart - chunk.addr
	offsetEnd := addrEnd - chunk.addr
	bit := offsetStart / ptrSize
	bitEnd := roundUp(offsetEnd, ptrSize) / ptrSize
	changed := false
	for ; bit < bitEnd; bit++ {
		mask := uint64(1) << (bit % 8)
		if chunk.bits[bit/8]&mask == 0 {
			chunk.bits[bit/8] |= mask
			changed = true
		}
	}
	return changed
}
type gcBitvector struct {
	bits    []byte
	nbits   uint64
	ptrSize uint64
	seg     dataSegment  
}
var gcEmptyBitvector = &gcBitvector{
	bits: make([]byte, 0),
}
func newGCBitvector(p *Program, seg dataSegment, bits []byte, nbits uint64) *gcBitvector {
	ptrSize := uint64(p.RuntimeLibrary.Arch.PointerSize)
	if size := (nbits + 7) / 8; size > seg.size() {
		panic(fmt.Sprintf("nbits=%d, size=%d, seg.size=%d", nbits, size, seg))
	}
	if seg.addr%ptrSize != 0 {
		panic(fmt.Sprintf("seg.addr=0x%x not aligned to ptrSize=%d", seg.addr, ptrSize))
	}
	return &gcBitvector{
		bits:    bits,
		nbits:   nbits,
		ptrSize: ptrSize,
		seg:     seg,
	}
}
func (bv *gcBitvector) contains(addr uint64) bool {
	return bv.seg.contains(addr)
}