Home | History | Annotate | Download | only in runtime
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Fixed-size object allocator.  Returned memory is not zeroed.
      6 //
      7 // See malloc.go for overview.
      8 
      9 package runtime
     10 
     11 import "unsafe"
     12 
     13 // FixAlloc is a simple free-list allocator for fixed size objects.
     14 // Malloc uses a FixAlloc wrapped around sysAlloc to manages its
     15 // MCache and MSpan objects.
     16 //
     17 // Memory returned by FixAlloc_Alloc is not zeroed.
     18 // The caller is responsible for locking around FixAlloc calls.
     19 // Callers can keep state in the object but the first word is
     20 // smashed by freeing and reallocating.
     21 type fixalloc struct {
     22 	size   uintptr
     23 	first  unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned
     24 	arg    unsafe.Pointer
     25 	list   *mlink
     26 	chunk  *byte
     27 	nchunk uint32
     28 	inuse  uintptr // in-use bytes now
     29 	stat   *uint64
     30 }
     31 
     32 // A generic linked list of blocks.  (Typically the block is bigger than sizeof(MLink).)
     33 // Since assignments to mlink.next will result in a write barrier being preformed
     34 // this can not be used by some of the internal GC structures. For example when
     35 // the sweeper is placing an unmarked object on the free list it does not want the
     36 // write barrier to be called since that could result in the object being reachable.
     37 type mlink struct {
     38 	next *mlink
     39 }
     40 
     41 // Initialize f to allocate objects of the given size,
     42 // using the allocator to obtain chunks of memory.
     43 func fixAlloc_Init(f *fixalloc, size uintptr, first func(unsafe.Pointer, unsafe.Pointer), arg unsafe.Pointer, stat *uint64) {
     44 	f.size = size
     45 	f.first = *(*unsafe.Pointer)(unsafe.Pointer(&first))
     46 	f.arg = arg
     47 	f.list = nil
     48 	f.chunk = nil
     49 	f.nchunk = 0
     50 	f.inuse = 0
     51 	f.stat = stat
     52 }
     53 
     54 func fixAlloc_Alloc(f *fixalloc) unsafe.Pointer {
     55 	if f.size == 0 {
     56 		print("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n")
     57 		throw("runtime: internal error")
     58 	}
     59 
     60 	if f.list != nil {
     61 		v := unsafe.Pointer(f.list)
     62 		f.list = f.list.next
     63 		f.inuse += f.size
     64 		return v
     65 	}
     66 	if uintptr(f.nchunk) < f.size {
     67 		f.chunk = (*uint8)(persistentalloc(_FixAllocChunk, 0, f.stat))
     68 		f.nchunk = _FixAllocChunk
     69 	}
     70 
     71 	v := (unsafe.Pointer)(f.chunk)
     72 	if f.first != nil {
     73 		fn := *(*func(unsafe.Pointer, unsafe.Pointer))(unsafe.Pointer(&f.first))
     74 		fn(f.arg, v)
     75 	}
     76 	f.chunk = (*byte)(add(unsafe.Pointer(f.chunk), f.size))
     77 	f.nchunk -= uint32(f.size)
     78 	f.inuse += f.size
     79 	return v
     80 }
     81 
     82 func fixAlloc_Free(f *fixalloc, p unsafe.Pointer) {
     83 	f.inuse -= f.size
     84 	v := (*mlink)(p)
     85 	v.next = f.list
     86 	f.list = v
     87 }
     88