zena:memory

zena
import {…} from 'zena:memory';

Low-level access to WebAssembly linear memory and memory allocators.

Provides Memory for reading and writing typed values at raw byte addresses, and allocator implementations (Allocator, FreeListAllocator, BumpAllocator) for managing linear memory buffers.

Examples ​

zena
import { Memory, defaultAllocator } from 'zena:memory';

if (let (true, ptr) = defaultAllocator.alloc(64)) {
  let mem = Memory.default;
  mem.setI32(ptr, 42);
  let val = mem.getI32(ptr);
  defaultAllocator.free(ptr);
}

Classes

Memory

zena
final class Memory
Re-exported from zena:memory.zena

Represents the WASM linear memory as an array-like object. Provides typed access to memory via operator overloading.

Properties
zena
static default: Memory
#

The default memory instance (memory index 0).

zena
byteLength: i32 { get; }
#

The current size in bytes.

Methods
zena
size(): i32
#

Get the current size of linear memory in 64KB pages.

zena
grow(pages: i32): i32
#

Grow linear memory by the specified number of pages. Returns the previous size in pages, or -1 on failure.

zena
getU8(ptr: i32): i32
#

Load an unsigned byte from the given address.

zena
setU8(ptr: i32, value: i32): void
#

Store a byte at the given address.

zena
getI32(ptr: i32): i32
#

Load a 32-bit signed integer from the given address.

zena
setI32(ptr: i32, value: i32): void
#

Store a 32-bit integer at the given address.

zena
getI64(ptr: i32): i64
#

Load a 64-bit signed integer from the given address.

zena
setI64(ptr: i32, value: i64): void
#

Store a 64-bit integer at the given address.

zena
getF32(ptr: i32): f32
#

Load a 32-bit float from the given address.

zena
setF32(ptr: i32, value: f32): void
#

Store a 32-bit float at the given address.

zena
getF64(ptr: i32): f64
#

Load a 64-bit float from the given address.

zena
setF64(ptr: i32, value: f64): void
#

Store a 64-bit float at the given address.

zena
getS8(ptr: i32): i32
#

Load a signed byte, sign-extended to i32.

zena
getU16(ptr: i32): i32
#

Load an unsigned little-endian 16-bit integer.

zena
getS16(ptr: i32): i32
#

Load a signed little-endian 16-bit integer, sign-extended to i32.

zena
setU16(ptr: i32, value: i32): void
#

Store the low 16 bits of value, little-endian.

zena
copyFromBytes(ptr: i32, bytes: FixedArray<u8>, start: i32, len: i32): void
#

Copy len bytes of bytes, from index start, to ptr.

zena
copyToBytes(ptr: i32, bytes: FixedArray<u8>, start: i32, len: i32): void
#

Copy len bytes at ptr into bytes, from index start.

zena
bytesAt(ptr: i32, len: i32): FixedArray<u8>
#

The len bytes at ptr, as a fresh array.

zena
copyToByteArray(ptr: i32, bytes: ByteArray, start: i32, len: i32): void
#

Copy len bytes at ptr into a ByteArray, from index start. For building a String's backing store from memory without an intermediate array: a String is a view over a ByteArray.

zena
copyFromString(ptr: i32, s: String, start: i32, len: i32): void
#

Copy len bytes of s, from byte index start, to ptr. The bytes are copied as the string stores them, with no re-encoding; a caller that needs UTF-8 checks the encoding first.

zena
copy(dst: i32, src: i32, len: i32): void
#

Copy len bytes from src to dst, both in linear memory. The ranges must not overlap unless dst is below src: the copy runs forward, so a destination above an overlapping source would read bytes it had already overwritten. Every caller so far moves a block into a fresh allocation.

Operators
zena
operator [](index: i32): i32
#

Read a byte at the given index.

zena
operator []=(index: i32, value: i32): void
#

Write a byte at the given index.

FreeListAllocator

