tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

litmus13.js (2375B)


      1 // Once we exhaust the register arguments this will alternately grow and then
      2 // shrink the stack frame across tail call boundaries because the increment of
      3 // stack allocation is 16 bytes and our variability exceeds that.
      4 //
      5 // (This is not redundant with eg litmus2, because in that case all the
      6 // functions have the same ballast.  Here we have different ballast, so we get
      7 // growing and shrinking.)
      8 //
      9 // See litmus11 for the direct-call case.
     10 // See litmus16 for the cross-module call_indirect case.
     11 
     12 function ntimes(n, v) {
     13    if (typeof v == "function")
     14        return iota(n).map(v).join(' ');
     15    return iota(n).map(_ => v).join(' ');
     16 }
     17 
     18 function get_local(n) {
     19    return `(local.get ${n})`
     20 }
     21 
     22 function compute(ballast) {
     23    return iota(ballast).reduce((p,g,n) => `(i32.or ${p} (local.get ${n}))`,
     24                                `(i32.const ${1 << ballast})`)
     25 }
     26 
     27 function build(n, ballast) {
     28    switch (n) {
     29    case 0:
     30        return `
     31 (func $f0 (export "f") (result i32)
     32  (return_call_indirect (type $ty1) (i32.const ${1 << n}) (i32.const 1)))
     33 `;
     34    case ballast:
     35        return `
     36 (func $f${ballast} (param ${ntimes(ballast, 'i32')}) (result i32)
     37    (if (result i32) (i32.eqz (global.get $glob))
     38        (then (return ${compute(ballast)}))
     39        (else (block (result i32)
     40          (global.set $glob (i32.sub (global.get $glob) (i32.const 1)))
     41          (return_call_indirect (type $ty0) (i32.const 0))))))
     42 `;
     43    default:
     44        return `
     45 (func $f${n} (param ${ntimes(n, 'i32')}) (result i32)
     46  (return_call_indirect (type $ty${n+1}) (i32.const ${1 << n}) ${ntimes(n, get_local)} (i32.const ${n+1})))
     47 `
     48    }
     49 }
     50 
     51 function types(n) {
     52    var ps = n == 0 ? '' : `(param ${ntimes(n, 'i32')})`;
     53    return `
     54 (type $ty${n} (func ${ps} (result i32)))`;
     55 }
     56 
     57 function funcnames(n) {
     58    return ntimes(n, n => `$f${n}`)
     59 }
     60 
     61 for ( let ballast=1; ballast < TailCallBallast; ballast++ ) {
     62 
     63    let vals = iota(ballast+1).map(v => 1 << v);
     64    let sumv = vals.reduce((p,c) => p|c);
     65    let text = `
     66 (module
     67  ${ntimes(ballast+1, n => types(n))}
     68  (table $t ${ballast+1} ${ballast+1} funcref)
     69  (elem (table $t) (i32.const 0) func ${funcnames(ballast+1)})
     70  (global $glob (mut i32) (i32.const ${TailCallIterations}))
     71  ${ntimes(ballast, n => build(n, ballast))}
     72  ${build(ballast, ballast)})
     73 `;
     74 
     75    let ins = wasmEvalText(text);
     76    assertEq(ins.exports.f(), sumv);
     77 }