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}