tor-browser

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

float-unaligned.js (4655B)


      1 // Various tests for unaligned float accesses.  These are specifically meant to
      2 // test the SIGBUS handling on 32-bit ARM by exercising odd addresses and odd
      3 // offsets.
      4 
      5 // For a triple of (numBallast, ty, offset), create the text for a pair of
      6 // functions "get_ty_offset" and "set_ty_offset" where each has numBallast live
      7 // dummy values across the operation of interest to force the use of different
      8 // register numbers.  (This is primarily for the FP registers as ARM code
      9 // generation currently always uses the same scratch register for the base
     10 // address of the access.)
     11 //
     12 // These must be augmented with a memory.  Memory addresses 0-255 are reserved
     13 // for internal use by these functions.  The memory must start as zero.
     14 
     15 function makeLoadStore(numBallast, ty, offset) {
     16    // The general idea of the ballast is that we occupy some FP registers and
     17    // some int registers with non-dead values before we perform an operation,
     18    // and then we consume the occupied registers after.
     19    //
     20    // In the case of load, the loaded result is stored back in memory before we
     21    // consume the ballast, thus the ion regalloc will not simply always load
     22    // the result into d0, but usually into some temp other than d0.  Thus the
     23    // amount of ballast affects the register.  (Ditto baseline though the
     24    // reasoning is simpler.)
     25    //
     26    // In the case of store, we keep the parameter value live until the end so
     27    // that the tmp that we compute for the store is moved into a different
     28    // register.  The tmp has the same value as the parameter value but a
     29    // non-JIT compiler can't know that.
     30 
     31    let loadtxt =
     32      `(func (export "get_${ty}_${offset}") (param $p i32) (result ${ty})
     33         ${ballast(() => `
     34              (i32.const 8)
     35              (i32.store (i32.const 8) (i32.add (i32.load (i32.const 8)) (i32.const 1)))
     36              (${ty}.load (i32.const 8))`)}
     37 
     38         (${ty}.store (i32.const 0) (${ty}.load offset=${offset} (local.get $p)))
     39 
     40         ${ballast(() => `
     41             ${ty}.store`)}
     42 
     43         (${ty}.load (i32.const 0)))`;
     44 
     45    // This will assume the value at mem[16] is zero.
     46    let storetxt =
     47      `(func (export "set_${ty}_${offset}") (param $p i32) (param $v ${ty})
     48         (local $tmp ${ty})
     49         ${ballast(() => `
     50              (i32.const 8)
     51              (i32.store (i32.const 8) (i32.add (i32.load (i32.const 8)) (i32.const 1)))
     52              (${ty}.load (i32.const 8))`)}
     53 
     54         (local.set $tmp (${ty}.add (local.get $v) (${ty}.load (i32.const 16))))
     55         (${ty}.store offset=${offset} (local.get $p) (local.get $tmp))
     56 
     57         ${ballast(() => `
     58             ${ty}.store`)}
     59         (${ty}.store (i32.const 8) (local.get $v)))`;
     60 
     61    return `${loadtxt}
     62            ${storetxt}`;
     63 
     64    function ballast(thunk) {
     65        let s = "";
     66        for ( let i=0 ; i < numBallast; i++ )
     67            s += thunk();
     68        return s;
     69    }
     70 }
     71 
     72 // The complexity here comes from trying to force the source/target FP registers
     73 // in the FP access instruction to vary.  For Baseline this is not hard; for Ion
     74 // trickier.
     75 
     76 function makeInstance(numBallast, offset) {
     77    let txt =
     78        `(module
     79           (memory (export "memory") 1 1)
     80           ${makeLoadStore(numBallast, 'f64', offset)}
     81           ${makeLoadStore(numBallast, 'f32', offset)})`;
     82    return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(txt)));
     83 }
     84 
     85 // `offset` corresponds to the "offset" directive in the instruction
     86 for ( let offset=0 ; offset < 8; offset++ ) {
     87 
     88    // `numBallast` represents the amount of ballast registers we're trying to use,
     89    // see comments above.
     90    for ( let numBallast=0; numBallast < 16; numBallast++ ) {
     91        let ins = makeInstance(numBallast, offset);
     92        let mem = ins.exports.memory;
     93        let buf = new DataView(mem.buffer);
     94 
     95        // `i` represents the offset in the pointer from a proper boundary
     96        for ( let i=0; i < 9; i++ ) {
     97     let offs = 256+i;
     98            let val = Math.PI+i;
     99 
    100            buf.setFloat64(offs + offset, val, true);
    101            assertEq(ins.exports["get_f64_" + offset](offs), val);
    102 
    103            ins.exports["set_f64_" + offset](offs + 32, val);
    104            assertEq(buf.getFloat64(offs + 32 + offset, true), val);
    105        }
    106 
    107        for ( let i=0; i < 9; i++ ) {
    108            let offs = 512+i;
    109            let val = Math.fround(Math.PI+i);
    110 
    111            buf.setFloat32(offs + offset, val, true);
    112            assertEq(ins.exports["get_f32_" + offset](offs), val);
    113 
    114            ins.exports["set_f32_" + offset](offs + 32, val);
    115            assertEq(buf.getFloat32(offs + 32 + offset, true), val);
    116        }
    117    }
    118 }