diff --git a/go.mod b/go.mod index 7db26699..bba9944c 100644 --- a/go.mod +++ b/go.mod @@ -14,4 +14,4 @@ require ( retract v0.4.0 // tagged from the wrong branch -replace github.com/tetratelabs/wazero => github.com/ncruces/wazero v0.0.0-20240406121256-0283488c26c8 +replace github.com/tetratelabs/wazero => github.com/ncruces/wazero v0.0.0-20240409112346-f2be6da37a3d diff --git a/go.sum b/go.sum index 8a4222dc..b7cf7d7c 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M= github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= -github.com/ncruces/wazero v0.0.0-20240406121256-0283488c26c8 h1:Xix9dlK5BpStboVxuRS/DNdwE2YqGROwf7gfqHJn/Mk= -github.com/ncruces/wazero v0.0.0-20240406121256-0283488c26c8/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= +github.com/ncruces/wazero v0.0.0-20240409112346-f2be6da37a3d h1:t3S5uhR50fDxrCgoMLcVDFo2jpYdKjq5VWbXFUMHv0w= +github.com/ncruces/wazero v0.0.0-20240409112346-f2be6da37a3d/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIwZLUE= github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= diff --git a/go.work.sum b/go.work.sum index 44186537..e1395588 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,5 +1,5 @@ -github.com/ncruces/wazero v0.0.0-20240406121256-0283488c26c8 h1:Xix9dlK5BpStboVxuRS/DNdwE2YqGROwf7gfqHJn/Mk= -github.com/ncruces/wazero v0.0.0-20240406121256-0283488c26c8/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= +github.com/ncruces/wazero v0.0.0-20240409112346-f2be6da37a3d h1:t3S5uhR50fDxrCgoMLcVDFo2jpYdKjq5VWbXFUMHv0w= +github.com/ncruces/wazero v0.0.0-20240409112346-f2be6da37a3d/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= diff --git a/internal/util/alloc.go b/internal/util/alloc.go index eccfb6d5..9601dcf0 100644 --- a/internal/util/alloc.go +++ b/internal/util/alloc.go @@ -1,53 +1,68 @@ -//go:build (linux || darwin) && (amd64 || arm64) +//go:build unix package util import ( "math" - "syscall" -) -type MmapedMemoryAllocator []byte + "github.com/tetratelabs/wazero/experimental" + "golang.org/x/sys/unix" +) -func (m *MmapedMemoryAllocator) Make(min, cap, max uint64) []byte { +func mmappedAllocator(min, cap, max uint64) experimental.MemoryBuffer { if max > math.MaxInt { // This ensures int(max) overflows to a negative value, - // and syscall.Mmap returns EINVAL. + // and unix.Mmap returns EINVAL. max = math.MaxUint64 } // Reserve the full max bytes of address space, to ensure we don't need to move it. // A protected, private, anonymous mapping should not commit memory. - b, err := syscall.Mmap(-1, 0, int(max), syscall.PROT_NONE, syscall.MAP_PRIVATE|syscall.MAP_ANON) + b, err := unix.Mmap(-1, 0, int(max), unix.PROT_NONE, unix.MAP_PRIVATE|unix.MAP_ANON) if err != nil { panic(err) } - // Commit the initial min bytes of memory. - err = syscall.Mprotect(b[:min], syscall.PROT_READ|syscall.PROT_WRITE) + // Commit the initial cap bytes of memory. + err = unix.Mprotect(b[:cap], unix.PROT_READ|unix.PROT_WRITE) if err != nil { - syscall.Munmap(b) + unix.Munmap(b) panic(err) } - b = b[:min] - *m = b - return b + return &mmappedBuffer{ + buf: b[:cap], + cur: min, + } +} + +// The slice covers the entire mmapped memory: +// - len(buf) is the already committed memory, +// - cap(buf) is the reserved address space, +// - cur is the already requested size. +type mmappedBuffer struct { + buf []byte + cur uint64 +} + +func (m *mmappedBuffer) Buffer() []byte { + // Limit capacity because bytes beyond len(m.buf) + // have not yet been committed. + return m.buf[:m.cur:len(m.buf)] } -func (m *MmapedMemoryAllocator) Grow(size uint64) []byte { - b := *m +func (m *mmappedBuffer) Grow(size uint64) []byte { // Commit additional memory up to size bytes. - err := syscall.Mprotect(b[len(b):size], syscall.PROT_READ|syscall.PROT_WRITE) + err := unix.Mprotect(m.buf[len(m.buf):size], unix.PROT_READ|unix.PROT_WRITE) if err != nil { panic(err) } - b = b[:size] - *m = b - return b + m.buf = m.buf[:size] + m.cur = size + return m.Buffer() } -func (m *MmapedMemoryAllocator) Free() { - err := syscall.Munmap(*m) +func (m *mmappedBuffer) Free() { + err := unix.Munmap(m.buf) if err != nil { panic(err) } - *m = nil + m.buf = nil } diff --git a/internal/util/handle.go b/internal/util/handle.go index cf4359c5..4584324c 100644 --- a/internal/util/handle.go +++ b/internal/util/handle.go @@ -10,12 +10,14 @@ type handleState struct { holes int } -func (s *handleState) close() { +func (s *handleState) CloseNotify(ctx context.Context, exitCode uint32) { for _, h := range s.handles { if c, ok := h.(io.Closer); ok { c.Close() } } + s.handles = nil + s.holes = 0 } func GetHandle(ctx context.Context, id uint32) any { diff --git a/internal/util/mmap.go b/internal/util/mmap.go index 17ab0d60..c2216940 100644 --- a/internal/util/mmap.go +++ b/internal/util/mmap.go @@ -19,7 +19,7 @@ type mmapState struct { func (s *mmapState) init(ctx context.Context, enabled bool) context.Context { if s.enabled = enabled; enabled { - return experimental.WithMemoryAllocator(ctx, &MmapedMemoryAllocator{}) + return experimental.WithMemoryAllocator(ctx, mmappedAllocator) } return ctx } diff --git a/internal/util/module.go b/internal/util/module.go index 9d5d153b..0db93bbb 100644 --- a/internal/util/module.go +++ b/internal/util/module.go @@ -19,8 +19,3 @@ func NewContext(ctx context.Context, mappableMemory bool) context.Context { ctx = state.mmapState.init(ctx, mappableMemory) return ctx } - -func (s *moduleState) CloseNotify(ctx context.Context, exitCode uint32) { - s.handleState.close() - *s = moduleState{} -}