nx_wasm_scratch.nx source
↩ module page · 46 lines · 2373 B
1// nx_wasm_scratch.nx -- WASM-lane framed SCRATCH allocator: the linear-memory port of nx_scratch
2// (nx_u256.nx), which is NATIVE-ONLY because it grows via sys_mmap (no wasm shim). This gives WASM organs
3// the SAME save/alloc/restore shadow-stack the native lane has -> native<->wasm parity for multi-word locals,
4// matching the language's REAL idiom (nx_scratch pointers) rather than a [i64;N] stack-array compiler feature
5// the codebase deliberately rejects (nx_types.nx:469). Backed by a fixed linear-memory arena + a cursor cell;
6// uses ONLY i64.load/store + arithmetic, so it runs in nx_wasm_vm and the browser with no syscalls.
7// license_tier: ORIGINAL (API + frame discipline from nx_scratch in nx_u256.nx; mmap-arena -> linear-mem arena)
8//
9// Memory map (within the backend's 32-page / 2 MiB linear memory):
10// [0 .. WS_BASE) organ's own fixed-offset region (framebuffers, guest RAM, etc.)
11// [WS_BASE .. WS_TOP) the scratch arena (grows UP)
12// [WS_CUR_CELL .. +8) the live cursor (the single-i64 frame mark), at the very top
13const WS_BASE: i64 = 1048576 // 1 MiB
14const WS_TOP: i64 = 2097144 // arena end (just below the cursor cell)
15const WS_CUR_CELL: i64 = 2097144 // 8-byte cursor cell at the top of the 2 MiB memory
16
17// read the live cursor; self-initialise to WS_BASE on first use (a real cursor is never 0).
18func ws_cur_load() -> i64 {
19 let cell: *i64 = WS_CUR_CELL as *i64
20 var c: i64 = cell[0]
21 if c == 0 { c = WS_BASE }
22 return c
23}
24func ws_cur_store(c: i64) -> i64 {
25 let cell: *i64 = WS_CUR_CELL as *i64
26 cell[0] = c
27 return 0
28}
29
30// allocate n bytes (rounded up to 8), zeroed; returns the linear-memory address as *u8.
31// fail-closed (return null) on arena overflow -- NEVER corrupt the cursor cell / silently wrap.
32func nx_scratch(n: i64) -> *u8 {
33 let aligned: i64 = ((n + 7) / 8) * 8
34 let cur: i64 = ws_cur_load()
35 if cur + aligned > WS_TOP { return 0 as *u8 }
36 ws_cur_store(cur + aligned)
37 let pw: *i64 = cur as *i64
38 let words: i64 = aligned / 8
39 var i: i64 = 0
40 while i < words { pw[i] = 0; i = i + 1 }
41 return cur as *u8
42}
43
44// LIFO frame: save returns the current cursor; restore rewinds to it (reclaims every alloc since).
45func nx_scratch_save() -> i64 { return ws_cur_load() }
46func nx_scratch_restore(mark: i64) -> i64 { ws_cur_store(mark); return 0 }