github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/internal/util/alloc_windows.go (about) 1 //go:build !sqlite3_nosys 2 3 package util 4 5 import ( 6 "math" 7 "reflect" 8 "unsafe" 9 10 "github.com/tetratelabs/wazero/experimental" 11 "golang.org/x/sys/windows" 12 ) 13 14 func virtualAlloc(cap, max uint64) experimental.LinearMemory { 15 // Round up to the page size. 16 rnd := uint64(windows.Getpagesize() - 1) 17 max = (max + rnd) &^ rnd 18 19 if max > math.MaxInt { 20 // This ensures uintptr(max) overflows to a large value, 21 // and windows.VirtualAlloc returns an error. 22 max = math.MaxUint64 23 } 24 25 // Reserve max bytes of address space, to ensure we won't need to move it. 26 // This does not commit memory. 27 r, err := windows.VirtualAlloc(0, uintptr(max), windows.MEM_RESERVE, windows.PAGE_READWRITE) 28 if err != nil { 29 panic(err) 30 } 31 32 mem := virtualMemory{addr: r} 33 // SliceHeader, although deprecated, avoids a go vet warning. 34 sh := (*reflect.SliceHeader)(unsafe.Pointer(&mem.buf)) 35 sh.Cap = int(max) // Not a bug. 36 sh.Data = r 37 return &mem 38 } 39 40 // The slice covers the entire mmapped memory: 41 // - len(buf) is the already committed memory, 42 // - cap(buf) is the reserved address space. 43 type virtualMemory struct { 44 buf []byte 45 addr uintptr 46 } 47 48 func (m *virtualMemory) Reallocate(size uint64) []byte { 49 com := uint64(len(m.buf)) 50 res := uint64(cap(m.buf)) 51 if com < size && size < res { 52 // Round up to the page size. 53 rnd := uint64(windows.Getpagesize() - 1) 54 new := (size + rnd) &^ rnd 55 56 // Commit additional memory up to new bytes. 57 _, err := windows.VirtualAlloc(m.addr, uintptr(new), windows.MEM_COMMIT, windows.PAGE_READWRITE) 58 if err != nil { 59 panic(err) 60 } 61 62 // Update committed memory. 63 m.buf = m.buf[:new] 64 } 65 // Limit returned capacity because bytes beyond 66 // len(m.buf) have not yet been committed. 67 return m.buf[:size:len(m.buf)] 68 } 69 70 func (m *virtualMemory) Free() { 71 err := windows.VirtualFree(m.addr, 0, windows.MEM_RELEASE) 72 if err != nil { 73 panic(err) 74 } 75 m.addr = 0 76 }