alloc_windows.go

 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}