zena
final class FreeListAllocator implements Allocator
Implements Allocator
Re-exported from zena:memory.zena

A free-list allocator that supports both alloc() and free().

Uses a simple first-fit free list. Each block has an 8-byte header: [size: i32, next: i32] (next is only used when block is free)

This is the recommended allocator for general use where memory needs to be reclaimed.

Constructors
zena
new(startPtr: i32)
#
Properties
zena
static default: FreeListAllocator
#

The default allocator, starting at byte 65536 (page 1) to avoid WASI console buffer overlap.

zena
allocated: i32 { get; }
#

Get approximate bytes currently allocated (not including freed).

Methods
zena
alloc(bytes: i32): inline (true, i32) | inline (false, _)
#

Allocate bytes bytes of linear memory.

zena
allocAligned(bytes: i32, align: i32): inline (true, i32) | inline (false, _)
#

Allocate bytes bytes at an address that is a multiple of align, a power of two.

Every block is already 8-aligned. For a larger alignment this takes a block with room to spare and moves the address forward to an aligned one at least 16 bytes in, then writes a header in front of the new address describing the rest of the block. The part skipped over keeps the original header, shrunk to fit, and goes onto the free list. Both halves are ordinary blocks, so free takes the aligned pointer like any other.

zena
free(ptr: i32): void
#

Free a previously allocated pointer.

BumpAllocator

zena
final class BumpAllocator implements Allocator
Implements Allocator
Re-exported from zena:memory.zena

A bump-pointer allocator for arena-style memory management.

Fast allocation (just increment a pointer), but free() is a no-op. Use reset() to free all allocations at once.

To create a BumpAllocator, first allocate a region from the root allocator:

zena
if (let (true, region) = defaultAllocator.alloc(4096)) {
  let arena = new BumpAllocator(region, 4096);
  if (let (true, ptr) = arena.alloc(64)) {
    // use ptr
  }
  arena.reset();  // Reuse the arena
  defaultAllocator.free(region);
}

Best for: temporary allocations with known lifetime, scratch buffers.

Constructors
zena
new(startPtr: i32, size: i32)
#

Create a BumpAllocator over a pre-allocated memory region.

startPtr

Start of the region (from another allocator)

size

Size of the region in bytes

Properties
zena
allocated: i32 { get; }
#

The number of bytes currently allocated.

zena
remaining: i32 { get; }
#

The number of bytes remaining in the arena.

Methods
zena
alloc(bytes: i32): inline (true, i32) | inline (false, _)
#

Allocate bytes bytes. Returns (true, ptr) on success, (false, _) if exhausted.

zena
allocAligned(bytes: i32, align: i32): inline (true, i32) | inline (false, _)
#

Allocate with alignment. Returns (true, ptr) on success, (false, _) if exhausted.

zena
free(ptr: i32): void
#

Free is a no-op for bump allocators. Use reset() instead.

zena
reset(): void
#

Reset the allocator to its initial state, allowing reuse. WARNING: This invalidates ALL previously allocated pointers!

Interfaces

Allocator

zena
interface Allocator
Re-exported from zena:memory.zena

Interface for linear memory allocators. Libraries should accept Allocator to allow flexible memory strategies.

Allocation methods return (true, ptr) | (false, _) to force callers to handle allocation failures. Use pattern matching:

zena
if (let (true, ptr) = alloc.alloc(size)) {
  // use ptr
} else {
  // handle out of memory
}
Methods
zena
alloc(bytes: i32): inline (true, i32) | inline (false, _)
#

Allocate bytes bytes. Returns (true, ptr) on success, (false, _) on failure.

zena
allocAligned(bytes: i32, align: i32): inline (true, i32) | inline (false, _)
#

Allocate bytes bytes aligned to align (must be power of 2).

zena
free(ptr: i32): void
#

Free a previously allocated pointer. May be a no-op for some allocators.

Variables

defaultAllocator

zena
let defaultAllocator: Allocator