tor-browser

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

trailers-gc-stress.js (7091B)


      1 // |jit-test| skip-if: getBuildConfiguration("simulator")
      2 
      3 // This test is intended to test what was committed in
      4 //
      5 //  Bug 1817385 - wasm-gc: reduce cost of allocation and GC paths
      6 //  and
      7 //  Bug 1820120 - Manage Wasm{Array,Struct}Object OOL-storage-blocks
      8 //                using a thread-private cache
      9 //
     10 // and in particular the latter.  The patches in these bugs reduce the cost of
     11 // wasm-gc struct/array allocation and collection, in part by better
     12 // integrating those objects with our generational GC facility.
     13 //
     14 // Existing tests do not cover all of those paths.  In particular they do not
     15 // exercise both set-subtraction algorithms in Nursery::freeTrailerBlocks.
     16 // This test does, though.
     17 //
     18 // The test first creates an "primary" array of 1500 elements.  Each element
     19 // is a reference to a secondary array of between 1 and 50 int32s.  These
     20 // secondary arrays have size chosen randomly, and the elements are also
     21 // random.
     22 //
     23 // Then, elements of the primary array are replaced.  An index in the range 0
     24 // .. N - 1 is randomly chosen, and the element there is replaced by a
     25 // randomly-created secondary array.  This is repeated 500,000 times with
     26 // N = 800.
     27 //
     28 // Finally, all of the above is repeated, but with N = 1200.
     29 //
     30 // As a result just over a million arrays and their trailer blocks, of various
     31 // sizes, are allocated and deallocated.  With N = 800, in
     32 // js::Nursery::freeTrailerBlocks, we end up with trailersRemovedUsed_ of
     33 // around 800, so one of the set-subtraction algorithms is exercised.
     34 // With N = 1200, the other is exercised.  It's not entirely clear why changing
     35 // N causes trailersRemovedUsed_ to have more or less the same value during
     36 // nursery collection, but the correlation does seem fairly robust.
     37 //
     38 // The test is skipped on the simulator because it takes too long to run, and
     39 // triggers timeouts.
     40 
     41 let t =
     42 `(module
     43 
     44   ;; A simple pseudo-random number generator.
     45   ;; Produces numbers in the range 0 .. 2^16-1.
     46   (global $rngState
     47     (mut i32) (i32.const 1)
     48   )
     49   (func $rand (export "rand") (result i32)
     50     (local $t i32)
     51     ;; update $rngState
     52     (local.set $t (global.get $rngState))
     53     (local.set $t (i32.mul (local.get $t) (i32.const 1103515245)))
     54     (local.set $t (i32.add (local.get $t) (i32.const 12345)))
     55     (global.set $rngState (local.get $t))
     56     ;; pull 16 random bits out of it
     57     (local.set $t (i32.shr_u (local.get $t) (i32.const 15)))
     58     (local.set $t (i32.and (local.get $t) (i32.const 0xFFFF)))
     59     (local.get $t)
     60   )
     61 
     62   ;; Array types
     63   (type $tArrayI32      (array (mut i32)))  ;; "secondary array" above
     64   (type $tArrayArrayI32 (array (mut (ref null $tArrayI32)))) ;; "primary array"
     65 
     66   ;; Create an array ("secondary array") containing random numbers, with a
     67   ;; size between 1 and 50, also randomly chosen.
     68   (func $createSecondaryArray (export "createSecondaryArray")
     69                               (result (ref $tArrayI32))
     70     (local $i i32)
     71     (local $nElems i32)
     72     (local $arr (ref $tArrayI32))
     73     (local.set $nElems (call $rand))
     74     (local.set $nElems (i32.rem_u (local.get $nElems) (i32.const 50)))
     75     (local.set $nElems (i32.add   (local.get $nElems) (i32.const 1)))
     76     (local.set $arr (array.new $tArrayI32 (i32.const 0) (local.get $nElems)))
     77     (loop $cont
     78       (array.set $tArrayI32 (local.get $arr) (local.get $i) (call $rand))
     79       (local.set $i (i32.add (local.get $i) (i32.const 1)))
     80       (br_if $cont (i32.lt_u (local.get $i) (local.get $nElems)))
     81     )
     82     (local.get $arr)
     83   )
     84 
     85   ;; Create an array (the "primary array") of 1500 elements of
     86   ;; type ref-of-tArrayI32.
     87   (func $createPrimaryArray (export "createPrimaryArray")
     88                             (result (ref $tArrayArrayI32))
     89     (local $i i32)
     90     (local $arrarr (ref $tArrayArrayI32))
     91     (local.set $arrarr (array.new $tArrayArrayI32 (ref.null $tArrayI32)
     92                                                   (i32.const 1500)))
     93     (loop $cont
     94       (array.set $tArrayArrayI32 (local.get $arrarr)
     95                                  (local.get $i) (call $createSecondaryArray))
     96       (local.set $i (i32.add (local.get $i) (i32.const 1)))
     97       (br_if $cont (i32.lt_u (local.get $i) (i32.const 1500)))
     98     )
     99     (local.get $arrarr)
    100   )
    101 
    102   ;; Use $createPrimaryArray to create an initial array.  Then randomly replace
    103   ;; elements for a while.
    104   (func $churn (export "churn") (param $thresh i32) (result i32)
    105     (local $i i32)
    106     (local $j i32)
    107     (local $finalSum i32)
    108     (local $arrarr (ref $tArrayArrayI32))
    109     (local $arr (ref null $tArrayI32))
    110     (local $arrLen i32)
    111     (local.set $arrarr (call $createPrimaryArray))
    112     ;; This loop iterates 500,000 times.  Each iteration, it chooses
    113     ;; a randomly element in $arrarr and replaces it with a new
    114     ;; random array of 32-bit ints.
    115     (loop $cont
    116       ;; make $j be a random number in 0 .. $thresh-1.
    117       ;; Then replace that index in $arrarr with a new random arrayI32.
    118       (local.set $j (i32.rem_u (call $rand) (local.get $thresh)))
    119       (array.set $tArrayArrayI32 (local.get $arrarr)
    120                                  (local.get $j) (call $createSecondaryArray))
    121       (local.set $i (i32.add (local.get $i) (i32.const 1)))
    122       (br_if $cont (i32.lt_u (local.get $i) (i32.const 500000)))
    123     )
    124 
    125     ;; Finally, compute a checksum by summing all the numbers
    126     ;; in all secondary arrays.  This simply assumes that all of the refs to
    127     ;; secondary arrays are non-null, which isn't per-se guaranteed by the
    128     ;; previous loop, but it works in this case because the RNG
    129     ;; produces each index value to overwrite at least once.
    130     (local.set $finalSum (i32.const 0))
    131     (local.set $i (i32.const 0)) ;; loop var for the outer loop
    132     (loop $outer
    133       ;; body of outer loop
    134       ;; $arr = $arrarr[i]
    135       (local.set $arr (array.get $tArrayArrayI32 (local.get $arrarr)
    136                       (local.get $i)))
    137       ;; iterate over $arr
    138       (local.set $arrLen (array.len (local.get $arr)))
    139       (local.set $j (i32.const 0)) ;; loop var for the inner loop
    140       (loop $inner
    141         ;; body of inner loop
    142         (local.set $finalSum
    143                    (i32.rotl (local.get $finalSum) (i32.const 1)))
    144         (local.set $finalSum
    145                    (i32.xor (local.get $finalSum)
    146                             (array.get $tArrayI32 (local.get $arr)
    147                                                   (local.get $j))))
    148         ;; loop control for the inner loop
    149         (local.set $j (i32.add (local.get $j) (i32.const 1)))
    150         (br_if $inner (i32.lt_u (local.get $j) (local.get $arrLen)))
    151       )
    152       ;; loop control for the outer loop
    153       (local.set $i (i32.add (local.get $i) (i32.const 1)))
    154       (br_if $outer (i32.lt_u (local.get $i) (i32.const 1500)))
    155     )
    156 
    157     ;; finally, roll in the final value of the RNG state
    158     (i32.xor (local.get $finalSum) (global.get $rngState))
    159   )
    160 )`;
    161 
    162 let i = wasmEvalText(t);
    163 let fns = i.exports;
    164 
    165 assertEq(fns.churn(800), -575895114);
    166 assertEq(fns.churn(1200), -1164697516);