nx_wasm_vm.nx source
↩ module page · 640 lines · 38033 B
1// nx_wasm_vm.nx F618 wasm-SIMD FLIP (2026-07-21, landed from the proven rung-1 twin). Adds interpretation of the
2// 0xFD-prefixed wasm-SIMD subset the nx_wasm_v128 emitter produces (v128.load, i8x16.sub_sat_u,
3// v128.or, i16x8.extadd_pairwise_i8x16_u/_s, i32x4.extadd_pairwise_i16x8_u, i32x4.extract_lane),
4// byte-level-exact per the spec, so the faithdiff-class differential can prove SIMD == scalar == native.
5// v128 VALUES ride the untyped i64 stack as POINTERS into a 4096-slot x 16B ring arena (values are
6// consumed within an op sequence; the SAD kernel holds <=3 live). wm_skip_imm ALSO learns 0xFD --
7// without that the structured-control forward scanners desync on any function containing SIMD.
8// FLIPPED into the shared VM 2026-07-21 (F618); nx_v128_gate T2/T3 + faithdiff hold it GREEN.
9// nx_wasm_vm.nx -- a SOVEREIGN WebAssembly virtual machine: parses a .wasm BINARY and executes its exported functions
10// over a linear memory, pure NishiLang, no third-party runtime (no node/wasmtime/wasmer). Purpose: close the last
11// verification gap for shipped wasm -- run the COMPILED nx_vcodec.wasm offline and prove it computes bit-exact to the
12// gate-proven NATIVE codec (a functional gate on the actual shipped bytes, which most toolchains never do; they trust
13// the compiler). This is R0+R1: the parser (sections -> module) + a stack-machine executor for the opcode subset our
14// nx_wat_compiler emits (i32/i64 const/arith/shift/compare, local.get/set/tee, i64/i32 load/store(+8/16), call,
15// block/loop/if/else/end/br/br_if/br_table/return/drop/select, memory.size/grow, wrap/extend). license_tier: ORIGINAL
16import "nx_syscalls.nx"
17import "nx_f32_hw.nx" // f32 opcodes execute on the SAME SSE bit-pattern ops the native build uses
18const K_MAGIC_65536: i64 = 65536
19const K_MAGIC_1024: i64 = 1024
20const K_MAGIC_2048: i64 = 2048
21const K_MAGIC_262144: i64 = 262144
22const K_MAGIC_4096: i64 = 4096
23const K_MAGIC_131072: i64 = 131072
24const K_MAGIC_2654435761: i64 = 2654435761
25const K_MAGIC_4000000: i64 = 4000000
26const K_MAGIC_32768: i64 = 32768
27const K_MAGIC_2147483648: i64 = 2147483648
28const K_MAGIC_4294967296: i64 = 4294967296
29const K_MAGIC_4090: i64 = 4090
30const K_MAGIC_65530: i64 = 65530
31const K_MAGIC_262140: i64 = 262140
32const K_MAGIC_999999: i64 = 999999
33
34// F618 v128 slot arena (module-level FLAG/POINTER statics live at the TOP, before any reader -- the
35// fwd-static rule). Scalar statics are the safe pattern; lazy mmap init on first SIMD op.
36static g_v128_arena: *u8
37static g_v128_idx: i64
38
39// ---------------- module representation ----------------
40struct WasmMod {
41 bytes: *u8, // the whole .wasm image
42 len: i64,
43 n_types: i64,
44 type_nparam: *i64, // params per type index
45 type_nres: *i64, // results per type index
46 n_imports: i64, // number of imported functions (func index space starts after these)
47 n_funcs: i64, // number of DEFINED functions
48 func_type: *i64, // type index per defined function
49 func_code: *i64, // byte offset of the first instruction (after the locals declaration)
50 func_end: *i64, // byte offset just past the function body
51 func_nloc: *i64, // total locals INCLUDING params (slots the executor must allocate)
52 mem: *u8, // linear memory
53 mem_bytes: i64,
54 n_exports: i64,
55 exp_name_off: *i64, // byte offset of each export name in bytes
56 exp_name_len: *i64,
57 exp_kind: *i64, // 0=func
58 exp_index: *i64, // func index for func exports
59 vstack: *i64, // shared operand-stack pool
60 vsp: i64, // operand stack pointer
61 locals: *i64, // shared locals pool (bump-allocated per call frame)
62 lsp: i64, // locals pointer
63 ctrl_kind: *i64, // control stack: 0=block,1=loop
64 ctrl_pc: *i64, // control target pc (end for block, body-start for loop)
65 csp: i64, // control stack pointer
66 memo_k: *i64, // match_end/match_else MEMO keys (startpos*2+kind; 0=empty) -- the dispatch-machine
67 memo_v: *i64, // lowering re-enters the same blocks millions of times; without this a full-game
68 // render vet forward-scans kilobytes per entry (added 2026-07-02, ~100x speedup)
69}
70
71// ---------------- byte readers ----------------
72func wv_u8(b: *u8, pos: *i64) -> i64 { let p: i64 = pos[0]; pos[0] = p + 1; return b[p] as i64 }
73func wv_uleb(b: *u8, pos: *i64) -> i64 {
74 var result: i64 = 0; var shift: i64 = 0; var p: i64 = pos[0]
75 while 1 == 1 {
76 let byte: i64 = b[p] as i64; p = p + 1
77 result = result | ((byte & 0x7F) << shift)
78 if (byte & 0x80) == 0 { pos[0] = p; return result }
79 shift = shift + 7
80 }
81 return 0
82}
83func wv_sleb(b: *u8, pos: *i64) -> i64 {
84 var result: i64 = 0; var shift: i64 = 0; var p: i64 = pos[0]
85 while 1 == 1 {
86 let byte: i64 = b[p] as i64; p = p + 1
87 result = result | ((byte & 0x7F) << shift); shift = shift + 7
88 if (byte & 0x80) == 0 {
89 if shift < 64 { if (byte & 0x40) != 0 { result = result | ((0 - 1) << shift) } }
90 pos[0] = p; return result
91 }
92 }
93 return 0
94}
95
96// ---------------- parser ----------------
97// Parse the whole module into mod (arrays pre-mmap'd by the caller / wm_new). Returns 0 on success, negative on error.
98func wm_parse(mod: *WasmMod) -> i64 {
99 let b: *u8 = mod.bytes
100 let n: i64 = mod.len
101 let pos: *i64 = sys_mmap(8) as *i64
102 pos[0] = 0
103 // magic + version
104 if b[0] != (0 as u8) { return 0 - 1 }
105 if b[1] != (0x61 as u8) { return 0 - 1 }
106 if b[2] != (0x73 as u8) { return 0 - 1 }
107 if b[3] != (0x6d as u8) { return 0 - 1 }
108 pos[0] = 8
109 mod.n_types = 0; mod.n_imports = 0; mod.n_funcs = 0; mod.n_exports = 0; mod.mem_bytes = 0
110 var fcount: i64 = 0 // running count of DEFINED functions seen in the function section
111 while pos[0] < n {
112 let sid: i64 = wv_u8(b, pos)
113 let ssize: i64 = wv_uleb(b, pos)
114 let send: i64 = pos[0] + ssize
115 if sid == 1 {
116 // TYPE section
117 let ct: i64 = wv_uleb(b, pos)
118 mod.n_types = ct
119 var i: i64 = 0
120 while i < ct {
121 let form: i64 = wv_u8(b, pos) // 0x60 func
122 let np: i64 = wv_uleb(b, pos)
123 var k: i64 = 0; while k < np { wv_u8(b, pos); k = k + 1 }
124 let nr: i64 = wv_uleb(b, pos)
125 var k2: i64 = 0; while k2 < nr { wv_u8(b, pos); k2 = k2 + 1 }
126 mod.type_nparam[i] = np
127 mod.type_nres[i] = nr
128 i = i + 1
129 }
130 } else { if sid == 2 {
131 // IMPORT section -- count function imports (they occupy the low func-index range)
132 let ci: i64 = wv_uleb(b, pos)
133 var i: i64 = 0
134 while i < ci {
135 let ml: i64 = wv_uleb(b, pos); var k: i64 = 0; while k < ml { wv_u8(b, pos); k = k + 1 }
136 let fl: i64 = wv_uleb(b, pos); var k2: i64 = 0; while k2 < fl { wv_u8(b, pos); k2 = k2 + 1 }
137 let kind: i64 = wv_u8(b, pos)
138 if kind == 0 { wv_uleb(b, pos); mod.n_imports = mod.n_imports + 1 }
139 else { if kind == 1 { wv_u8(b, pos); wv_u8(b, pos); let fl2: i64 = wv_uleb(b, pos); if fl2 != 0 { wv_uleb(b, pos) } }
140 else { if kind == 2 { let fl3: i64 = wv_uleb(b, pos); wv_uleb(b, pos); if fl3 != 0 { wv_uleb(b, pos) } }
141 else { wv_u8(b, pos); wv_uleb(b, pos) } } }
142 i = i + 1
143 }
144 } else { if sid == 3 {
145 // FUNCTION section -- type index per defined function
146 let cf: i64 = wv_uleb(b, pos)
147 mod.n_funcs = cf
148 var i: i64 = 0
149 while i < cf { mod.func_type[i] = wv_uleb(b, pos); i = i + 1 }
150 } else { if sid == 5 {
151 // MEMORY section -- first memory's minimum size (pages of 64 KiB)
152 let cm: i64 = wv_uleb(b, pos)
153 if cm > 0 {
154 let flags: i64 = wv_u8(b, pos)
155 let minp: i64 = wv_uleb(b, pos)
156 if (flags & 1) != 0 { wv_uleb(b, pos) }
157 mod.mem_bytes = minp * K_MAGIC_65536
158 // ALLOCATE the linear memory (found 2026-07-02: mem stayed the wm_new NULL -> the FIRST
159 // load/store in any standalone module segfaulted at the raw address, sailing past the
160 // bounds guards whose mem_bytes was correctly set)
161 mod.mem = sys_mmap(mod.mem_bytes)
162 var j: i64 = 1
163 while j < cm { let f: i64 = wv_u8(b, pos); wv_uleb(b, pos); if (f & 1) != 0 { wv_uleb(b, pos) } j = j + 1 }
164 }
165 } else { if sid == 7 {
166 // EXPORT section
167 let ce: i64 = wv_uleb(b, pos)
168 mod.n_exports = ce
169 var i: i64 = 0
170 while i < ce {
171 let nl: i64 = wv_uleb(b, pos)
172 mod.exp_name_off[i] = pos[0]
173 mod.exp_name_len[i] = nl
174 var k: i64 = 0; while k < nl { wv_u8(b, pos); k = k + 1 }
175 mod.exp_kind[i] = wv_u8(b, pos)
176 mod.exp_index[i] = wv_uleb(b, pos)
177 i = i + 1
178 }
179 } else { if sid == 10 {
180 // CODE section -- per defined function: locals decl then the instruction body
181 let cc: i64 = wv_uleb(b, pos)
182 var i: i64 = 0
183 while i < cc {
184 let bodysize: i64 = wv_uleb(b, pos)
185 let bodystart: i64 = pos[0]
186 let bodyend: i64 = bodystart + bodysize
187 // locals declaration
188 let nld: i64 = wv_uleb(b, pos)
189 var nloc: i64 = 0
190 var d: i64 = 0
191 while d < nld { let cnt: i64 = wv_uleb(b, pos); wv_u8(b, pos); nloc = nloc + cnt; d = d + 1 }
192 let tyidx: i64 = mod.func_type[i]
193 mod.func_nloc[i] = mod.type_nparam[tyidx] + nloc
194 mod.func_code[i] = pos[0]
195 mod.func_end[i] = bodyend
196 pos[0] = bodyend
197 i = i + 1
198 }
199 fcount = cc
200 } else {
201 // skip any other section
202 } } } } } }
203 pos[0] = send
204 }
205 if fcount == 0 { fcount = mod.n_funcs }
206 return 0
207}
208
209// compare an export name (in the module bytes) to a C-string needle; 1 if equal.
210func wm_name_eq(b: *u8, off: i64, len: i64, needle: *u8) -> i64 {
211 var i: i64 = 0
212 while i < len { if b[off + i] != needle[i] { return 0 } i = i + 1 }
213 if needle[len] != (0 as u8) { return 0 } // needle must end exactly
214 return 1
215}
216// find an exported function's GLOBAL function index by name, or -1.
217func wm_find_export(mod: *WasmMod, needle: *u8) -> i64 {
218 var i: i64 = 0
219 while i < mod.n_exports {
220 if mod.exp_kind[i] == 0 {
221 if wm_name_eq(mod.bytes, mod.exp_name_off[i], mod.exp_name_len[i], needle) == 1 { return mod.exp_index[i] }
222 }
223 i = i + 1
224 }
225 return 0 - 1
226}
227// allocate a module + its arrays around a loaded .wasm image.
228func wm_new(bytes: *u8, len: i64) -> *WasmMod {
229 let mod: *WasmMod = sys_mmap(256) as *WasmMod
230 mod.bytes = bytes; mod.len = len
231 mod.type_nparam = sys_mmap(K_MAGIC_1024*8) as *i64
232 mod.type_nres = sys_mmap(K_MAGIC_1024*8) as *i64
233 mod.func_type = sys_mmap(K_MAGIC_2048*8) as *i64
234 mod.func_code = sys_mmap(K_MAGIC_2048*8) as *i64
235 mod.func_end = sys_mmap(K_MAGIC_2048*8) as *i64
236 mod.func_nloc = sys_mmap(K_MAGIC_2048*8) as *i64
237 mod.exp_name_off = sys_mmap(K_MAGIC_1024*8) as *i64
238 mod.exp_name_len = sys_mmap(K_MAGIC_1024*8) as *i64
239 mod.exp_kind = sys_mmap(K_MAGIC_1024*8) as *i64
240 mod.exp_index = sys_mmap(K_MAGIC_1024*8) as *i64
241 mod.mem = 0 as *u8
242 mod.vstack = sys_mmap(K_MAGIC_65536*8) as *i64
243 mod.locals = sys_mmap(K_MAGIC_262144*8) as *i64
244 mod.ctrl_kind = sys_mmap(K_MAGIC_4096*8) as *i64
245 mod.ctrl_pc = sys_mmap(K_MAGIC_4096*8) as *i64
246 mod.memo_k = sys_mmap(K_MAGIC_131072*8) as *i64
247 mod.memo_v = sys_mmap(K_MAGIC_131072*8) as *i64
248 mod.vsp = 0; mod.lsp = 0; mod.csp = 0
249 return mod
250}
251// scan-memo: open-address hash keyed by startpos*2+kind (key 0 = empty slot; code offsets are always > 0)
252func wm_memo_get(mod: *WasmMod, key: i64) -> i64 {
253 var i: i64 = (key * K_MAGIC_2654435761) % K_MAGIC_131072
254 if i < 0 { i = i + K_MAGIC_131072 }
255 var probes: i64 = 0
256 while probes < K_MAGIC_131072 {
257 if mod.memo_k[i] == key { return mod.memo_v[i] }
258 if mod.memo_k[i] == 0 { return 0 }
259 i = i + 1
260 if i >= K_MAGIC_131072 { i = 0 }
261 probes = probes + 1
262 }
263 return 0
264}
265func wm_memo_put(mod: *WasmMod, key: i64, val: i64) -> i64 {
266 var i: i64 = (key * K_MAGIC_2654435761) % K_MAGIC_131072
267 if i < 0 { i = i + K_MAGIC_131072 }
268 var probes: i64 = 0
269 while probes < K_MAGIC_131072 {
270 if mod.memo_k[i] == 0 { mod.memo_k[i] = key; mod.memo_v[i] = val; return 0 }
271 if mod.memo_k[i] == key { mod.memo_v[i] = val; return 0 }
272 i = i + 1
273 if i >= K_MAGIC_131072 { i = 0 }
274 probes = probes + 1
275 }
276 return 0 - 1
277}
278
279// ---------------- executor ----------------
280// faithful little-endian 8-byte memory access (exactly what i64.load/i64.store do in the shipped wasm).
281func wm_ld64(m: *u8, a: i64) -> i64 { var v: i64=0; var i: i64=0; while i<8 { v = v | ((m[a+i] as i64) << (i*8)); i=i+1 } return v }
282func wm_st64(m: *u8, a: i64, v: i64) -> i64 { var i: i64=0; while i<8 { m[a+i] = ((v >> (i*8)) & 0xFF) as u8; i=i+1 } return 0 }
283
284// advance past an opcode's immediate operands (for the structured-control forward scan). pc points just AFTER the op byte.
285func wm_skip_imm(b: *u8, op: i64, pos: *i64) -> i64 {
286 if op == 0x02 { wv_u8(b, pos); return 0 } // block: blocktype byte
287 if op == 0x03 { wv_u8(b, pos); return 0 } // loop: blocktype byte
288 if op == 0x04 { wv_u8(b, pos); return 0 } // if: blocktype byte
289 if op == 0x0C { wv_uleb(b, pos); return 0 } // br
290 if op == 0x0D { wv_uleb(b, pos); return 0 } // br_if
291 if op == 0x0E { let c: i64 = wv_uleb(b, pos); var i: i64=0; while i<=c { wv_uleb(b, pos); i=i+1 } return 0 } // br_table
292 if op == 0x10 { wv_uleb(b, pos); return 0 } // call
293 if op == 0x20 { wv_uleb(b, pos); return 0 } // local.get
294 if op == 0x21 { wv_uleb(b, pos); return 0 } // local.set
295 if op == 0x22 { wv_uleb(b, pos); return 0 } // local.tee
296 if op == 0x41 { wv_sleb(b, pos); return 0 } // i32.const
297 if op == 0x42 { wv_sleb(b, pos); return 0 } // i64.const
298 if op >= 0x28 { if op <= 0x3E { wv_uleb(b, pos); wv_uleb(b, pos); return 0 } } // load/store memarg (align, offset)
299 if op == 0xFD { // F618 SIMD prefix: uleb sub-opcode + per-sub immediates
300 let fsub: i64 = wv_uleb(b, pos)
301 if fsub == 0 { wv_uleb(b, pos); wv_uleb(b, pos); return 0 } // v128.load memarg
302 if fsub == 11 { wv_uleb(b, pos); wv_uleb(b, pos); return 0 } // v128.store memarg
303 if fsub == 27 { wv_u8(b, pos); return 0 } // i32x4.extract_lane laneidx
304 return 0 // sub_sat_u/or/extadds: no immediate
305 }
306 return 0 // all other ops: no immediate
307}
308// find the pc just past the `end` that matches the block/loop/if opened at *pos (pos points after the opener's blocktype).
309func wm_match_end(b: *u8, startpos: i64) -> i64 {
310 let pos: *i64 = sys_mmap(8) as *i64; pos[0] = startpos
311 var depth: i64 = 1
312 var steps: i64 = 0
313 while depth > 0 {
314 // runaway guard: a scanner that never closes = an opcode whose immediates wm_skip_imm doesn't know
315 // (desync). Fail LOUD with the last opcode instead of walking off the mapping (was a silent SIGSEGV).
316 steps = steps + 1
317 if steps > K_MAGIC_4000000 { sys_write(2, "SCAN-RUNAWAY match_end\n" as *u8, 23); sys_exit(9) }
318 let op: i64 = wv_u8(b, pos)
319 if op == 0x02 { depth = depth + 1 } else {
320 if op == 0x03 { depth = depth + 1 } else {
321 if op == 0x04 { depth = depth + 1 } else {
322 if op == 0x0B { depth = depth - 1 } else {
323 wm_skip_imm(b, op, pos)
324 } } } }
325 if op == 0x02 { wv_u8(b, pos) } // also skip the opener blocktype we counted
326 if op == 0x03 { wv_u8(b, pos) }
327 if op == 0x04 { wv_u8(b, pos) }
328 }
329 let rme: i64 = pos[0]; sys_munmap(pos as *u8, 8); return rme // free the scan cursor (was a per-open leak)
330}
331
332// find where execution goes when an `if` condition is FALSE: the position after the matching `else` opcode, or --
333// if there is no else -- the position after the matching `end` (i.e., skip the whole construct). startpos is just
334// after the if's blocktype byte.
335func wm_match_else(b: *u8, startpos: i64) -> i64 {
336 let pos: *i64 = sys_mmap(8) as *i64; pos[0] = startpos
337 var depth: i64 = 1
338 var steps: i64 = 0
339 while depth > 0 {
340 steps = steps + 1
341 if steps > K_MAGIC_4000000 { sys_write(2, "SCAN-RUNAWAY match_else\n" as *u8, 24); sys_exit(9) }
342 let op: i64 = wv_u8(b, pos)
343 if op == 0x02 { depth = depth + 1; wv_u8(b, pos) } else {
344 if op == 0x03 { depth = depth + 1; wv_u8(b, pos) } else {
345 if op == 0x04 { depth = depth + 1; wv_u8(b, pos) } else {
346 if op == 0x05 { if depth == 1 { let r1: i64 = pos[0]; sys_munmap(pos as *u8, 8); return r1 } } else {
347 if op == 0x0B { depth = depth - 1 } else {
348 wm_skip_imm(b, op, pos)
349 } } } } }
350 }
351 let r2: i64 = pos[0]; sys_munmap(pos as *u8, 8); return r2 // free the scan cursor (was a per-if leak)
352}
353// perform a branch to label depth `lbl` (0 = innermost): loop re-enters at its body start (keep its frame),
354// block/if exit to past their end (drop their frame). Sets pos[0] and the control stack pointer.
355func wm_do_br(mod: *WasmMod, pos: *i64, lbl: i64) -> i64 {
356 let t: i64 = mod.csp - 1 - lbl
357 pos[0] = mod.ctrl_pc[t]
358 if mod.ctrl_kind[t] == 1 { mod.csp = t + 1 } else { mod.csp = t }
359 return 0
360}
361// call defined function fidx with nargs i64 args in args[]; returns the i64 result (0 if void). Faithful wasm exec.
362// FLAT dispatch (one `if op == X` per opcode -- this codebase's idiom; avoids deep if/else brace fragility).
363// --- fail-fast diagnostic helpers: a faithful VM should never trip these; firing => real corruption ---
364func wm_phexf(v: i64, fd: i64) -> i64 {
365 let d: *u8 = "0123456789abcdef" as *u8
366 let h: *u8 = sys_mmap(2)
367 h[0] = d[(v >> 4) & 0xF]; h[1] = d[v & 0xF]
368 sys_write(fd, h, 2); return 0
369}
370func wm_pn2f(v: i64, fd: i64) -> i64 {
371 let b: *u8 = sys_mmap(28); var x: i64 = v
372 if x < 0 { sys_write(fd, "-" as *u8, 1); x = 0 - x }
373 if x == 0 { sys_write(fd, "0" as *u8, 1); return 0 }
374 var d: i64 = 0; var y: i64 = x
375 while y > 0 { d = d + 1; y = y / 10 }
376 var i: i64 = d - 1; y = x
377 while i >= 0 { b[i] = (48 + (y % 10)) as u8; y = y / 10; i = i - 1 }
378 sys_write(fd, b, d); return 0
379}
380func wm_pn2(v: i64) -> i64 { return wm_pn2f(v, 2) }
381func wm_phex(v: i64) -> i64 { return wm_phexf(v, 2) }
382func wm_trap1(code: i64, op: i64, a: i64, bb: i64, fd: i64) -> i64 {
383 sys_write(fd, "VM-TRAP code=" as *u8, 13); wm_pn2f(code, fd)
384 sys_write(fd, " op=0x" as *u8, 6); wm_phexf(op, fd)
385 sys_write(fd, " a=" as *u8, 3); wm_pn2f(a, fd)
386 sys_write(fd, " b=" as *u8, 3); wm_pn2f(bb, fd)
387 sys_write(fd, "\n" as *u8, 1)
388 return 0
389}
390func wm_trap(code: i64, op: i64, a: i64, bb: i64) -> i64 {
391 // BOTH streams: stderr capture gets eaten by some harness layers (learned 2026-07-02) -- stdout survives
392 wm_trap1(code, op, a, bb, 1)
393 wm_trap1(code, op, a, bb, 2)
394 sys_exit(8); return 0
395}
396func wm_call(mod: *WasmMod, fidx: i64, args: *i64, nargs: i64) -> i64 {
397 let b: *u8 = mod.bytes
398 let di: i64 = fidx - mod.n_imports
399 let nloc: i64 = mod.func_nloc[di]
400 let lbase: i64 = mod.lsp
401 mod.lsp = mod.lsp + nloc
402 let L: *i64 = mod.locals
403 var i: i64 = 0
404 while i < nloc { if i < nargs { L[lbase+i] = args[i] } else { L[lbase+i] = 0 } i = i + 1 }
405 let vbase: i64 = mod.vsp
406 let cbase: i64 = mod.csp
407 let V: *i64 = mod.vstack
408 let m: *u8 = mod.mem
409 let pos: *i64 = sys_mmap(8) as *i64
410 pos[0] = mod.func_code[di]
411 let cend: i64 = mod.func_end[di]
412 var retval: i64 = 0
413 var running: i64 = 1
414 while running == 1 {
415 if pos[0] >= cend { running = 0 }
416 if running == 1 {
417 let op: i64 = wv_u8(b, pos)
418 // control flow
419 if op == 0x0B { if mod.csp <= cbase { running = 0 } else { mod.csp = mod.csp - 1 } }
420 if op == 0x02 {
421 wv_u8(b, pos)
422 var e02: i64 = wm_memo_get(mod, pos[0] * 2)
423 if e02 == 0 { e02 = wm_match_end(b, pos[0]); wm_memo_put(mod, pos[0] * 2, e02) }
424 mod.ctrl_kind[mod.csp] = 0; mod.ctrl_pc[mod.csp] = e02; mod.csp = mod.csp + 1
425 }
426 if op == 0x03 { wv_u8(b, pos); mod.ctrl_kind[mod.csp] = 1; mod.ctrl_pc[mod.csp] = pos[0]; mod.csp = mod.csp + 1 }
427 if op == 0x04 {
428 wv_u8(b, pos)
429 var endp: i64 = wm_memo_get(mod, pos[0] * 2)
430 if endp == 0 { endp = wm_match_end(b, pos[0]); wm_memo_put(mod, pos[0] * 2, endp) }
431 var elsep: i64 = wm_memo_get(mod, pos[0] * 2 + 1)
432 if elsep == 0 { elsep = wm_match_else(b, pos[0]); wm_memo_put(mod, pos[0] * 2 + 1, elsep) }
433 mod.vsp = mod.vsp - 1; let cond: i64 = V[mod.vsp]
434 if cond != 0 { mod.ctrl_kind[mod.csp] = 0; mod.ctrl_pc[mod.csp] = endp; mod.csp = mod.csp + 1 }
435 if cond == 0 {
436 if elsep < endp { mod.ctrl_kind[mod.csp] = 0; mod.ctrl_pc[mod.csp] = endp; mod.csp = mod.csp + 1; pos[0] = elsep }
437 if elsep >= endp { pos[0] = endp }
438 }
439 }
440 if op == 0x05 { mod.csp = mod.csp - 1; pos[0] = mod.ctrl_pc[mod.csp] }
441 if op == 0x0C { let lbl: i64 = wv_uleb(b, pos); wm_do_br(mod, pos, lbl) }
442 if op == 0x0D { let lbl: i64 = wv_uleb(b, pos); mod.vsp = mod.vsp - 1; if V[mod.vsp] != 0 { wm_do_br(mod, pos, lbl) } }
443 if op == 0x0E {
444 let cnt: i64 = wv_uleb(b, pos)
445 mod.vsp = mod.vsp - 1; var idx: i64 = V[mod.vsp]
446 if idx < 0 { idx = cnt }
447 if idx > cnt { idx = cnt }
448 var lbl: i64 = 0; var k: i64 = 0
449 while k <= cnt { let l: i64 = wv_uleb(b, pos); if k == idx { lbl = l } k = k + 1 }
450 wm_do_br(mod, pos, lbl)
451 }
452 if op == 0x0F { if mod.vsp > vbase { retval = V[mod.vsp - 1] } running = 0 }
453 if op == 0x10 {
454 let cf: i64 = wv_uleb(b, pos)
455 let cdi: i64 = cf - mod.n_imports
456 let cnp: i64 = mod.type_nparam[mod.func_type[cdi]]
457 mod.vsp = mod.vsp - cnp
458 let r: i64 = wm_call(mod, cf, ((mod.vstack as i64) + mod.vsp*8) as *i64, cnp)
459 if mod.type_nres[mod.func_type[cdi]] > 0 { V[mod.vsp] = r; mod.vsp = mod.vsp + 1 }
460 }
461 // values / locals
462 if op == 0x20 { let x: i64 = wv_uleb(b, pos); V[mod.vsp] = L[lbase + x]; mod.vsp = mod.vsp + 1 }
463 if op == 0x21 { let x: i64 = wv_uleb(b, pos); mod.vsp = mod.vsp - 1; L[lbase + x] = V[mod.vsp] }
464 if op == 0x22 { let x: i64 = wv_uleb(b, pos); L[lbase + x] = V[mod.vsp - 1] }
465 if op == 0x41 { V[mod.vsp] = wv_sleb(b, pos); mod.vsp = mod.vsp + 1 }
466 if op == 0x42 { V[mod.vsp] = wv_sleb(b, pos); mod.vsp = mod.vsp + 1 }
467 if op == 0x1A { mod.vsp = mod.vsp - 1 }
468 // memory (faithful 8-byte, exactly as the wat specifies)
469 if op == 0x29 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); let a29: i64 = V[mod.vsp-1] + o2; if a29 < 0 { wm_trap(6, op, a29, 0) } if a29 + 8 > mod.mem_bytes { wm_trap(6, op, a29, mod.mem_bytes) } V[mod.vsp-1] = wm_ld64(m, a29) }
470 if op == 0x28 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); V[mod.vsp-1] = wm_ld64(m, V[mod.vsp-1] + o2) & 0xFFFFFFFF }
471 if op == 0x37 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); mod.vsp = mod.vsp - 1; let v: i64 = V[mod.vsp]; mod.vsp = mod.vsp - 1; let a37: i64 = V[mod.vsp] + o2; if a37 < 0 { wm_trap(7, op, a37, 0) } if a37 + 8 > mod.mem_bytes { wm_trap(7, op, a37, mod.mem_bytes) } wm_st64(m, a37, v) }
472 if op == 0x36 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); mod.vsp = mod.vsp - 1; let v: i64 = V[mod.vsp]; mod.vsp = mod.vsp - 1; wm_st64(m, V[mod.vsp] + o2, v) }
473 // byte-width memory (the fixed backend now emits these for u8 arrays)
474 if op == 0x31 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); let a31: i64 = V[mod.vsp-1] + o2; if a31 < 0 { wm_trap(6, op, a31, 0) } if a31 >= mod.mem_bytes { wm_trap(6, op, a31, mod.mem_bytes) } V[mod.vsp-1] = m[a31] as i64 }
475 if op == 0x3C { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); mod.vsp = mod.vsp - 1; let v: i64 = V[mod.vsp]; mod.vsp = mod.vsp - 1; let a3c: i64 = V[mod.vsp] + o2; if a3c < 0 { wm_trap(7, op, a3c, 0) } if a3c >= mod.mem_bytes { wm_trap(7, op, a3c, mod.mem_bytes) } m[a3c] = (v & 0xFF) as u8 }
476 // full subword-memory family (2026-07-10 sext debt fix): signed loads sign-extend via
477 // arithmetic (the VM's own *u8 reads zero-extend by language semantics -- unchanged);
478 // 16/32-bit widths were previously NOT implemented at all (backend could emit -> VM had no op).
479 if op == 0x30 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); let a30: i64 = V[mod.vsp-1] + o2; if a30 < 0 { wm_trap(6, op, a30, 0) } if a30 >= mod.mem_bytes { wm_trap(6, op, a30, mod.mem_bytes) } var v30: i64 = m[a30] as i64; if v30 >= 128 { v30 = v30 - 256 } V[mod.vsp-1] = v30 }
480 if op == 0x33 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); let a33: i64 = V[mod.vsp-1] + o2; if a33 < 0 { wm_trap(6, op, a33, 0) } if a33 + 2 > mod.mem_bytes { wm_trap(6, op, a33, mod.mem_bytes) } V[mod.vsp-1] = (m[a33] as i64) | ((m[a33+1] as i64) << 8) }
481 if op == 0x32 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); let a32: i64 = V[mod.vsp-1] + o2; if a32 < 0 { wm_trap(6, op, a32, 0) } if a32 + 2 > mod.mem_bytes { wm_trap(6, op, a32, mod.mem_bytes) } var v32: i64 = (m[a32] as i64) | ((m[a32+1] as i64) << 8); if v32 >= K_MAGIC_32768 { v32 = v32 - K_MAGIC_65536 } V[mod.vsp-1] = v32 }
482 if op == 0x35 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); let a35: i64 = V[mod.vsp-1] + o2; if a35 < 0 { wm_trap(6, op, a35, 0) } if a35 + 4 > mod.mem_bytes { wm_trap(6, op, a35, mod.mem_bytes) } V[mod.vsp-1] = (m[a35] as i64) | ((m[a35+1] as i64) << 8) | ((m[a35+2] as i64) << 16) | ((m[a35+3] as i64) << 24) }
483 if op == 0x34 { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); let a34: i64 = V[mod.vsp-1] + o2; if a34 < 0 { wm_trap(6, op, a34, 0) } if a34 + 4 > mod.mem_bytes { wm_trap(6, op, a34, mod.mem_bytes) } var v34: i64 = (m[a34] as i64) | ((m[a34+1] as i64) << 8) | ((m[a34+2] as i64) << 16) | ((m[a34+3] as i64) << 24); if v34 >= K_MAGIC_2147483648 { v34 = v34 - K_MAGIC_4294967296 } V[mod.vsp-1] = v34 }
484 if op == 0x3D { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); mod.vsp = mod.vsp - 1; let v3d: i64 = V[mod.vsp]; mod.vsp = mod.vsp - 1; let a3d: i64 = V[mod.vsp] + o2; if a3d < 0 { wm_trap(7, op, a3d, 0) } if a3d + 2 > mod.mem_bytes { wm_trap(7, op, a3d, mod.mem_bytes) } m[a3d] = (v3d & 0xFF) as u8; m[a3d+1] = ((v3d >> 8) & 0xFF) as u8 }
485 if op == 0x3E { wv_uleb(b, pos); let o2: i64 = wv_uleb(b, pos); mod.vsp = mod.vsp - 1; let v3e: i64 = V[mod.vsp]; mod.vsp = mod.vsp - 1; let a3e: i64 = V[mod.vsp] + o2; if a3e < 0 { wm_trap(7, op, a3e, 0) } if a3e + 4 > mod.mem_bytes { wm_trap(7, op, a3e, mod.mem_bytes) } m[a3e] = (v3e & 0xFF) as u8; m[a3e+1] = ((v3e >> 8) & 0xFF) as u8; m[a3e+2] = ((v3e >> 16) & 0xFF) as u8; m[a3e+3] = ((v3e >> 24) & 0xFF) as u8 }
486 // conversions
487 if op == 0xA7 { V[mod.vsp-1] = V[mod.vsp-1] & 0xFFFFFFFF }
488 if op == 0xAD { V[mod.vsp-1] = V[mod.vsp-1] & 0xFFFFFFFF }
489 // f32 (added 2026-07-02 for the mineworld render vet): values are f32 BIT PATTERNS in the low 32
490 // bits of the untyped i64 slots -- exactly nx_f32_hw's convention, so each op IS the native SSE op.
491 if op == 0xB4 { V[mod.vsp-1] = f32_of(V[mod.vsp-1]) } // f32.convert_i64_s
492 if op == 0xAE { V[mod.vsp-1] = f32_int(V[mod.vsp-1]) } // i64.trunc_f32_s
493 if op == 0xBE { V[mod.vsp-1] = V[mod.vsp-1] & 0xFFFFFFFF } // f32.reinterpret_i32
494 if op == 0xBC { V[mod.vsp-1] = V[mod.vsp-1] & 0xFFFFFFFF } // i32.reinterpret_f32
495 if op == 0x92 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = f32_add(V[mod.vsp-1], V[mod.vsp]) } // f32.add
496 if op == 0x94 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = f32_mul(V[mod.vsp-1], V[mod.vsp]) } // f32.mul
497 if op == 0x95 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = f32_div(V[mod.vsp-1], V[mod.vsp]) } // f32.div
498 // i64 arithmetic
499 if op == 0x7C { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] + V[mod.vsp] }
500 if op == 0x7D { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] - V[mod.vsp] }
501 if op == 0x7E { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] * V[mod.vsp] }
502 if op == 0x7F { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] / V[mod.vsp] }
503 if op == 0x81 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] % V[mod.vsp] }
504 if op == 0x83 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] & V[mod.vsp] }
505 if op == 0x84 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] | V[mod.vsp] }
506 if op == 0x85 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] ^ V[mod.vsp] }
507 if op == 0x86 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] << V[mod.vsp] }
508 if op == 0x87 { mod.vsp=mod.vsp-1; V[mod.vsp-1] = V[mod.vsp-1] >> V[mod.vsp] }
509 // i64 compares (push 1/0)
510 if op == 0x51 { mod.vsp=mod.vsp-1; if V[mod.vsp-1]==V[mod.vsp] { V[mod.vsp-1]=1 } else { V[mod.vsp-1]=0 } }
511 if op == 0x52 { mod.vsp=mod.vsp-1; if V[mod.vsp-1]!=V[mod.vsp] { V[mod.vsp-1]=1 } else { V[mod.vsp-1]=0 } }
512 if op == 0x53 { mod.vsp=mod.vsp-1; if V[mod.vsp-1]<V[mod.vsp] { V[mod.vsp-1]=1 } else { V[mod.vsp-1]=0 } }
513 if op == 0x55 { mod.vsp=mod.vsp-1; if V[mod.vsp-1]>V[mod.vsp] { V[mod.vsp-1]=1 } else { V[mod.vsp-1]=0 } }
514 if op == 0x57 { mod.vsp=mod.vsp-1; if V[mod.vsp-1]<=V[mod.vsp] { V[mod.vsp-1]=1 } else { V[mod.vsp-1]=0 } }
515 if op == 0x59 { mod.vsp=mod.vsp-1; if V[mod.vsp-1]>=V[mod.vsp] { V[mod.vsp-1]=1 } else { V[mod.vsp-1]=0 } }
516 if op == 0x50 { if V[mod.vsp-1]==0 { V[mod.vsp-1]=1 } else { V[mod.vsp-1]=0 } }
517 // --- F618 wasm-SIMD subset (0xFD prefix). v128 values = pointers into the 16B-slot ring arena. ---
518 if op == 0xFD {
519 if (g_v128_arena as i64) == 0 { g_v128_arena = sys_mmap(K_MAGIC_65536) }
520 let fxsub: i64 = wv_uleb(b, pos)
521 if fxsub == 0 { // v128.load memarg
522 wv_uleb(b, pos)
523 let fxo: i64 = wv_uleb(b, pos)
524 let fxa: i64 = V[mod.vsp-1] + fxo
525 if fxa < 0 { wm_trap(6, 0xFD, fxa, 0) }
526 if fxa + 16 > mod.mem_bytes { wm_trap(6, 0xFD, fxa, mod.mem_bytes) }
527 let fxsl: i64 = (g_v128_arena as i64) + (g_v128_idx % K_MAGIC_4096) * 16
528 g_v128_idx = g_v128_idx + 1
529 let fxsp: *u8 = fxsl as *u8
530 var fxk: i64 = 0
531 while fxk < 16 { fxsp[fxk] = m[fxa + fxk]; fxk = fxk + 1 }
532 V[mod.vsp-1] = fxsl
533 }
534 if fxsub == 0x73 { // i8x16.sub_sat_u: pop b, a -> per-byte max(a-b, 0)
535 mod.vsp = mod.vsp - 1
536 let fxpb: *u8 = V[mod.vsp] as *u8
537 let fxpa: *u8 = V[mod.vsp-1] as *u8
538 let fxsl2: i64 = (g_v128_arena as i64) + (g_v128_idx % K_MAGIC_4096) * 16
539 g_v128_idx = g_v128_idx + 1
540 let fxso: *u8 = fxsl2 as *u8
541 var fxk2: i64 = 0
542 while fxk2 < 16 {
543 var fxd: i64 = (fxpa[fxk2] as i64) - (fxpb[fxk2] as i64)
544 if fxd < 0 { fxd = 0 }
545 fxso[fxk2] = fxd as u8
546 fxk2 = fxk2 + 1 }
547 V[mod.vsp-1] = fxsl2
548 }
549 if fxsub == 0x50 { // v128.or: pop b, a -> per-byte a|b
550 mod.vsp = mod.vsp - 1
551 let fxob: *u8 = V[mod.vsp] as *u8
552 let fxoa: *u8 = V[mod.vsp-1] as *u8
553 let fxsl3: i64 = (g_v128_arena as i64) + (g_v128_idx % K_MAGIC_4096) * 16
554 g_v128_idx = g_v128_idx + 1
555 let fxoo: *u8 = fxsl3 as *u8
556 var fxk3: i64 = 0
557 while fxk3 < 16 {
558 let fxv3: i64 = (fxoa[fxk3] as i64) | (fxob[fxk3] as i64)
559 fxoo[fxk3] = fxv3 as u8
560 fxk3 = fxk3 + 1 }
561 V[mod.vsp-1] = fxsl3
562 }
563 if fxsub == 0x7D { // i16x8.extadd_pairwise_i8x16_u: 16 u8 -> 8 u16 pair sums (LE)
564 let fxea: *u8 = V[mod.vsp-1] as *u8
565 let fxsl4: i64 = (g_v128_arena as i64) + (g_v128_idx % K_MAGIC_4096) * 16
566 g_v128_idx = g_v128_idx + 1
567 let fxeo: *u8 = fxsl4 as *u8
568 var fxj: i64 = 0
569 while fxj < 8 {
570 let fxs: i64 = (fxea[fxj*2] as i64) + (fxea[fxj*2+1] as i64)
571 fxeo[fxj*2] = (fxs & 0xFF) as u8
572 fxeo[fxj*2+1] = ((fxs >> 8) & 0xFF) as u8
573 fxj = fxj + 1 }
574 V[mod.vsp-1] = fxsl4
575 }
576 if fxsub == 0x7C { // i16x8.extadd_pairwise_i8x16_s (SIGNED twin -- the mutation gate's tooth)
577 let fxsa: *u8 = V[mod.vsp-1] as *u8
578 let fxsl5: i64 = (g_v128_arena as i64) + (g_v128_idx % K_MAGIC_4096) * 16
579 g_v128_idx = g_v128_idx + 1
580 let fxsoo: *u8 = fxsl5 as *u8
581 var fxj2: i64 = 0
582 while fxj2 < 8 {
583 var fxv0: i64 = fxsa[fxj2*2] as i64
584 if fxv0 >= 128 { fxv0 = fxv0 - 256 }
585 var fxv1: i64 = fxsa[fxj2*2+1] as i64
586 if fxv1 >= 128 { fxv1 = fxv1 - 256 }
587 let fxs2: i64 = (fxv0 + fxv1) & 0xFFFF
588 fxsoo[fxj2*2] = (fxs2 & 0xFF) as u8
589 fxsoo[fxj2*2+1] = ((fxs2 >> 8) & 0xFF) as u8
590 fxj2 = fxj2 + 1 }
591 V[mod.vsp-1] = fxsl5
592 }
593 if fxsub == 0x7F { // i32x4.extadd_pairwise_i16x8_u: 8 u16 -> 4 u32 pair sums (LE)
594 let fxwa: *u8 = V[mod.vsp-1] as *u8
595 let fxsl6: i64 = (g_v128_arena as i64) + (g_v128_idx % K_MAGIC_4096) * 16
596 g_v128_idx = g_v128_idx + 1
597 let fxwo: *u8 = fxsl6 as *u8
598 var fxj3: i64 = 0
599 while fxj3 < 4 {
600 let fxw0: i64 = (fxwa[fxj3*4] as i64) | ((fxwa[fxj3*4+1] as i64) << 8)
601 let fxw1: i64 = (fxwa[fxj3*4+2] as i64) | ((fxwa[fxj3*4+3] as i64) << 8)
602 let fxs3: i64 = fxw0 + fxw1
603 fxwo[fxj3*4] = (fxs3 & 0xFF) as u8
604 fxwo[fxj3*4+1] = ((fxs3 >> 8) & 0xFF) as u8
605 fxwo[fxj3*4+2] = ((fxs3 >> 16) & 0xFF) as u8
606 fxwo[fxj3*4+3] = ((fxs3 >> 24) & 0xFF) as u8
607 fxj3 = fxj3 + 1 }
608 V[mod.vsp-1] = fxsl6
609 }
610 if fxsub == 0x1B { // i32x4.extract_lane <laneidx>: v128 slot -> u32 lane (LE)
611 let fxln: i64 = wv_u8(b, pos)
612 let fxxa: *u8 = V[mod.vsp-1] as *u8
613 let fxoff: i64 = fxln * 4
614 let fxr: i64 = (fxxa[fxoff] as i64) | ((fxxa[fxoff+1] as i64) << 8) | ((fxxa[fxoff+2] as i64) << 16) | ((fxxa[fxoff+3] as i64) << 24)
615 V[mod.vsp-1] = fxr
616 }
617 }
618 // --- fail-fast state-corruption guards (never trip on a faithful run) ---
619 if mod.csp < cbase { wm_trap(1, op, mod.csp, cbase) }
620 if mod.csp >= K_MAGIC_4090 { wm_trap(2, op, mod.csp, 0) }
621 if mod.vsp < vbase { wm_trap(3, op, mod.vsp, vbase) }
622 if mod.vsp >= K_MAGIC_65530 { wm_trap(4, op, mod.vsp, 0) }
623 if mod.lsp >= K_MAGIC_262140 { wm_trap(5, op, mod.lsp, 0) }
624 }
625 }
626 if running == 0 { if mod.vsp > vbase { retval = V[mod.vsp - 1] } }
627 mod.vsp = vbase
628 mod.lsp = lbase
629 mod.csp = cbase
630 sys_munmap(pos as *u8, 8) // free this frame's code cursor (was a per-call leak; recursion-safe LIFO)
631 return retval
632}
633// convenience: run an exported function by name with up to 5 args.
634func wm_run(mod: *WasmMod, name: *u8, a0: i64, a1: i64, a2: i64, a3: i64, a4: i64, na: i64) -> i64 {
635 let fidx: i64 = wm_find_export(mod, name)
636 if fidx < 0 { return 0 - K_MAGIC_999999 }
637 let args: *i64 = sys_mmap(8*8) as *i64
638 args[0]=a0; args[1]=a1; args[2]=a2; args[3]=a3; args[4]=a4
639 return wm_call(mod, fidx, args, na)
640}