package runtime
import (
)
type Pinner struct {
*pinner
}
func ( *Pinner) ( any) {
if .pinner == nil {
:= acquirem()
if := .p.ptr(); != nil {
.pinner = .pinnerCache
.pinnerCache = nil
}
releasem()
if .pinner == nil {
.pinner = new(pinner)
.refs = .refStore[:0]
SetFinalizer(.pinner, func( *pinner) {
if len(.refs) != 0 {
.unpin()
pinnerLeakPanic()
}
})
}
}
:= pinnerGetPtr(&)
if setPinned(, true) {
.refs = append(.refs, )
}
}
func ( *Pinner) () {
.pinner.unpin()
:= acquirem()
if := .p.ptr(); != nil && .pinnerCache == nil {
.pinnerCache = .pinner
.pinner = nil
}
releasem()
}
const (
pinnerSize = 64
pinnerRefStoreSize = (pinnerSize - unsafe.Sizeof([]unsafe.Pointer{})) / unsafe.Sizeof(unsafe.Pointer(nil))
)
type pinner struct {
refs []unsafe.Pointer
refStore [pinnerRefStoreSize]unsafe.Pointer
}
func ( *pinner) () {
if == nil || .refs == nil {
return
}
for := range .refs {
setPinned(.refs[], false)
}
.refStore = [pinnerRefStoreSize]unsafe.Pointer{}
.refs = .refStore[:0]
}
func ( *any) unsafe.Pointer {
:= efaceOf()
:= ._type
if == nil {
panic(errorString("runtime.Pinner: argument is nil"))
}
if := .Kind_ & abi.KindMask; != abi.Pointer && != abi.UnsafePointer {
panic(errorString("runtime.Pinner: argument is not a pointer: " + toRType().string()))
}
if inUserArenaChunk(uintptr(.data)) {
panic(errorString("runtime.Pinner: object was allocated into an arena"))
}
return .data
}
func ( unsafe.Pointer) bool {
:= spanOfHeap(uintptr())
if == nil {
return true
}
:= .getPinnerBits()
if == nil {
return false
}
:= .objIndex(uintptr())
:= .ofObject()
KeepAlive()
return .isPinned()
}
func ( unsafe.Pointer, bool) bool {
:= spanOfHeap(uintptr())
if == nil {
if ! {
panic(errorString("tried to unpin non-Go pointer"))
}
return false
}
:= acquirem()
.ensureSwept()
KeepAlive()
:= .objIndex(uintptr())
lock(&.speciallock)
:= .getPinnerBits()
if == nil {
= .newPinnerBits()
.setPinnerBits()
}
:= .ofObject()
if {
if .isPinned() {
.setMultiPinned(true)
systemstack(func() {
:= * .elemsize
.incPinCounter()
})
} else {
.setPinned(true)
}
} else {
if .isPinned() {
if .isMultiPinned() {
var bool
systemstack(func() {
:= * .elemsize
= .decPinCounter()
})
if ! {
.setMultiPinned(false)
}
} else {
.setPinned(false)
}
} else {
throw("runtime.Pinner: object already unpinned")
}
}
unlock(&.speciallock)
releasem()
return true
}
type pinState struct {
bytep *uint8
byteVal uint8
mask uint8
}
func ( *pinState) () bool {
return (.byteVal & .mask) != 0
}
func ( *pinState) () bool {
return (.byteVal & (.mask << 1)) != 0
}
func ( *pinState) ( bool) {
.set(, false)
}
func ( *pinState) ( bool) {
.set(, true)
}
func ( *pinState) ( bool, bool) {
:= .mask
if {
<<= 1
}
if {
atomic.Or8(.bytep, )
} else {
atomic.And8(.bytep, ^)
}
}
type pinnerBits gcBits
func ( *pinnerBits) ( uintptr) pinState {
, := (*gcBits)().bitp( * 2)
:= atomic.Load8()
return pinState{, , }
}
func ( *mspan) () uintptr {
return divRoundUp(uintptr(.nelems)*2, 8)
}
func ( *mspan) () *pinnerBits {
return (*pinnerBits)(newMarkBits(uintptr(.nelems) * 2))
}
func ( *mspan) () *pinnerBits {
return (*pinnerBits)(atomic.Loadp(unsafe.Pointer(&.pinnerBits)))
}
func ( *mspan) ( *pinnerBits) {
atomicstorep(unsafe.Pointer(&.pinnerBits), unsafe.Pointer())
}
func ( *mspan) () {
:= .getPinnerBits()
if == nil {
return
}
:= false
:= alignUp(.pinnerBitSize(), 8)
for , := range unsafe.Slice((*uint64)(unsafe.Pointer(&.x)), /8) {
if != 0 {
= true
break
}
}
if {
:= .newPinnerBits()
memmove(unsafe.Pointer(&.x), unsafe.Pointer(&.x), )
.setPinnerBits()
} else {
.setPinnerBits(nil)
}
}
func ( *mspan) ( uintptr) {
var *specialPinCounter
, := .specialFindSplicePoint(, _KindSpecialPinCounter)
if ! {
lock(&mheap_.speciallock)
= (*specialPinCounter)(mheap_.specialPinCounterAlloc.alloc())
unlock(&mheap_.speciallock)
.special.offset =
.special.kind = _KindSpecialPinCounter
.special.next = *
* = (*special)(unsafe.Pointer())
spanHasSpecials()
} else {
= (*specialPinCounter)(unsafe.Pointer(*))
}
.counter++
}
func ( *mspan) ( uintptr) bool {
, := .specialFindSplicePoint(, _KindSpecialPinCounter)
if ! {
throw("runtime.Pinner: decreased non-existing pin counter")
}
:= (*specialPinCounter)(unsafe.Pointer(*))
.counter--
if .counter == 0 {
* = .special.next
if .specials == nil {
spanHasNoSpecials()
}
lock(&mheap_.speciallock)
mheap_.specialPinCounterAlloc.free(unsafe.Pointer())
unlock(&mheap_.speciallock)
return false
}
return true
}
func ( unsafe.Pointer) *uintptr {
, , := findObject(uintptr(), 0, 0)
:= * .elemsize
, := .specialFindSplicePoint(, _KindSpecialPinCounter)
if ! {
return nil
}
:= (*specialPinCounter)(unsafe.Pointer(*))
return &.counter
}
var pinnerLeakPanic = func() {
panic(errorString("runtime.Pinner: found leaking pinned pointer; forgot to call Unpin()?"))
}