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