code wiki / _hdl_build / nx_js_vm_bench.nx
nx_js_vm_bench.nx source
↩ module page · 92 lines · 5487 B
1// nx_js_vm_bench.nx -- KEYSTONE of the bytecode-VM arc: a minimal stack-based BYTECODE VM (tight dispatch
2// loop, no AST walk / no recursion / no per-node kind-dispatch) runs the SAME hot loop as the tree-walker,
3// and we MEASURE the speedup. Integer-only for the proof (the hot path is arithmetic); tagged values +
4// full opcodes + an AST->bytecode compiler are the next rungs. Same result + faster = the architecture is
5// proven, de-risking the arc. license_tier: ORIGINAL
6import "nx_js_eval.nx" // tree-walker (js_run_source) for the head-to-head
7const BC_MAGIC_100000: i64 = 100000
8const BC_MAGIC_4999950000: i64 = 4999950000
9const BC_MAGIC_200000: i64 = 200000
10const BC_MAGIC_1000000: i64 = 1000000
11
12func bw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
13func bn(v: i64) -> i64 { if v==0 { sys_write(1,"0" as *u8,1); return 0 } var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } let t: *u8=sys_mmap(32); var k: i64=0; while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } let o: *u8=sys_mmap(32); var q: i64=k-1; var x: i64=0; while q>=0 { o[x]=t[q]; x=x+1; q=q-1 } sys_write(1,o,x); return 0 }
14func bsl(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
15
16// ---- bytecode ISA (each instr = 2 i64: [op, arg]; pc indexes the flat array, +2 per instr) ----
17const BC_PUSH: i64 = 1 // push imm arg
18const BC_LOAD: i64 = 2 // push vars[arg]
19const BC_STORE: i64 = 3 // vars[arg] = pop
20const BC_ADD: i64 = 4 // b=pop; a=pop; push a+b
21const BC_LT: i64 = 5 // b=pop; a=pop; push (a<b)?1:0
22const BC_JMPF: i64 = 6 // c=pop; if c==0 pc=arg else pc+=2
23const BC_JMP: i64 = 7 // pc=arg
24const BC_RET: i64 = 8 // return top of stack
25
26// the TIGHT dispatch loop -- this is the whole point: one array read + a dispatch chain per instruction.
27func vm_run(code: *i64, vars: *i64, stack: *i64) -> i64 {
28 var pc: i64 = 0
29 var sp: i64 = 0
30 var result: i64 = 0
31 var running: i64 = 1
32 while running == 1 {
33 let op: i64 = code[pc]
34 let arg: i64 = code[pc + 1]
35 if op == BC_PUSH { stack[sp] = arg; sp = sp + 1; pc = pc + 2 }
36 else { if op == BC_LOAD { let v: i64 = vars[arg]; stack[sp] = v; sp = sp + 1; pc = pc + 2 }
37 else { if op == BC_STORE { sp = sp - 1; let v: i64 = stack[sp]; vars[arg] = v; pc = pc + 2 }
38 else { if op == BC_ADD { sp = sp - 1; let b: i64 = stack[sp]; let a: i64 = stack[sp - 1]; stack[sp - 1] = a + b; pc = pc + 2 }
39 else { if op == BC_LT { sp = sp - 1; let b: i64 = stack[sp]; let a: i64 = stack[sp - 1]; if a < b { stack[sp - 1] = 1 } else { stack[sp - 1] = 0 } pc = pc + 2 }
40 else { if op == BC_JMPF { sp = sp - 1; let c: i64 = stack[sp]; if c == 0 { pc = arg } else { pc = pc + 2 } }
41 else { if op == BC_JMP { pc = arg }
42 else { if op == BC_RET { let v: i64 = stack[sp - 1]; result = v; running = 0 }
43 else { running = 0 } } } } } } } }
44 }
45 return result
46}
47func emit(code: *i64, i: i64, op: i64, arg: i64) -> i64 { code[i * 2] = op; code[i * 2 + 1] = arg; return 0 }
48
49func main(argc: i64, argv: *i64) -> i64 {
50 bw("=== nx_js_vm_bench: tree-walker vs bytecode VM (same hot loop) ===\n" as *u8)
51 // --- tree-walker ---
52 let src: *u8 = "var s=0;var i=0;while(i<100000){s=s+i;i=i+1;}s" as *u8
53 let out: *i64 = sys_mmap(16) as *i64
54 let a0: i64 = sys_now_us(); js_run_source(src, bsl(src), out); let a1: i64 = sys_now_us()
55 let tw_us: i64 = a1 - a0
56 let tw_res: i64 = out[1]
57
58 // --- bytecode VM: hand-compiled `var s=0;var i=0;while(i<100000){s=s+i;i=i+1;} s` (vars: s=0, i=1) ---
59 let code: *i64 = sys_mmap(64 * 8) as *i64
60 emit(code, 0, BC_PUSH, 0) // s=0
61 emit(code, 1, BC_STORE, 0)
62 emit(code, 2, BC_PUSH, 0) // i=0
63 emit(code, 3, BC_STORE, 1)
64 emit(code, 4, BC_LOAD, 1) // LOOP (pc8): i
65 emit(code, 5, BC_PUSH, BC_MAGIC_100000)
66 emit(code, 6, BC_LT, 0) // i<BC_MAGIC_100000
67 emit(code, 7, BC_JMPF, 34) // false -> END (pc34)
68 emit(code, 8, BC_LOAD, 0) // s
69 emit(code, 9, BC_LOAD, 1) // i
70 emit(code, 10, BC_ADD, 0) // s+i
71 emit(code, 11, BC_STORE, 0) // s=
72 emit(code, 12, BC_LOAD, 1) // i
73 emit(code, 13, BC_PUSH, 1)
74 emit(code, 14, BC_ADD, 0) // i+1
75 emit(code, 15, BC_STORE, 1) // i=
76 emit(code, 16, BC_JMP, 8) // -> LOOP (pc8)
77 emit(code, 17, BC_LOAD, 0) // END (pc34): s
78 emit(code, 18, BC_RET, 0)
79 let vars: *i64 = sys_mmap(16 * 8) as *i64
80 let stack: *i64 = sys_mmap(256 * 8) as *i64
81 let b0: i64 = sys_now_us(); let vm_res: i64 = vm_run(code, vars, stack); let b1: i64 = sys_now_us()
82 let vm_us: i64 = b1 - b0
83
84 bw(" tree-walker : result="); bn(tw_res); bw(" time="); bn(tw_us); bw(" us\n" as *u8)
85 bw(" bytecode VM : result="); bn(vm_res); bw(" time="); bn(vm_us); bw(" us\n" as *u8)
86 var ok: i64 = 0
87 if tw_res == vm_res { if tw_res == BC_MAGIC_4999950000 { ok = 1 } }
88 if ok == 1 { bw(" CORRECT (both = 4999950000)\n" as *u8) } else { bw(" !! MISMATCH\n" as *u8) }
89 if vm_us > 0 { bw(" SPEEDUP = "); bn(tw_us / vm_us); bw("x faster ("); bn((BC_MAGIC_200000 * BC_MAGIC_1000000) / vm_us); bw(" ops/sec vs "); bn((BC_MAGIC_200000 * BC_MAGIC_1000000) / tw_us); bw(")\n" as *u8) }
90 if ok == 1 { if vm_us < tw_us { bw("=== GREEN: bytecode VM is CORRECT + FASTER -> architecture PROVEN ===\n" as *u8); return 0 } }
91 bw("=== RED ===\n" as *u8); return 1
92}