Skip to main content

15  Memory, Arenas, Addr and FFI

Edva executes without a garbage collector or runtime type headers. Memory is managed deterministically through stack values, scoped bump arenas, explicit Builder buffers, and raw Addr pointers for low-level systems and C FFI interoperability.

15.1 Runtime value and memory model

Category Types Allocation & Passing Model
Immediate register values Int, i8..u64, Float, f32, Rune, <>, Addr, () Held directly in CPU/SIMD registers and stack slots; zero heap allocation
Unboxed descriptors / pairs String (16B), T[] (16B), A => B (16B), RamPP { i1, i64 } (16B), Enum { i64, ptr } (16B) Descriptors pass by value in registers; pointed-to payload bytes live in the active arena
Growable arena containers Builder (24B), T{} (24B), K ^ V (ptr) Backing buffers allocate and double in the active arena
Deep copy (++x) String, Builder, Record, T{}, T[] Allocates a fresh copy in the current arena (use before arena scope exit to promote values)
State binding lens (~~lvalue) Mutable variable x', field r.f, array slot xs(i), map slot m ^ k Constructs a two-way accessor record (get: () => T, set: T => ())
#use io

probe: () => Int
probe = !=>
   count' = 10
   lens = ~~count'
   lens.set(lens.get! + 5)
   count'

io::out $ probe!   // 15

15.2 Raw pointers (Addr), &, and volatile memory (@[...])

Addr (alias ptr) is an untyped raw memory address (8 bytes on 64-bit targets, 4 bytes on 32-bit targets, lowered to LLVM ptr).

Operation Syntax Operand / Result Types Rules & Diagnostics
Null / integer cast Addr(0), Addr(0x1000), Int(p) Int (i8..u64) \(\leftrightarrow\) Addr Bidirectional between integerish scalars and Addr. Casting records/arrays/functions via Addr(rec) emits E3084 (use &rec)
String / Builder data ptr &s, &b String / Builder \(\to\) Addr No space after &. &s points to NUL-terminated UTF-8 bytes; &b points to writable buffer
Composite address &rec Record / tuple \(\to\) Addr Pointer to record storage
Scalar out-parameter libc::fn(fd, &len') Scalar variable \(\to\) Addr Permitted strictly in downward call-argument position; storing p = &len' emits E3078
Pointer arithmetic p + offset, p - offset Addr, Int \(\to\) Addr Byte-offset pointer arithmetic
Pointer comparison p1 == p2, p1 < p2, p1 !< p2 Addr, Addr \(\to\) <> Unsigned address comparison
Provenance bitmask %ptrmask(p, mask) Addr, Int \(\to\) Addr Masks pointer bits (e.g. 0b1{48}) while preserving LLVM pointer provenance
Volatile typed load @[addr T] Addr, Type \(\to\) T Reads value of type T from addr (or zero-copy record view when T is a #packed record)
Volatile untyped store @[addr] = val Addr, val: T \(\to\) () Stores val at addr using the width of val. Writing @[addr T] = val emits E2093
#use io

b = {16}
@[&b] = 69u8
@[&b + 1] = 100u8
@[&b + 2] = 118u8
@[&b + 3] = 97u8
?b = 4
io::out $ +b   // Edva

15.3 C FFI (#foreign, #export) and ABI conventions

FFI Feature Syntax & Convention Specification
Import C symbol #foreign "c" open: Addr, i32, i32 => i32
#foreign "m" hypot: Float, Float => Float
Links against libc, libm, or native libraries declared in edva.ccl (native.libs / native.pkg-config); explicit type signature required (E2060)
Export C symbol #export compute: i32, i32 => i32 Emits unmangled symbol with platform C calling convention
C string passing libc::puts(&s) Whole String values guarantee data[len] == '\0'; slices s(a..b) share interior bytes and must be copied (++sub) if a trailing \0 is required by C
C buffer reads n = libc::read(fd, &b, 1024); ?b = n Pass &b for writable buffer pointer, then update ?b = n (0 <= n <= cap, E4008)
C struct layout #type Stat (...) / #type Hdr #packed (...) Named records match platform C struct ABI layout; #packed and #align N match __attribute__((packed, aligned(N)))

15.4 Supported target triples and architecture rules

Pass -t <triple> (or --target <triple>) on the CLI or set target = <triple> under targets = in edva.ccl:

Target Triple Architecture Int Width Addr Width Runtime Notes
x86_64-unknown-linux-gnu x86-64 Linux (default host) 64-bit (i64) 64-bit (8B) Full POSIX / libc / io_uring support
aarch64-linux-gnu ARM64 Linux 64-bit (i64) 64-bit (8B) Requires AArch64 sysroot/linker when cross-linking
wasm32-unknown-unknown WebAssembly (freestanding) 64-bit (i64) 32-bit (4B) Exports #export functions directly; --cflag -msimd128 enables SIMD128
wasm32-wasi WebAssembly System Interface 64-bit (i64) 32-bit (4B) Hosted WASI I/O and filesystem