code wiki / _hdl_build / nx_js_jit_gate.nx

nx_js_jit_gate.nx source

↩ module page · 241 lines · 12178 B

1// nx_js_jit_gate.nx -- P5 BASELINE JIT: prove it (A) is CORRECT vs the VM and the tree-walker on the 2// templatable subset, (B) DECLINES cleanly (jit_compile==0 -> VM) on everything outside the subset, 3// and (C) MEASURES the native speedup + class band on the SAME entry point (js_jit_disable A/B). 4// The 108/108 parity gate already proves JIT==tree end-to-end; this adds the three-way A/B/tree 5// agreement, the decline contract, and the ladder placement. expect_exit: 0 license_tier: ORIGINAL 6import "nx_js_vm.nx" 7 8// three-way: tree-walker vs JIT-on vs VM-forced must ALL agree (value + rc) on `src`. 9func jchk(src: *u8, label: *u8, pp: *i64, tp: *i64) -> i64 { 10 tp[0] = tp[0] + 1 11 let tw: *i64 = sys_mmap(16) as *i64 12 let trc: i64 = js_run_source(src, bsl(src), tw) 13 js_jit_disable(0) 14 let jv: *i64 = sys_mmap(16) as *i64 15 let jrc: i64 = compile_run(src, jv) 16 js_jit_disable(1) 17 let vv: *i64 = sys_mmap(16) as *i64 18 let vrc: i64 = compile_run(src, vv) 19 js_jit_disable(0) 20 bw(" ") 21 bw(label) 22 bw(": ") 23 var ok: i64 = 1 24 if trc != jrc { ok = 0 } 25 if trc != vrc { ok = 0 } 26 if trc == 0 { if cells_eq(tw, jv) == 0 { ok = 0 } } 27 if trc == 0 { if cells_eq(tw, vv) == 0 { ok = 0 } } 28 if ok == 1 { pp[0] = pp[0] + 1; bw("ok (tree=JIT=VM)\n" as *u8); return 0 } 29 bw("FAIL tree(rc=") 30 bn(trc) 31 bw(",tag=") 32 bn(tw[0]) 33 bw(",pay=") 34 bn(tw[1]) 35 bw(") JIT(rc=") 36 bn(jrc) 37 bw(",tag=") 38 bn(jv[0]) 39 bw(",pay=") 40 bn(jv[1]) 41 bw(") VM(rc=") 42 bn(vrc) 43 bw(",tag=") 44 bn(vv[0]) 45 bw(",pay=") 46 bn(vv[1]) 47 bw(")\n" as *u8) 48 return 0 49} 50// decline contract: `src` MUST or MUST NOT be JIT-compiled (want=1 templatable, 0 declines to VM). 51func jdec(src: *u8, want: i64, label: *u8, pp: *i64, tp: *i64) -> i64 { 52 tp[0] = tp[0] + 1 53 let got: i64 = js_jit_probe(src) 54 bw(" ") 55 bw(label) 56 bw(": jit=") 57 bn(got) 58 bw(" want=") 59 bn(want) 60 if got == want { pp[0] = pp[0] + 1; bw(" ok\n" as *u8); return 0 } 61 bw(" FAIL\n" as *u8) 62 return 0 63} 64// best-of-3 microseconds for `src` at a JIT setting (0=JIT on, 1=forced VM); records result in `outcell`. 65// min-of-N cancels WSL load spikes -- single-sample A/B margins flake and the pass asserts should not. 66func jt3(src: *u8, disabled: i64, outcell: *i64) -> i64 { 67 js_jit_disable(disabled) 68 var best: i64 = 0 69 var r: i64 = 0 70 while r < 3 { 71 let t0: i64 = sys_now_us() 72 compile_run(src, outcell) 73 let t1: i64 = sys_now_us() 74 var us: i64 = t1 - t0 75 if us < 1 { us = 1 } 76 if r == 0 { best = us } 77 if us < best { best = us } 78 r = r + 1 79 } 80 js_jit_disable(0) 81 return best 82} 83 84func main(argc: i64, argv: *i64) -> i64 { 85 bw("=== nx_js_jit_gate: P5 baseline JIT -- correct + declines + measured ===\n" as *u8) 86 let pp: *i64 = sys_mmap(8) as *i64 87 let tp: *i64 = sys_mmap(8) as *i64 88 bw(" [A: tree == JIT == VM on the templatable subset]\n" as *u8) 89 jchk("1+2*3" as *u8, "J1 int precedence" as *u8, pp, tp) 90 jchk("var s=0;var i=0;while(i<1000){s=s+i;i++;}s" as *u8, "J2 counted loop 1000" as *u8, pp, tp) 91 jchk("var n=6;var f=1;var i=1;while(i<=n){f=f*i;i=i+1;}f" as *u8, "J3 factorial(6)" as *u8, pp, tp) 92 jchk("var x=7;if(x>5){x=1;}else{x=2;}x" as *u8, "J4 if/else" as *u8, pp, tp) 93 jchk("0-5+3" as *u8, "J5 neg arith" as *u8, pp, tp) 94 jchk("var n=4;-n" as *u8, "J6 unary neg" as *u8, pp, tp) 95 jchk("var i=5;i++;i" as *u8, "J7 i++" as *u8, pp, tp) 96 jchk("var i=5;var j=i++;j*10+i" as *u8, "J8 postfix OLD" as *u8, pp, tp) 97 jchk("var x=5;x+=3;x" as *u8, "J9 compound += (SWAP)" as *u8, pp, tp) 98 jchk("var a=1;var b=5;a&&b" as *u8, "J10 && (DUP/JMPF)" as *u8, pp, tp) 99 jchk("var a=0;var b=5;a||b" as *u8, "J11 || (JMPT)" as *u8, pp, tp) 100 jchk("var i=0;var c=0;while(i<10){if(i>2){if(i<7){c=c+1;}}i=i+1;}c" as *u8, "J12 nested-if loop" as *u8, pp, tp) 101 jchk("var x=5;x>3?100:200" as *u8, "J13 ternary" as *u8, pp, tp) 102 jchk("!0" as *u8, "J14 unary not" as *u8, pp, tp) 103 jchk("var s=0;var i=1;while(i<20){s=s+7/2;i++;}s" as *u8, "J15 float in loop (7/2=3.5, tree=JIT=VM)" as *u8, pp, tp) 104 jchk("5+zzz" as *u8, "J16 ReferenceError parity" as *u8, pp, tp) 105 jchk("var r='';var i=0;while(i<5){r=r+'x';i++;}r" as *u8, "J17 string concat (slow BINOP path)" as *u8, pp, tp) 106 jchk("var s=0;var i=0;while(i<100){s=s+i*2-1;i++;}s" as *u8, "J18 mixed arith loop" as *u8, pp, tp) 107 // objects/arrays now JIT (inline shape-guarded GETPROP + call-threaded set/idx/literal); must match 108 jchk("var o={a:1,b:2,c:3};o.a+o.b+o.c" as *u8, "J19 object member reads" as *u8, pp, tp) 109 jchk("var o={a:0,b:7};var i=0;while(i<1000){o.a=o.a+o.b;i++;}o.a" as *u8, "J20 property churn loop (inline IC)" as *u8, pp, tp) 110 jchk("var a=[];var i=0;while(i<50){a[i]={n:i,m:i*2};i++;}var s=0;var j=0;while(j<50){s=s+a[j].m;j++;}s" as *u8, "J21 array of objects (many shapes-hit)" as *u8, pp, tp) 111 jchk("var o={a:1};o.b=2;o.a+o.b" as *u8, "J22 incremental prop (shape transition)" as *u8, pp, tp) 112 jchk("var a=[3,1,4];a[1]=9;a[0]+a[1]+a[2]" as *u8, "J23 array index get+set" as *u8, pp, tp) 113 jchk("var o={x:5};o.nope" as *u8, "J24 absent prop -> undefined (shape miss slow path)" as *u8, pp, tp) 114 jchk("var o={n:2};o.n+=5;o.n" as *u8, "J25 compound member (get+set)" as *u8, pp, tp) 115 // functions now run NATIVE (frame setup + hardware call/ret + closures + recursion); must match 116 jchk("function add(a,b){return a+b;}add(3,4)" as *u8, "J26 fn decl+call (native)" as *u8, pp, tp) 117 jchk("function fib(n){if(n<2){return n;}return fib(n-1)+fib(n-2);}fib(12)" as *u8, "J27 recursion fib(12)" as *u8, pp, tp) 118 jchk("function mk(){var c=0;return function(){c=c+1;return c;};}var f=mk();f();f();f()" as *u8, "J28 closure counter (captured env)" as *u8, pp, tp) 119 jchk("function mkAdd(x){return function(y){return x+y;};}var a5=mkAdd(5);a5(7)" as *u8, "J29 closure adder" as *u8, pp, tp) 120 jchk("function f(a,b=10){return a+b;}f(5)" as *u8, "J30 param default (native)" as *u8, pp, tp) 121 jchk("function f(a,...r){return r.length+a;}f(1,2,3,4)" as *u8, "J31 rest param (native)" as *u8, pp, tp) 122 jchk("(function(){return 5;})()" as *u8, "J32 IIFE" as *u8, pp, tp) 123 jchk("function g(){var o={a:1,b:2};return o.a+o.b;}g()+g()" as *u8, "J33 object inside fn body" as *u8, pp, tp) 124 jchk("function bad(){return zzzundeclared;}var r=0;bad()" as *u8, "J34 error inside call -> rc1 (longjmp bail)" as *u8, pp, tp) 125 // method calls, new, and callbacks now JIT too (native method-resolution + this-binding; callbacks re-enter) 126 jchk("var o={v:6,f:function(){return this.v;}};o.f()" as *u8, "J35 method call (this-binding)" as *u8, pp, tp) 127 jchk("[1,2,3].map(function(x){return x*2;}).join('-')" as *u8, "J36 forEach/map callback (CALLM)" as *u8, pp, tp) 128 jchk("[1,2,3,4].reduce(function(a,b){return a+b;},0)" as *u8, "J37 reduce callback" as *u8, pp, tp) 129 jchk("function P(n){this.n=n;this.m=n*2;}var p=new P(4);p.n+p.m" as *u8, "J38 new user ctor (this)" as *u8, pp, tp) 130 jchk("Math.max(3,7,5)+Math.min(2,9)" as *u8, "J39 globalns method (Math)" as *u8, pp, tp) 131 jchk("var a=[3,1];a.push(9);a.length" as *u8, "J40 array method (push)" as *u8, pp, tp) 132 bw(" [B: decline contract -- only TRY/THROW decline now; functions/methods/new/callbacks all JIT]\n" as *u8) 133 jdec("var s=0;var i=0;while(i<10){s=s+i;i++;}s" as *u8, 1, "D1 pure loop -> JIT" as *u8, pp, tp) 134 jdec("var o={a:1};o.a" as *u8, 1, "D2 object member -> JIT" as *u8, pp, tp) 135 jdec("function fib(n){if(n<2){return n;}return fib(n-1)+fib(n-2);}fib(5)" as *u8, 1, "D3 recursion -> JIT" as *u8, pp, tp) 136 jdec("var o={f:function(){return 1;}};o.f()" as *u8, 1, "D4 method call -> JIT (native)" as *u8, pp, tp) 137 jdec("[1,2,3].forEach(function(x){});1" as *u8, 1, "D5 callback (CALLM) -> JIT" as *u8, pp, tp) 138 jdec("function P(n){this.n=n;}var p=new P(4);p.n" as *u8, 1, "D6 new (BC_NEW) -> JIT" as *u8, pp, tp) 139 jdec("Math.max(1,2,3)" as *u8, 1, "D7 Math.max (CALLM globalns) -> JIT" as *u8, pp, tp) 140 jdec("try{throw 1;}catch(e){}1" as *u8, 0, "D8 try/catch -> decline" as *u8, pp, tp) 141 jdec("try{var x=1;}finally{var y=2;}x" as *u8, 0, "D9 try/finally -> decline" as *u8, pp, tp) 142 bw(" --- correctness+decline: " as *u8) 143 bn(pp[0]) 144 bw("/" as *u8) 145 bn(tp[0]) 146 bw(" ---\n" as *u8) 147 148 // [C] measurement: SAME entry (compile_run), JIT vs forced-VM, on the K1 dispatch kernel. 149 bw(" [C: native speedup + class band on the K1 dispatch kernel (200k int loop)]\n" as *u8) 150 let ksrc: *u8 = "var s=0;var i=0;while(i<200000){s=s+i;i++;}s" as *u8 151 let jo: *i64 = sys_mmap(16) as *i64 152 let vo: *i64 = sys_mmap(16) as *i64 153 let jus: i64 = jt3(ksrc, 0, jo) 154 let vus: i64 = jt3(ksrc, 1, vo) 155 let jrate: i64 = 200000 * 1000000 / jus 156 let vrate: i64 = 200000 * 1000000 / vus 157 var okc: i64 = 0 158 if cells_eq(jo, vo) == 1 { okc = 1 } 159 bw(" VM : ") 160 bn(vrate) 161 bw(" iters/s (") 162 bn(vus) 163 bw("us)\n" as *u8) 164 bw(" JIT : ") 165 bn(jrate) 166 bw(" iters/s (") 167 bn(jus) 168 bw("us) speedup=") 169 bn(jrate / vrate) 170 bw("x\n" as *u8) 171 bw(" band : JIT lands in ") 172 if jrate >= 500000000 { bw("optimizing-JIT-class (>=500M iters/s)" as *u8) } 173 if jrate >= 100000000 { if jrate < 500000000 { bw("baseline-JIT-class (>=100M iters/s)" as *u8) } } 174 if jrate < 100000000 { bw("interpreter-class (<100M -- box under load; retry on a fresh VM)" as *u8) } 175 bw("\n" as *u8) 176 177 // [D] object-heavy kernel (property churn): inline shape-guarded GETPROP runs native; call-threaded 178 // SETPROP. JIT vs forced-VM A/B on the SAME entry. 179 bw(" [D: property-churn kernel (100k iters, o.a=o.a+o.b -- inline shape-IC GETPROP)]\n" as *u8) 180 let psrc: *u8 = "var o={a:0,b:7};var i=0;while(i<100000){o.a=o.a+o.b;i++;}o.a" as *u8 181 let pjo: *i64 = sys_mmap(16) as *i64 182 let pvo: *i64 = sys_mmap(16) as *i64 183 let pjus: i64 = jt3(psrc, 0, pjo) 184 let pvus: i64 = jt3(psrc, 1, pvo) 185 var okp: i64 = 0 186 if cells_eq(pjo, pvo) == 1 { okp = 1 } 187 bw(" VM : ") 188 bn(pvus) 189 bw("us JIT: ") 190 bn(pjus) 191 bw("us speedup=") 192 bn(pvus * 100 / pjus) 193 bw("/100x (result match=") 194 bn(okp) 195 bw(")\n" as *u8) 196 197 // [E] call-heavy kernel (recursion): native frames + hardware call/ret. JIT vs forced-VM A/B. 198 bw(" [E: recursion kernel fib(28) -- native call frames + hardware call/ret]\n" as *u8) 199 let fsrc: *u8 = "function fib(n){if(n<2){return n;}return fib(n-1)+fib(n-2);}fib(28)" as *u8 200 let fjo: *i64 = sys_mmap(16) as *i64 201 let fvo: *i64 = sys_mmap(16) as *i64 202 let fjus: i64 = jt3(fsrc, 0, fjo) 203 let fvus: i64 = jt3(fsrc, 1, fvo) 204 var okf: i64 = 0 205 if cells_eq(fjo, fvo) == 1 { okf = 1 } 206 bw(" VM : ") 207 bn(fvus) 208 bw("us JIT: ") 209 bn(fjus) 210 bw("us speedup=") 211 bn(fvus * 100 / fjus) 212 bw("/100x (result match=") 213 bn(okf) 214 bw(")\n" as *u8) 215 216 // [F] method-call kernel: hot loop calling a user method with this-binding (native CALLM + frame). 217 bw(" [F: method-call kernel (100k o.inc() -- native CALLM + this-binding + native frame)]\n" as *u8) 218 let msrc: *u8 = "var o={v:0,inc:function(){this.v=this.v+1;return this.v;}};var s=0;var i=0;while(i<100000){s=s+o.inc();i++;}s" as *u8 219 let mjo: *i64 = sys_mmap(16) as *i64 220 let mvo: *i64 = sys_mmap(16) as *i64 221 let mjus: i64 = jt3(msrc, 0, mjo) 222 let mvus: i64 = jt3(msrc, 1, mvo) 223 var okm: i64 = 0 224 if cells_eq(mjo, mvo) == 1 { okm = 1 } 225 bw(" VM : ") 226 bn(mvus) 227 bw("us JIT: ") 228 bn(mjus) 229 bw("us speedup=") 230 bn(mvus * 100 / mjus) 231 bw("/100x (result match=") 232 bn(okm) 233 bw(")\n" as *u8) 234 235 if pp[0] == tp[0] { if okc == 1 { if okp == 1 { if okf == 1 { if okm == 1 { if jrate > vrate { if pjus < pvus { if fjus < fvus { if mjus < mvus { 236 bw("=== GREEN: JIT CORRECT (tree=JIT=VM) incl OBJECTS + FUNCTIONS/METHODS/NEW/RECURSION/CLOSURES/CALLBACKS; declines only TRY; native-fast on ints, property churn, calls, AND methods ===\n" as *u8) 237 return 0 238 } } } } } } } } } 239 bw("=== RED ===\n" as *u8) 240 return 1 241}