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