summaryrefslogtreecommitdiff
path: root/libgo/go/runtime/malloc.go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
commitaf146490bb04205107cb23e301ec7a8ff927b5fc (patch)
tree13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/runtime/malloc.go
parent725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff)
runtime: Remove now unnecessary pad field from ParFor.
It is not needed due to the removal of the ctx field. Reviewed-on: https://go-review.googlesource.com/16525 From-SVN: r229616
Diffstat (limited to 'libgo/go/runtime/malloc.go')
-rw-r--r--libgo/go/runtime/malloc.go837
1 files changed, 0 insertions, 837 deletions
diff --git a/libgo/go/runtime/malloc.go b/libgo/go/runtime/malloc.go
deleted file mode 100644
index 11704494404..00000000000
--- a/libgo/go/runtime/malloc.go
+++ /dev/null
@@ -1,837 +0,0 @@
-// Copyright 2014 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 runtime
-
-import (
- "unsafe"
-)
-
-const (
- debugMalloc = false
-
- flagNoScan = _FlagNoScan
- flagNoZero = _FlagNoZero
-
- maxTinySize = _TinySize
- tinySizeClass = _TinySizeClass
- maxSmallSize = _MaxSmallSize
-
- pageShift = _PageShift
- pageSize = _PageSize
- pageMask = _PageMask
-
- bitsPerPointer = _BitsPerPointer
- bitsMask = _BitsMask
- pointersPerByte = _PointersPerByte
- maxGCMask = _MaxGCMask
- bitsDead = _BitsDead
- bitsPointer = _BitsPointer
-
- mSpanInUse = _MSpanInUse
-
- concurrentSweep = _ConcurrentSweep != 0
-)
-
-// Page number (address>>pageShift)
-type pageID uintptr
-
-// base address for all 0-byte allocations
-var zerobase uintptr
-
-// Allocate an object of size bytes.
-// Small objects are allocated from the per-P cache's free lists.
-// Large objects (> 32 kB) are allocated straight from the heap.
-func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
- if size == 0 {
- return unsafe.Pointer(&zerobase)
- }
- size0 := size
-
- if flags&flagNoScan == 0 && typ == nil {
- gothrow("malloc missing type")
- }
-
- // This function must be atomic wrt GC, but for performance reasons
- // we don't acquirem/releasem on fast path. The code below does not have
- // split stack checks, so it can't be preempted by GC.
- // Functions like roundup/add are inlined. And onM/racemalloc are nosplit.
- // If debugMalloc = true, these assumptions are checked below.
- if debugMalloc {
- mp := acquirem()
- if mp.mallocing != 0 {
- gothrow("malloc deadlock")
- }
- mp.mallocing = 1
- if mp.curg != nil {
- mp.curg.stackguard0 = ^uintptr(0xfff) | 0xbad
- }
- }
-
- c := gomcache()
- var s *mspan
- var x unsafe.Pointer
- if size <= maxSmallSize {
- if flags&flagNoScan != 0 && size < maxTinySize {
- // Tiny allocator.
- //
- // Tiny allocator combines several tiny allocation requests
- // into a single memory block. The resulting memory block
- // is freed when all subobjects are unreachable. The subobjects
- // must be FlagNoScan (don't have pointers), this ensures that
- // the amount of potentially wasted memory is bounded.
- //
- // Size of the memory block used for combining (maxTinySize) is tunable.
- // Current setting is 16 bytes, which relates to 2x worst case memory
- // wastage (when all but one subobjects are unreachable).
- // 8 bytes would result in no wastage at all, but provides less
- // opportunities for combining.
- // 32 bytes provides more opportunities for combining,
- // but can lead to 4x worst case wastage.
- // The best case winning is 8x regardless of block size.
- //
- // Objects obtained from tiny allocator must not be freed explicitly.
- // So when an object will be freed explicitly, we ensure that
- // its size >= maxTinySize.
- //
- // SetFinalizer has a special case for objects potentially coming
- // from tiny allocator, it such case it allows to set finalizers
- // for an inner byte of a memory block.
- //
- // The main targets of tiny allocator are small strings and
- // standalone escaping variables. On a json benchmark
- // the allocator reduces number of allocations by ~12% and
- // reduces heap size by ~20%.
- tinysize := uintptr(c.tinysize)
- if size <= tinysize {
- tiny := unsafe.Pointer(c.tiny)
- // Align tiny pointer for required (conservative) alignment.
- if size&7 == 0 {
- tiny = roundup(tiny, 8)
- } else if size&3 == 0 {
- tiny = roundup(tiny, 4)
- } else if size&1 == 0 {
- tiny = roundup(tiny, 2)
- }
- size1 := size + (uintptr(tiny) - uintptr(unsafe.Pointer(c.tiny)))
- if size1 <= tinysize {
- // The object fits into existing tiny block.
- x = tiny
- c.tiny = (*byte)(add(x, size))
- c.tinysize -= uintptr(size1)
- c.local_tinyallocs++
- if debugMalloc {
- mp := acquirem()
- if mp.mallocing == 0 {
- gothrow("bad malloc")
- }
- mp.mallocing = 0
- if mp.curg != nil {
- mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
- }
- // Note: one releasem for the acquirem just above.
- // The other for the acquirem at start of malloc.
- releasem(mp)
- releasem(mp)
- }
- return x
- }
- }
- // Allocate a new maxTinySize block.
- s = c.alloc[tinySizeClass]
- v := s.freelist
- if v == nil {
- mp := acquirem()
- mp.scalararg[0] = tinySizeClass
- onM(mcacheRefill_m)
- releasem(mp)
- s = c.alloc[tinySizeClass]
- v = s.freelist
- }
- s.freelist = v.next
- s.ref++
- //TODO: prefetch v.next
- x = unsafe.Pointer(v)
- (*[2]uint64)(x)[0] = 0
- (*[2]uint64)(x)[1] = 0
- // See if we need to replace the existing tiny block with the new one
- // based on amount of remaining free space.
- if maxTinySize-size > tinysize {
- c.tiny = (*byte)(add(x, size))
- c.tinysize = uintptr(maxTinySize - size)
- }
- size = maxTinySize
- } else {
- var sizeclass int8
- if size <= 1024-8 {
- sizeclass = size_to_class8[(size+7)>>3]
- } else {
- sizeclass = size_to_class128[(size-1024+127)>>7]
- }
- size = uintptr(class_to_size[sizeclass])
- s = c.alloc[sizeclass]
- v := s.freelist
- if v == nil {
- mp := acquirem()
- mp.scalararg[0] = uintptr(sizeclass)
- onM(mcacheRefill_m)
- releasem(mp)
- s = c.alloc[sizeclass]
- v = s.freelist
- }
- s.freelist = v.next
- s.ref++
- //TODO: prefetch
- x = unsafe.Pointer(v)
- if flags&flagNoZero == 0 {
- v.next = nil
- if size > 2*ptrSize && ((*[2]uintptr)(x))[1] != 0 {
- memclr(unsafe.Pointer(v), size)
- }
- }
- }
- c.local_cachealloc += intptr(size)
- } else {
- mp := acquirem()
- mp.scalararg[0] = uintptr(size)
- mp.scalararg[1] = uintptr(flags)
- onM(largeAlloc_m)
- s = (*mspan)(mp.ptrarg[0])
- mp.ptrarg[0] = nil
- releasem(mp)
- x = unsafe.Pointer(uintptr(s.start << pageShift))
- size = uintptr(s.elemsize)
- }
-
- if flags&flagNoScan != 0 {
- // All objects are pre-marked as noscan.
- goto marked
- }
-
- // If allocating a defer+arg block, now that we've picked a malloc size
- // large enough to hold everything, cut the "asked for" size down to
- // just the defer header, so that the GC bitmap will record the arg block
- // as containing nothing at all (as if it were unused space at the end of
- // a malloc block caused by size rounding).
- // The defer arg areas are scanned as part of scanstack.
- if typ == deferType {
- size0 = unsafe.Sizeof(_defer{})
- }
-
- // From here till marked label marking the object as allocated
- // and storing type info in the GC bitmap.
- {
- arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
- off := (uintptr(x) - arena_start) / ptrSize
- xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
- shift := (off % wordsPerBitmapByte) * gcBits
- if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary {
- println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask))
- gothrow("bad bits in markallocated")
- }
-
- var ti, te uintptr
- var ptrmask *uint8
- if size == ptrSize {
- // It's one word and it has pointers, it must be a pointer.
- *xbits |= (bitsPointer << 2) << shift
- goto marked
- }
- if typ.kind&kindGCProg != 0 {
- nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
- masksize := nptr
- if masksize%2 != 0 {
- masksize *= 2 // repeated
- }
- masksize = masksize * pointersPerByte / 8 // 4 bits per word
- masksize++ // unroll flag in the beginning
- if masksize > maxGCMask && typ.gc[1] != 0 {
- // If the mask is too large, unroll the program directly
- // into the GC bitmap. It's 7 times slower than copying
- // from the pre-unrolled mask, but saves 1/16 of type size
- // memory for the mask.
- mp := acquirem()
- mp.ptrarg[0] = x
- mp.ptrarg[1] = unsafe.Pointer(typ)
- mp.scalararg[0] = uintptr(size)
- mp.scalararg[1] = uintptr(size0)
- onM(unrollgcproginplace_m)
- releasem(mp)
- goto marked
- }
- ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
- // Check whether the program is already unrolled.
- if uintptr(atomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 {
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(typ)
- onM(unrollgcprog_m)
- releasem(mp)
- }
- ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
- } else {
- ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
- }
- if size == 2*ptrSize {
- *xbits = *ptrmask | bitBoundary
- goto marked
- }
- te = uintptr(typ.size) / ptrSize
- // If the type occupies odd number of words, its mask is repeated.
- if te%2 == 0 {
- te /= 2
- }
- // Copy pointer bitmask into the bitmap.
- for i := uintptr(0); i < size0; i += 2 * ptrSize {
- v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti))
- ti++
- if ti == te {
- ti = 0
- }
- if i == 0 {
- v |= bitBoundary
- }
- if i+ptrSize == size0 {
- v &^= uint8(bitPtrMask << 4)
- }
-
- *xbits = v
- xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0)))
- }
- if size0%(2*ptrSize) == 0 && size0 < size {
- // Mark the word after last object's word as bitsDead.
- *xbits = bitsDead << 2
- }
- }
-marked:
- if raceenabled {
- racemalloc(x, size)
- }
-
- if debugMalloc {
- mp := acquirem()
- if mp.mallocing == 0 {
- gothrow("bad malloc")
- }
- mp.mallocing = 0
- if mp.curg != nil {
- mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
- }
- // Note: one releasem for the acquirem just above.
- // The other for the acquirem at start of malloc.
- releasem(mp)
- releasem(mp)
- }
-
- if debug.allocfreetrace != 0 {
- tracealloc(x, size, typ)
- }
-
- if rate := MemProfileRate; rate > 0 {
- if size < uintptr(rate) && int32(size) < c.next_sample {
- c.next_sample -= int32(size)
- } else {
- mp := acquirem()
- profilealloc(mp, x, size)
- releasem(mp)
- }
- }
-
- if memstats.heap_alloc >= memstats.next_gc {
- gogc(0)
- }
-
- return x
-}
-
-// implementation of new builtin
-func newobject(typ *_type) unsafe.Pointer {
- flags := uint32(0)
- if typ.kind&kindNoPointers != 0 {
- flags |= flagNoScan
- }
- return mallocgc(uintptr(typ.size), typ, flags)
-}
-
-// implementation of make builtin for slices
-func newarray(typ *_type, n uintptr) unsafe.Pointer {
- flags := uint32(0)
- if typ.kind&kindNoPointers != 0 {
- flags |= flagNoScan
- }
- if int(n) < 0 || (typ.size > 0 && n > maxmem/uintptr(typ.size)) {
- panic("runtime: allocation size out of range")
- }
- return mallocgc(uintptr(typ.size)*n, typ, flags)
-}
-
-// rawmem returns a chunk of pointerless memory. It is
-// not zeroed.
-func rawmem(size uintptr) unsafe.Pointer {
- return mallocgc(size, nil, flagNoScan|flagNoZero)
-}
-
-// round size up to next size class
-func goroundupsize(size uintptr) uintptr {
- if size < maxSmallSize {
- if size <= 1024-8 {
- return uintptr(class_to_size[size_to_class8[(size+7)>>3]])
- }
- return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])
- }
- if size+pageSize < size {
- return size
- }
- return (size + pageSize - 1) &^ pageMask
-}
-
-func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
- c := mp.mcache
- rate := MemProfileRate
- if size < uintptr(rate) {
- // pick next profile time
- // If you change this, also change allocmcache.
- if rate > 0x3fffffff { // make 2*rate not overflow
- rate = 0x3fffffff
- }
- next := int32(fastrand1()) % (2 * int32(rate))
- // Subtract the "remainder" of the current allocation.
- // Otherwise objects that are close in size to sampling rate
- // will be under-sampled, because we consistently discard this remainder.
- next -= (int32(size) - c.next_sample)
- if next < 0 {
- next = 0
- }
- c.next_sample = next
- }
-
- mProf_Malloc(x, size)
-}
-
-// force = 1 - do GC regardless of current heap usage
-// force = 2 - go GC and eager sweep
-func gogc(force int32) {
- // The gc is turned off (via enablegc) until the bootstrap has completed.
- // Also, malloc gets called in the guts of a number of libraries that might be
- // holding locks. To avoid deadlocks during stoptheworld, don't bother
- // trying to run gc while holding a lock. The next mallocgc without a lock
- // will do the gc instead.
- mp := acquirem()
- if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 {
- releasem(mp)
- return
- }
- releasem(mp)
- mp = nil
-
- semacquire(&worldsema, false)
-
- if force == 0 && memstats.heap_alloc < memstats.next_gc {
- // typically threads which lost the race to grab
- // worldsema exit here when gc is done.
- semrelease(&worldsema)
- return
- }
-
- // Ok, we're doing it! Stop everybody else
- startTime := nanotime()
- mp = acquirem()
- mp.gcing = 1
- releasem(mp)
- onM(stoptheworld)
- if mp != acquirem() {
- gothrow("gogc: rescheduled")
- }
-
- clearpools()
-
- // Run gc on the g0 stack. We do this so that the g stack
- // we're currently running on will no longer change. Cuts
- // the root set down a bit (g0 stacks are not scanned, and
- // we don't need to scan gc's internal state). We also
- // need to switch to g0 so we can shrink the stack.
- n := 1
- if debug.gctrace > 1 {
- n = 2
- }
- for i := 0; i < n; i++ {
- if i > 0 {
- startTime = nanotime()
- }
- // switch to g0, call gc, then switch back
- mp.scalararg[0] = uintptr(uint32(startTime)) // low 32 bits
- mp.scalararg[1] = uintptr(startTime >> 32) // high 32 bits
- if force >= 2 {
- mp.scalararg[2] = 1 // eagersweep
- } else {
- mp.scalararg[2] = 0
- }
- onM(gc_m)
- }
-
- // all done
- mp.gcing = 0
- semrelease(&worldsema)
- onM(starttheworld)
- releasem(mp)
- mp = nil
-
- // now that gc is done, kick off finalizer thread if needed
- if !concurrentSweep {
- // give the queued finalizers, if any, a chance to run
- Gosched()
- }
-}
-
-// GC runs a garbage collection.
-func GC() {
- gogc(2)
-}
-
-// linker-provided
-var noptrdata struct{}
-var enoptrdata struct{}
-var noptrbss struct{}
-var enoptrbss struct{}
-
-// SetFinalizer sets the finalizer associated with x to f.
-// When the garbage collector finds an unreachable block
-// with an associated finalizer, it clears the association and runs
-// f(x) in a separate goroutine. This makes x reachable again, but
-// now without an associated finalizer. Assuming that SetFinalizer
-// is not called again, the next time the garbage collector sees
-// that x is unreachable, it will free x.
-//
-// SetFinalizer(x, nil) clears any finalizer associated with x.
-//
-// The argument x must be a pointer to an object allocated by
-// calling new or by taking the address of a composite literal.
-// The argument f must be a function that takes a single argument
-// to which x's type can be assigned, and can have arbitrary ignored return
-// values. If either of these is not true, SetFinalizer aborts the
-// program.
-//
-// Finalizers are run in dependency order: if A points at B, both have
-// finalizers, and they are otherwise unreachable, only the finalizer
-// for A runs; once A is freed, the finalizer for B can run.
-// If a cyclic structure includes a block with a finalizer, that
-// cycle is not guaranteed to be garbage collected and the finalizer
-// is not guaranteed to run, because there is no ordering that
-// respects the dependencies.
-//
-// The finalizer for x is scheduled to run at some arbitrary time after
-// x becomes unreachable.
-// There is no guarantee that finalizers will run before a program exits,
-// so typically they are useful only for releasing non-memory resources
-// associated with an object during a long-running program.
-// For example, an os.File object could use a finalizer to close the
-// associated operating system file descriptor when a program discards
-// an os.File without calling Close, but it would be a mistake
-// to depend on a finalizer to flush an in-memory I/O buffer such as a
-// bufio.Writer, because the buffer would not be flushed at program exit.
-//
-// It is not guaranteed that a finalizer will run if the size of *x is
-// zero bytes.
-//
-// It is not guaranteed that a finalizer will run for objects allocated
-// in initializers for package-level variables. Such objects may be
-// linker-allocated, not heap-allocated.
-//
-// A single goroutine runs all finalizers for a program, sequentially.
-// If a finalizer must run for a long time, it should do so by starting
-// a new goroutine.
-func SetFinalizer(obj interface{}, finalizer interface{}) {
- e := (*eface)(unsafe.Pointer(&obj))
- etyp := e._type
- if etyp == nil {
- gothrow("runtime.SetFinalizer: first argument is nil")
- }
- if etyp.kind&kindMask != kindPtr {
- gothrow("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer")
- }
- ot := (*ptrtype)(unsafe.Pointer(etyp))
- if ot.elem == nil {
- gothrow("nil elem type!")
- }
-
- // find the containing object
- _, base, _ := findObject(e.data)
-
- if base == nil {
- // 0-length objects are okay.
- if e.data == unsafe.Pointer(&zerobase) {
- return
- }
-
- // Global initializers might be linker-allocated.
- // var Foo = &Object{}
- // func main() {
- // runtime.SetFinalizer(Foo, nil)
- // }
- // The relevant segments are: noptrdata, data, bss, noptrbss.
- // We cannot assume they are in any order or even contiguous,
- // due to external linking.
- if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) ||
- uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) ||
- uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) ||
- uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) {
- return
- }
- gothrow("runtime.SetFinalizer: pointer not in allocated block")
- }
-
- if e.data != base {
- // As an implementation detail we allow to set finalizers for an inner byte
- // of an object if it could come from tiny alloc (see mallocgc for details).
- if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize {
- gothrow("runtime.SetFinalizer: pointer not at beginning of allocated block")
- }
- }
-
- f := (*eface)(unsafe.Pointer(&finalizer))
- ftyp := f._type
- if ftyp == nil {
- // switch to M stack and remove finalizer
- mp := acquirem()
- mp.ptrarg[0] = e.data
- onM(removeFinalizer_m)
- releasem(mp)
- return
- }
-
- if ftyp.kind&kindMask != kindFunc {
- gothrow("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function")
- }
- ft := (*functype)(unsafe.Pointer(ftyp))
- ins := *(*[]*_type)(unsafe.Pointer(&ft.in))
- if ft.dotdotdot || len(ins) != 1 {
- gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
- }
- fint := ins[0]
- switch {
- case fint == etyp:
- // ok - same type
- goto okarg
- case fint.kind&kindMask == kindPtr:
- if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
- // ok - not same type, but both pointers,
- // one or the other is unnamed, and same element type, so assignable.
- goto okarg
- }
- case fint.kind&kindMask == kindInterface:
- ityp := (*interfacetype)(unsafe.Pointer(fint))
- if len(ityp.mhdr) == 0 {
- // ok - satisfies empty interface
- goto okarg
- }
- if _, ok := assertE2I2(ityp, obj); ok {
- goto okarg
- }
- }
- gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
-okarg:
- // compute size needed for return parameters
- nret := uintptr(0)
- for _, t := range *(*[]*_type)(unsafe.Pointer(&ft.out)) {
- nret = round(nret, uintptr(t.align)) + uintptr(t.size)
- }
- nret = round(nret, ptrSize)
-
- // make sure we have a finalizer goroutine
- createfing()
-
- // switch to M stack to add finalizer record
- mp := acquirem()
- mp.ptrarg[0] = f.data
- mp.ptrarg[1] = e.data
- mp.scalararg[0] = nret
- mp.ptrarg[2] = unsafe.Pointer(fint)
- mp.ptrarg[3] = unsafe.Pointer(ot)
- onM(setFinalizer_m)
- if mp.scalararg[0] != 1 {
- gothrow("runtime.SetFinalizer: finalizer already set")
- }
- releasem(mp)
-}
-
-// round n up to a multiple of a. a must be a power of 2.
-func round(n, a uintptr) uintptr {
- return (n + a - 1) &^ (a - 1)
-}
-
-// Look up pointer v in heap. Return the span containing the object,
-// the start of the object, and the size of the object. If the object
-// does not exist, return nil, nil, 0.
-func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
- c := gomcache()
- c.local_nlookup++
- if ptrSize == 4 && c.local_nlookup >= 1<<30 {
- // purge cache stats to prevent overflow
- lock(&mheap_.lock)
- purgecachedstats(c)
- unlock(&mheap_.lock)
- }
-
- // find span
- arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
- arena_used := uintptr(unsafe.Pointer(mheap_.arena_used))
- if uintptr(v) < arena_start || uintptr(v) >= arena_used {
- return
- }
- p := uintptr(v) >> pageShift
- q := p - arena_start>>pageShift
- s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*ptrSize))
- if s == nil {
- return
- }
- x = unsafe.Pointer(uintptr(s.start) << pageShift)
-
- if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
- s = nil
- x = nil
- return
- }
-
- n = uintptr(s.elemsize)
- if s.sizeclass != 0 {
- x = add(x, (uintptr(v)-uintptr(x))/n*n)
- }
- return
-}
-
-var fingCreate uint32
-
-func createfing() {
- // start the finalizer goroutine exactly once
- if fingCreate == 0 && cas(&fingCreate, 0, 1) {
- go runfinq()
- }
-}
-
-// This is the goroutine that runs all of the finalizers
-func runfinq() {
- var (
- frame unsafe.Pointer
- framecap uintptr
- )
-
- for {
- lock(&finlock)
- fb := finq
- finq = nil
- if fb == nil {
- gp := getg()
- fing = gp
- fingwait = true
- gp.issystem = true
- goparkunlock(&finlock, "finalizer wait")
- gp.issystem = false
- continue
- }
- unlock(&finlock)
- if raceenabled {
- racefingo()
- }
- for fb != nil {
- for i := int32(0); i < fb.cnt; i++ {
- f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i)*unsafe.Sizeof(finalizer{})))
-
- framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret)
- if framecap < framesz {
- // The frame does not contain pointers interesting for GC,
- // all not yet finalized objects are stored in finq.
- // If we do not mark it as FlagNoScan,
- // the last finalized object is not collected.
- frame = mallocgc(framesz, nil, flagNoScan)
- framecap = framesz
- }
-
- if f.fint == nil {
- gothrow("missing type in runfinq")
- }
- switch f.fint.kind & kindMask {
- case kindPtr:
- // direct use of pointer
- *(*unsafe.Pointer)(frame) = f.arg
- case kindInterface:
- ityp := (*interfacetype)(unsafe.Pointer(f.fint))
- // set up with empty interface
- (*eface)(frame)._type = &f.ot.typ
- (*eface)(frame).data = f.arg
- if len(ityp.mhdr) != 0 {
- // convert to interface with methods
- // this conversion is guaranteed to succeed - we checked in SetFinalizer
- *(*fInterface)(frame) = assertE2I(ityp, *(*interface{})(frame))
- }
- default:
- gothrow("bad kind in runfinq")
- }
- reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
-
- // drop finalizer queue references to finalized object
- f.fn = nil
- f.arg = nil
- f.ot = nil
- }
- fb.cnt = 0
- next := fb.next
- lock(&finlock)
- fb.next = finc
- finc = fb
- unlock(&finlock)
- fb = next
- }
- }
-}
-
-var persistent struct {
- lock mutex
- pos unsafe.Pointer
- end unsafe.Pointer
-}
-
-// Wrapper around sysAlloc that can allocate small chunks.
-// There is no associated free operation.
-// Intended for things like function/type/debug-related persistent data.
-// If align is 0, uses default align (currently 8).
-func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer {
- const (
- chunk = 256 << 10
- maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
- )
-
- if align != 0 {
- if align&(align-1) != 0 {
- gothrow("persistentalloc: align is not a power of 2")
- }
- if align > _PageSize {
- gothrow("persistentalloc: align is too large")
- }
- } else {
- align = 8
- }
-
- if size >= maxBlock {
- return sysAlloc(size, stat)
- }
-
- lock(&persistent.lock)
- persistent.pos = roundup(persistent.pos, align)
- if uintptr(persistent.pos)+size > uintptr(persistent.end) {
- persistent.pos = sysAlloc(chunk, &memstats.other_sys)
- if persistent.pos == nil {
- unlock(&persistent.lock)
- gothrow("runtime: cannot allocate memory")
- }
- persistent.end = add(persistent.pos, chunk)
- }
- p := persistent.pos
- persistent.pos = add(persistent.pos, size)
- unlock(&persistent.lock)
-
- if stat != &memstats.other_sys {
- xadd64(stat, int64(size))
- xadd64(&memstats.other_sys, -int64(size))
- }
- return p
-}