Skip to content

Commit 48ba71f

Browse files
committed
runtime: Fix WASM memory allocation
1 parent c364701 commit 48ba71f

File tree

1 file changed

+20
-23
lines changed

1 file changed

+20
-23
lines changed

runtime/wasm/src/module/mod.rs

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,11 @@ pub(crate) struct WasmiModule<T, L, S, U> {
191191
// This is used to prevent mutating store state in start.
192192
running_start: bool,
193193

194-
// First free byte in the heap.
195-
heap_start_ptr: u32,
194+
// First free byte in the current arena.
195+
arena_start_ptr: u32,
196196

197-
// Number of free bytes starting from `heap_start_ptr`.
198-
heap_free_size: u32,
197+
// Number of free bytes starting from `arena_start_ptr`.
198+
arena_free_size: u32,
199199
}
200200

201201
impl<T, L, S, U> WasmiModule<T, L, S, U>
@@ -245,9 +245,9 @@ where
245245
start_time: Instant::now(),
246246
running_start: true,
247247

248-
// `heap_start_ptr` will be set on the first call to `raw_new`.
249-
heap_free_size: 0,
250-
heap_start_ptr: 0,
248+
// `arena_start_ptr` will be set on the first call to `raw_new`.
249+
arena_free_size: 0,
250+
arena_start_ptr: 0,
251251
};
252252

253253
this.module = module
@@ -420,35 +420,32 @@ where
420420
+ 'static,
421421
{
422422
fn raw_new(&mut self, bytes: &[u8]) -> Result<u32, Error> {
423-
// We request large chunks from the AssemblyScript allocator and manage them ourselves.
424-
// This assumes the arena allocator is being used in AS.
423+
// We request large chunks from the AssemblyScript allocator to use as arenas that we
424+
// manage directly.
425425

426-
static MIN_HEAP_SIZE_INCREMENT: u32 = 10_000;
426+
static MIN_ARENA_SIZE: u32 = 10_000;
427427

428428
let size = u32::try_from(bytes.len()).unwrap();
429-
if size > self.heap_free_size {
430-
let need = size - self.heap_free_size;
431-
let allocate = need.max(MIN_HEAP_SIZE_INCREMENT);
429+
if size > self.arena_free_size {
430+
// Allocate a new arena. Any free space left in the previous arena is left unused. This
431+
// causes at most half of memory to be wasted, which is acceptable.
432+
let arena_size = size.max(MIN_ARENA_SIZE);
432433
let allocated_ptr = self
433434
.module
434435
.clone()
435-
.invoke_export("memory.allocate", &[RuntimeValue::from(allocate)], self)
436+
.invoke_export("memory.allocate", &[RuntimeValue::from(arena_size)], self)
436437
.expect("Failed to invoke memory allocation function")
437438
.expect("Function did not return a value")
438439
.try_into::<u32>()
439440
.expect("Function did not return u32");
440-
self.heap_free_size += allocate;
441-
442-
// On the first call, initialze `self.heap_start_ptr`.
443-
if self.heap_start_ptr == 0 {
444-
self.heap_start_ptr = allocated_ptr;
445-
}
441+
self.arena_start_ptr = allocated_ptr;
442+
self.arena_free_size = arena_size;
446443
};
447444

448-
let ptr = self.heap_start_ptr;
445+
let ptr = self.arena_start_ptr;
449446
self.memory.set(ptr, bytes)?;
450-
self.heap_start_ptr += size;
451-
self.heap_free_size -= size;
447+
self.arena_start_ptr += size;
448+
self.arena_free_size -= size;
452449

453450
Ok(ptr)
454451
}

0 commit comments

Comments
 (0)