tor-browser

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

table-gc.js (6166B)


      1 // |jit-test| --no-baseline; --no-blinterp
      2 // Turn off baseline and since it messes up the GC finalization assertions by
      3 // adding spurious edges to the GC graph.
      4 
      5 const Module = WebAssembly.Module;
      6 const Instance = WebAssembly.Instance;
      7 const Table = WebAssembly.Table;
      8 const RuntimeError = WebAssembly.RuntimeError;
      9 
     10 var caller = `(type $v2i (func (result i32))) (func $call (param $i i32) (result i32) (call_indirect (type $v2i) (local.get $i))) (export "call" (func $call))`
     11 var callee = i => `(func $f${i} (type $v2i) (i32.const ${i}))`;
     12 
     13 // A table should not hold exported functions alive and exported functions
     14 // should not hold their originating table alive. Live exported functions should
     15 // hold instances alive and instances hold imported tables alive. Nothing
     16 // should hold the export object alive.
     17 resetFinalizeCount();
     18 var i = wasmEvalText(`(module (table 2 funcref) (export "tbl" (table 0)) (elem (i32.const 0) $f0) ${callee(0)} ${caller})`);
     19 var e = i.exports;
     20 var t = e.tbl;
     21 var f = t.get(0);
     22 assertEq(f(), e.call(0));
     23 assertErrorMessage(() => e.call(1), RuntimeError, /indirect call to null/);
     24 assertErrorMessage(() => e.call(2), RuntimeError, /index out of bounds/);
     25 assertEq(finalizeCount(), 0);
     26 i.edge = makeFinalizeObserver();
     27 t.edge = makeFinalizeObserver();
     28 f.edge = makeFinalizeObserver();
     29 gc();
     30 assertEq(finalizeCount(), 0);
     31 f.x = 42;
     32 f = null;
     33 gc();
     34 assertEq(finalizeCount(), 0);
     35 f = t.get(0);
     36 assertEq(f.x, 42);
     37 gc();
     38 assertEq(finalizeCount(), 0);
     39 i.exports = null;
     40 e = null;
     41 gc();
     42 assertEq(finalizeCount(), 0);
     43 t = null;
     44 gc();
     45 assertEq(finalizeCount(), 0);
     46 i = null;
     47 gc();
     48 assertEq(finalizeCount(), 0);
     49 assertEq(f(), 0);
     50 f = null;
     51 gc();
     52 assertEq(finalizeCount(), 3);
     53 
     54 // A table should hold the instance of any of its elements alive.
     55 resetFinalizeCount();
     56 var i = wasmEvalText(`(module (table 1 funcref) (export "tbl" (table 0)) (elem (i32.const 0) $f0) ${callee(0)} ${caller})`);
     57 var e = i.exports;
     58 var t = e.tbl;
     59 var f = t.get(0);
     60 i.edge = makeFinalizeObserver();
     61 t.edge = makeFinalizeObserver();
     62 f.edge = makeFinalizeObserver();
     63 gc();
     64 assertEq(finalizeCount(), 0);
     65 i.exports = null;
     66 e = null;
     67 gc();
     68 assertEq(finalizeCount(), 0);
     69 f = null;
     70 gc();
     71 assertEq(finalizeCount(), 0);
     72 i = null;
     73 gc();
     74 assertEq(finalizeCount(), 0);
     75 t = null;
     76 gc();
     77 assertEq(finalizeCount(), 3);
     78 
     79 // Null elements shouldn't keep anything alive.
     80 resetFinalizeCount();
     81 var i = wasmEvalText(`(module (table 2 funcref) (export "tbl" (table 0)) ${caller})`);
     82 var e = i.exports;
     83 var t = e.tbl;
     84 i.edge = makeFinalizeObserver();
     85 t.edge = makeFinalizeObserver();
     86 gc();
     87 assertEq(finalizeCount(), 0);
     88 i.exports = null;
     89 e = null;
     90 gc();
     91 assertEq(finalizeCount(), 0);
     92 i = null;
     93 gc();
     94 assertEq(finalizeCount(), 1);
     95 t = null;
     96 gc();
     97 assertEq(finalizeCount(), 2);
     98 
     99 // Before initialization, a table is not bound to any instance.
    100 resetFinalizeCount();
    101 var i = wasmEvalText(`(module (func $f0 (result i32) (i32.const 0)) (export "f0" (func $f0)))`);
    102 var t = new Table({initial:4, element:"anyfunc"});
    103 i.edge = makeFinalizeObserver();
    104 t.edge = makeFinalizeObserver();
    105 gc();
    106 assertEq(finalizeCount(), 0);
    107 i = null;
    108 gc();
    109 assertEq(finalizeCount(), 1);
    110 t = null;
    111 gc();
    112 assertEq(finalizeCount(), 2);
    113 
    114 // When a Table is created (uninitialized) and then first assigned, it keeps the
    115 // first element's Instance alive (as above).
    116 resetFinalizeCount();
    117 var i = wasmEvalText(`(module (func $f (result i32) (i32.const 42)) (export "f" (func $f)))`);
    118 var f = i.exports.f;
    119 var t = new Table({initial:1, element:"anyfunc"});
    120 i.edge = makeFinalizeObserver();
    121 f.edge = makeFinalizeObserver();
    122 t.edge = makeFinalizeObserver();
    123 t.set(0, f);
    124 assertEq(t.get(0), f);
    125 assertEq(t.get(0)(), 42);
    126 gc();
    127 assertEq(finalizeCount(), 0);
    128 f = null;
    129 i.exports = null;
    130 gc();
    131 assertEq(finalizeCount(), 0);
    132 assertEq(t.get(0)(), 42);
    133 i = null;
    134 gc();
    135 assertEq(finalizeCount(), 0);
    136 t.set(0, null);
    137 assertEq(t.get(0), null);
    138 gc();
    139 assertEq(finalizeCount(), 2);
    140 t = null;
    141 gc();
    142 assertEq(finalizeCount(), 3);
    143 
    144 // Once all of an instance's elements in a Table have been clobbered, the
    145 // Instance should not be reachable.
    146 resetFinalizeCount();
    147 var i1 = wasmEvalText(`(module (func $f1 (result i32) (i32.const 13)) (export "f1" (func $f1)))`);
    148 var i2 = wasmEvalText(`(module (func $f2 (result i32) (i32.const 42)) (export "f2" (func $f2)))`);
    149 var f1 = i1.exports.f1;
    150 var f2 = i2.exports.f2;
    151 var t = new Table({initial:2, element:"anyfunc"});
    152 i1.edge = makeFinalizeObserver();
    153 i2.edge = makeFinalizeObserver();
    154 f1.edge = makeFinalizeObserver();
    155 f2.edge = makeFinalizeObserver();
    156 t.edge = makeFinalizeObserver();
    157 t.set(0, f1);
    158 t.set(1, f2);
    159 gc();
    160 assertEq(finalizeCount(), 0);
    161 f1 = f2 = null;
    162 i1.exports = null;
    163 i2.exports = null;
    164 gc();
    165 assertEq(finalizeCount(), 0);
    166 i1 = null;
    167 i2 = null;
    168 gc();
    169 assertEq(finalizeCount(), 0);
    170 t.set(0, t.get(1));
    171 gc();
    172 assertEq(finalizeCount(), 2);
    173 t.set(0, null);
    174 t.set(1, null);
    175 gc();
    176 assertEq(finalizeCount(), 4);
    177 t = null;
    178 gc();
    179 assertEq(finalizeCount(), 5);
    180 
    181 // Ensure that an instance that is only live on the stack cannot be GC even if
    182 // there are no outstanding references.
    183 resetFinalizeCount();
    184 const N = 10;
    185 var tbl = new Table({initial:N, element:"anyfunc"});
    186 tbl.edge = makeFinalizeObserver();
    187 function runTest() {
    188    tbl = null;
    189    gc();
    190    assertEq(finalizeCount(), 0);
    191    return 100;
    192 }
    193 var i = wasmEvalText(
    194    `(module
    195        (import "a" "b" (func $imp (result i32)))
    196        (func $f (param i32) (result i32) (call $imp))
    197        (export "f" (func $f))
    198    )`,
    199    {a:{b:runTest}}
    200 );
    201 i.edge = makeFinalizeObserver();
    202 tbl.set(0, i.exports.f);
    203 var m = new Module(wasmTextToBinary(`(module
    204    (import "a" "b" (table ${N} funcref))
    205    (type $i2i (func (param i32) (result i32)))
    206    (func $f (param $i i32) (result i32)
    207        (local.set $i (i32.sub (local.get $i) (i32.const 1)))
    208        (i32.add
    209            (i32.const 1)
    210            (call_indirect (type $i2i) (local.get $i) (local.get $i))))
    211    (export "f" (func $f))
    212 )`));
    213 for (var i = 1; i < N; i++) {
    214    var inst = new Instance(m, {a:{b:tbl}});
    215    inst.edge = makeFinalizeObserver();
    216    tbl.set(i, inst.exports.f);
    217 }
    218 inst = null;
    219 assertEq(tbl.get(N - 1)(N - 1), 109);
    220 gc();
    221 assertEq(finalizeCount(), N + 1);