code wiki / (root) / nx_wasmfit.nx

nx_wasmfit.nx source

↩ module page · 109 lines · 6510 B

1// nx_wasmfit.nx -- THE ONE RULER FOR "CAN THIS MODULE'S FRAMEBUFFER EXIST IN THE MEMORY IT DECLARES". 2// 3// WHY IT IS A LIBRARY AND NOT A CHECK INSIDE AN EMITTER. On 2026-08-14 /craft shipped BLACK TWICE: its 4// framebuffer had outgrown the module's own declared linear memory (needed 22,022,528 bytes against 5// 192 pages = 12,582,912), so every browser frame trapped with "index out of bounds". The guard that 6// now refuses that was written INSIDE nx_game_page_emit's gpe_build_s, whose header claimed "every 7// wasm page in the estate is built through this function -- one guard here covers all of them". 8// 9// THAT CLAIM WAS FALSE, AND MEASURED SO ON 2026-08-15. nx_wasmpage_census walked all 62,906 shipped 10// html pages: 25 carry an embedded wasm module, and only 9 come from gpe_build_s. The other 16 -- 11// pong, racing, td, city, shmup, explorer, adventure, voxelworld, sudoku and the rest -- are emitted 12// by organs that each hand-pasted their own copy of the same blit shim and none of the guard. 13// ★★★★★★A GUARD PLACED IN "THE" SHARED PATH IS ONLY AS BROAD AS THE CLAIM THAT THE PATH IS SHARED, 14// AND THAT CLAIM IS A MEASUREMENT NOBODY TOOK. The census took it and the answer was 9 of 25. 15// 16// So the ruler moves DOWN here, where any emitter can reach it, and gpe_build_s becomes one of its 17// callers rather than its owner. ★EXTEND THE INCUMBENT, NEVER ADD A SECOND RULER: the arithmetic below 18// is gpe_build_s's, moved rather than re-typed, so there is exactly one definition of "fits" in the 19// estate and no opportunity for two of them to drift. 20// 21// It asks the ARTIFACT, never a constant typed in another file: wm_parse reads the module's own memory 22// section, and fb_off/ww/hh are the module's own accessors. With no init() the quality slot is zero, 23// which clamps to the FINEST setting, so ww/hh report the worst case the adaptive controller can ever 24// reach -- exactly the case that has to fit. Cheap by construction: three accessor calls and no 25// render, so it costs nothing per emit and there is no reason for any caller to skip it. 26// license_tier: ORIGINAL 27import "nx_syscalls.nx" 28import "nx_wasm_vm.nx" 29 30const WF_PROCEED: i64 = 0 31const WF_REFUSE: i64 = 1 32 33// ⚠THIS FORMATTER IS A KNOWN DUPLICATE AND IS NAMED AS ONE. The estate's clean implementation is 34// gv_puts/gv_num in nx_gate_verdict (measured balanced by nx_mmapbal), and both other organs written 35// alongside this one now simply delegate to it. This lib deliberately does NOT, because it is imported 36// by every wasm-page EMITTER and pulling the gate framework into each of them to print digits is a 37// worse trade than one small local copy. So the copy stays, BALANCED via the singleton-getter idiom 38// that nx_mmapbal recognises as an owning allocation. 39// ★★★★★OWED, AND STATED RATHER THAN LEFT SILENT: the estate has several integer formatters 40// (gv_num, gpe_pn, g_pn, wf_num). Converging them needs a leaf-level print lib that carries no gate 41// dependency; that is a campaign, not this edit, and pretending otherwise would be the duplicate-ruler 42// defect with a comment on top. 43const WF_NUMBUF: i64 = 32 44func wf_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 45static WF_NUM_B: i64 46func wf_num_b() -> *u8 { if WF_NUM_B == 0 { WF_NUM_B = sys_mmap(WF_NUMBUF) as i64 } return WF_NUM_B as *u8 } 47static WF_NUM_T: i64 48func wf_num_t() -> *u8 { if WF_NUM_T == 0 { WF_NUM_T = sys_mmap(WF_NUMBUF) as i64 } return WF_NUM_T as *u8 } 49func wf_num(v: i64) -> i64 { 50 let b: *u8 = wf_num_b() 51 var n: i64 = 0 52 var x: i64 = v 53 if x == 0 { b[0] = 48 as u8; n = 1 } else { 54 if x < 0 { wf_puts("-" as *u8); x = 0 - x } 55 let t: *u8 = wf_num_t() 56 var m: i64 = 0 57 while x > 0 { t[m] = (48 + (x % 10)) as u8; x = x / 10; m = m + 1 } 58 while m > 0 { m = m - 1; b[n] = t[m]; n = n + 1 } 59 } 60 sys_write(1, b, n) 61 return 0 62} 63 64// THE CONTRACT IS DELIBERATELY BINARY: WF_PROCEED or WF_REFUSE, because the caller's decision is 65// binary and a three-valued return invites `if wf_guard(...) != 0 { refuse }`, which would refuse 66// every module that simply has no framebuffer to check. ★A RETURN CODE THAT MAKES THE WRONG USAGE THE 67// NATURAL ONE IS A DEFECT IN THE CONTRACT, NOT IN THE CALLER. The distinction between "fits" and 68// "nothing to check" is not lost -- it is PRINTED, named, with the numbers beside it. 69// `who` names the calling emitter so a refusal in a build log says which page was not built. 70func wf_guard(wasm: *u8, wn: i64, who: *u8) -> i64 { 71 let m: *WasmMod = wm_new(wasm, wn) 72 if wm_parse(m) != 0 { 73 wf_puts("WASMFIT-REFUSE [" as *u8); wf_puts(who) 74 wf_puts("]: the wasm does not parse -- no page built\n" as *u8) 75 return WF_REFUSE 76 } 77 let fo: i64 = wm_find_export(m, "fb_off" as *u8) 78 let fw: i64 = wm_find_export(m, "ww" as *u8) 79 let fh: i64 = wm_find_export(m, "hh" as *u8) 80 if fo < 0 { return wf_nosurface(who) } 81 if fw < 0 { return wf_nosurface(who) } 82 if fh < 0 { return wf_nosurface(who) } 83 84 let off: i64 = wm_run(m, "fb_off" as *u8, 0,0,0,0,0, 0) 85 let w: i64 = wm_run(m, "ww" as *u8, 0,0,0,0,0, 0) 86 let h: i64 = wm_run(m, "hh" as *u8, 0,0,0,0,0, 0) 87 let need: i64 = off + w*h*8 88 wf_puts(" wasmfit [" as *u8); wf_puts(who); wf_puts("]: framebuffer " as *u8) 89 wf_num(w); wf_puts("x" as *u8); wf_num(h) 90 wf_puts(" at " as *u8); wf_num(off); wf_puts(" needs " as *u8); wf_num(need) 91 wf_puts(" of " as *u8); wf_num(m.mem_bytes); wf_puts(" declared\n" as *u8) 92 if need > m.mem_bytes { 93 wf_puts("WASMFIT-REFUSE [" as *u8); wf_puts(who) 94 wf_puts("]: the framebuffer does not fit the module's own linear memory -- a browser\n" as *u8) 95 wf_puts("traps with 'index out of bounds' on the first frame and the page renders NOTHING.\n" as *u8) 96 wf_puts("Raise the module's declared memory or lower its render ceiling; no page built.\n" as *u8) 97 return WF_REFUSE 98 } 99 return WF_PROCEED 100} 101 102// A module with no ww/hh/fb_off has no framebuffer, so the fit question does not APPLY to it -- this 103// is "not applicable", not "could not look", and acquitting is correct. It still announces, because a 104// guard that passes in silence is indistinguishable from one that was never called. 105func wf_nosurface(who: *u8) -> i64 { 106 wf_puts(" wasmfit [" as *u8); wf_puts(who) 107 wf_puts("]: module exposes no ww/hh/fb_off surface -- no framebuffer to bound\n" as *u8) 108 return WF_PROCEED 109}