Skip to content

Commit 55f21b8

Browse files
authored
experimental: custom memory allocator API tweaks (#2186)
Signed-off-by: Nuno Cruces <[email protected]>
1 parent e9bea55 commit 55f21b8

File tree

3 files changed

+39
-26
lines changed

3 files changed

+39
-26
lines changed

experimental/memory.go

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,36 @@ import (
66
"github.com/tetratelabs/wazero/internal/expctxkeys"
77
)
88

9-
// MemoryAllocator is a memory allocation hook which is invoked
10-
// to create a new MemoryBuffer, with the given specification:
11-
// min is the initial and minimum length (in bytes) of the backing []byte,
12-
// cap a suggested initial capacity, and max the maximum length
13-
// that will ever be requested.
14-
type MemoryAllocator func(min, cap, max uint64) MemoryBuffer
9+
// MemoryAllocator is a memory allocation hook,
10+
// invoked to create a LinearMemory.
11+
type MemoryAllocator interface {
12+
// Allocate should create a new LinearMemory with the given specification:
13+
// cap is the suggested initial capacity for the backing []byte,
14+
// and max the maximum length that will ever be requested.
15+
//
16+
// Notes:
17+
// - To back a shared memory, the address of the backing []byte cannot
18+
// change. This is checked at runtime. Implementations should document
19+
// if the returned LinearMemory meets this requirement.
20+
Allocate(cap, max uint64) LinearMemory
21+
}
22+
23+
// MemoryAllocatorFunc is a convenience for defining inlining a MemoryAllocator.
24+
type MemoryAllocatorFunc func(cap, max uint64) LinearMemory
25+
26+
// Allocate implements MemoryAllocator.Allocate.
27+
func (f MemoryAllocatorFunc) Allocate(cap, max uint64) LinearMemory {
28+
return f(cap, max)
29+
}
1530

16-
// MemoryBuffer is a memory buffer that backs a Wasm memory.
17-
type MemoryBuffer interface {
18-
// Buffer returns the backing []byte for the memory buffer.
19-
Buffer() []byte
20-
// Grow the backing memory buffer to size bytes in length.
21-
// To back a shared memory, Grow can't change the address
22-
// of the backing []byte (only its length/capacity may change).
23-
Grow(size uint64) []byte
31+
// LinearMemory is an expandable []byte that backs a Wasm linear memory.
32+
type LinearMemory interface {
33+
// Reallocates the linear memory to size bytes in length.
34+
//
35+
// Notes:
36+
// - To back a shared memory, Reallocate can't change the address of the
37+
// backing []byte (only its length/capacity may change).
38+
Reallocate(size uint64) []byte
2439
// Free the backing memory buffer.
2540
Free()
2641
}

internal/wasm/memory.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ type MemoryInstance struct {
5959
// with a fixed weight of 1 and no spurious notifications.
6060
waiters sync.Map
6161

62-
expBuffer experimental.MemoryBuffer
62+
expBuffer experimental.LinearMemory
6363
}
6464

6565
// NewMemoryInstance creates a new instance based on the parameters in the SectionIDMemory.
@@ -69,10 +69,10 @@ func NewMemoryInstance(memSec *Memory, allocator experimental.MemoryAllocator) *
6969
maxBytes := MemoryPagesToBytesNum(memSec.Max)
7070

7171
var buffer []byte
72-
var expBuffer experimental.MemoryBuffer
72+
var expBuffer experimental.LinearMemory
7373
if allocator != nil {
74-
expBuffer = allocator(minBytes, capBytes, maxBytes)
75-
buffer = expBuffer.Buffer()
74+
expBuffer = allocator.Allocate(capBytes, maxBytes)
75+
buffer = expBuffer.Reallocate(minBytes)
7676
} else if memSec.IsShared {
7777
// Shared memory needs a fixed buffer, so allocate with the maximum size.
7878
//
@@ -233,7 +233,7 @@ func (m *MemoryInstance) Grow(delta uint32) (result uint32, ok bool) {
233233
if newPages > m.Max || int32(delta) < 0 {
234234
return 0, false
235235
} else if m.expBuffer != nil {
236-
buffer := m.expBuffer.Grow(MemoryPagesToBytesNum(newPages))
236+
buffer := m.expBuffer.Reallocate(MemoryPagesToBytesNum(newPages))
237237
if m.Shared {
238238
if unsafe.SliceData(buffer) != unsafe.SliceData(m.Buffer) {
239239
panic("shared memory cannot move, this is a bug in the memory allocator")

internal/wasm/memory_test.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func TestMemoryInstance_Grow_Size(t *testing.T) {
5555
case tc.capEqualsMax:
5656
m = &MemoryInstance{Cap: max, Max: max, Buffer: make([]byte, 0, maxBytes)}
5757
case tc.expAllocator:
58-
expBuffer := sliceAllocator(0, 0, maxBytes)
59-
m = &MemoryInstance{Max: max, Buffer: expBuffer.Buffer(), expBuffer: expBuffer}
58+
expBuffer := sliceAllocator(0, maxBytes)
59+
m = &MemoryInstance{Max: max, Buffer: expBuffer.Reallocate(0), expBuffer: expBuffer}
6060
}
6161

6262
res, ok := m.Grow(5)
@@ -994,8 +994,8 @@ func requireChannelEmpty(t *testing.T, ch chan string) {
994994
}
995995
}
996996

997-
func sliceAllocator(min, cap, max uint64) experimental.MemoryBuffer {
998-
return &sliceBuffer{make([]byte, min, cap), max}
997+
func sliceAllocator(cap, max uint64) experimental.LinearMemory {
998+
return &sliceBuffer{make([]byte, cap), max}
999999
}
10001000

10011001
type sliceBuffer struct {
@@ -1005,9 +1005,7 @@ type sliceBuffer struct {
10051005

10061006
func (b *sliceBuffer) Free() {}
10071007

1008-
func (b *sliceBuffer) Buffer() []byte { return b.buf }
1009-
1010-
func (b *sliceBuffer) Grow(size uint64) []byte {
1008+
func (b *sliceBuffer) Reallocate(size uint64) []byte {
10111009
if cap := uint64(cap(b.buf)); size > cap {
10121010
b.buf = append(b.buf[:cap], make([]byte, size-cap)...)
10131011
} else {

0 commit comments

Comments
 (0)