alloc_windows.go 1.8 KB

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