code wiki / (root) / nx_arena_types.nx

nx_arena_types.nx source

↩ module page · 122 lines · 4614 B

1// nx_arena_types.nx -- arena type + constants, zero-syscall. 2// 3// FOUR-PILLAR FIX (2026-05-16): nx_arena.nx hard-imports nx_syscalls.nx 4// because nx_arena_new() calls sys_mmap internally. Any caller that 5// wanted to compose against nx_arena PLUS a different syscall layer 6// (e.g., nx_syscalls_x86_64.nx for native exec) hit linker symbol 7// redefinition -- the F-meta-4-class cross-target portability gap. 8// 9// This file ADDS the inversion-of-control entry point. It carries: 10// - struct NxArena (the type) 11// - NX_ARENA_BYTES (sizeof constant) 12// - nx_arena_align_up (pure math) 13// - nx_arena_alloc / _alloc_zero / _reset / _used / _cap_bytes / 14// _alloc_count / _oom_count (operate on a caller-owned arena) 15// - nx_arena_init(a, base, cap) (init a caller-allocated NxArena 16// struct + caller-allocated backing buffer) 17// 18// What it does NOT carry: nx_arena_new (which mmaps). That stays 19// in nx_arena.nx for backwards-compat + convenience. Callers that 20// want a different syscall ABI can: 21// 22// 1. allocate the NxArena struct + backing buffer themselves 23// 2. call nx_arena_init(a, base, cap) 24// 3. pass `a` to nx_arena_alloc + friends as before 25// 26// Per cardinal user-owns-every-bit: this is the canonical shape. 27// The caller mmaps the bytes (using whichever syscall layer matches 28// the target ABI); substrate just uses them. 29// 30// nx_capability_claims: 31// needs: [pointer_arithmetic, struct_field_assign] 32// provides: [arena_type, arena_init, arena_alloc, arena_reset] 33// safety: [no_unchecked_deref, no_floating_point, no_syscall, 34// bit_equal_reproducible, target_agnostic] 35// verdict: [no_silent_failure (oom returns null + n_oom++)] 36// license: ORIGINAL 37// kind: racing_crew_specialist 38 39// No imports. This file is the BASE LAYER -- types + pure-math 40// alloc/reset/inspect with zero syscall dependency. Per cardinal 41// user-owns-every-bit: caller picks the syscall ABI by importing 42// whichever nx_syscalls*.nx layer matches their target. 43 44struct NxArena { 45 base: *u8, // backing storage (caller-owned) 46 cap: i64, // total capacity bytes 47 off: i64, // current bump position (bytes used) 48 n_alloc: i64, // total alloc requests served (for diag) 49 n_oom: i64, // total alloc requests that overflowed cap 50} 51 52const NX_ARENA_BYTES: i64 = 40 53 54// --- construction (no syscalls; caller supplies bytes) ------------- 55 56// Init a caller-allocated NxArena with a caller-allocated backing 57// buffer. Caller's responsibility: 58// - allocate sizeof(NxArena) bytes for `a` 59// - allocate `cap` bytes for `base` 60// - keep both alive for the arena's lifetime 61// 62// Per cardinal user-owns-every-bit: substrate doesn't pick the 63// allocation strategy. Use sys_mmap if you want pages; use a 64// static [u8; N] if you want a fixed buffer; use a file mapping 65// if you want disk-backed. 66func nx_arena_init(a: *NxArena, base: *u8, cap: i64) -> i64 { 67 if a == (0 as *NxArena) { return -1 } 68 if base == (0 as *u8) { return -2 } 69 if cap <= 0 { return -3 } 70 a.base = base 71 a.cap = cap 72 a.off = 0 73 a.n_alloc = 0 74 a.n_oom = 0 75 return 0 76} 77 78// --- alloc (no syscalls) ------------------------------------------- 79 80// Round x up to the nearest multiple of align (align must be power-of-2). 81func nx_arena_align_up(x: i64, align: i64) -> i64 { 82 let mask: i64 = align - 1 83 return (x + mask) & (~mask) 84} 85 86// Bump n bytes with align-byte alignment. Returns a *u8 into the 87// arena's backing storage on success, or NULL on overflow. 88func nx_arena_alloc(a: *NxArena, n: i64, align: i64) -> *u8 { 89 if n <= 0 { return 0 as *u8 } 90 if align <= 0 { return 0 as *u8 } 91 let aligned: i64 = nx_arena_align_up(a.off, align) 92 let next: i64 = aligned + n 93 if next > a.cap { 94 a.n_oom = a.n_oom + 1 95 return 0 as *u8 96 } 97 a.off = next 98 a.n_alloc = a.n_alloc + 1 99 let p: i64 = (a.base as i64) + aligned 100 return p as *u8 101} 102 103// Zero-init variant. 104func nx_arena_alloc_zero(a: *NxArena, n: i64, align: i64) -> *u8 { 105 let p: *u8 = nx_arena_alloc(a, n, align) 106 if p == (0 as *u8) { return p } 107 var i: i64 = 0 108 while i < n { p[i] = 0; i = i + 1 } 109 return p 110} 111 112// --- reset / inspect (no syscalls) --------------------------------- 113 114func nx_arena_reset(a: *NxArena) -> i64 { 115 a.off = 0 116 return 0 117} 118 119func nx_arena_used(a: *NxArena) -> i64 { return a.off } 120func nx_arena_cap_bytes(a: *NxArena) -> i64 { return a.cap } 121func nx_arena_alloc_count(a: *NxArena) -> i64 { return a.n_alloc } 122func nx_arena_oom_count(a: *NxArena) -> i64 { return a.n_oom }