github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/arena/arena.go (about) 1 package arena 2 3 import ( 4 "syscall" 5 ) 6 7 const ( 8 MEM_COMMIT = 0x1000 9 MEM_RESERVE = 0x2000 10 MEM_RELEASE = 0x8000 11 MEM_RESET = 0x80000 12 13 PAGE_NOACCESS = 0x0001 14 PAGE_EXECUTE_READWRITE = 0x40 15 16 B = 1 17 KB = 1024 * B 18 MB = 1024 * KB 19 GB = 1024 * MB 20 ) 21 22 const ChunkSize = 8 * KB 23 24 var ( 25 dll = syscall.MustLoadDLL("kernel32.dll") 26 VirtualAlloc = dll.MustFindProc("VirtualAlloc") 27 VirtualFree = dll.MustFindProc("VirtualFree") 28 ) 29 30 type chunk struct { 31 offset uintptr 32 data uintptr 33 } 34 35 type Arena struct { 36 chunks []chunk 37 } 38 39 func New(chunksize uint) *Arena { 40 arena := &Arena{} 41 arena.newblock() 42 return arena 43 } 44 45 func alloc(size uint) (uintptr, error) { 46 addr, _, err := VirtualAlloc.Call(0, uintptr(size), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE) 47 if addr == 0 { 48 return 0, err 49 } 50 return addr, nil 51 } 52 func free(p uintptr) error { 53 r, _, err := VirtualFree.Call(p, 0, MEM_RELEASE) 54 if r == 0 { 55 return err 56 } 57 return nil 58 } 59 60 func (a *Arena) last() *chunk { 61 if len(a.chunks) == 0 { 62 return a.newblock() 63 } 64 return &a.chunks[len(a.chunks)-1] 65 } 66 67 func (a *Arena) newblock() *chunk { 68 data, err := alloc(ChunkSize) 69 if err != nil { 70 panic(err) 71 } 72 a.chunks = append(a.chunks, chunk{offset: 0, data: data}) 73 return &a.chunks[len(a.chunks)-1] 74 } 75 76 func (a *Arena) Alloc(size uintptr) uintptr { 77 cursor := a.last() 78 if cursor.offset+size > ChunkSize { 79 cursor = a.newblock() 80 } 81 p := cursor.data + cursor.offset 82 cursor.offset += size 83 return uintptr(p) 84 } 85 86 func (a *Arena) Release() { 87 for _, c := range a.chunks { 88 err := free(c.data) 89 if err != nil { 90 panic(err) 91 } 92 } 93 }