tor-browser

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

finalizationRegistry-with-symbol-keys.js (6825B)


      1 // |jit-test| --enable-symbols-as-weakmap-keys
      2 
      3 function checkPropertyDescriptor(obj, property, writable, enumerable,
      4                                 configurable) {
      5  let desc = Object.getOwnPropertyDescriptor(obj, property);
      6  assertEq(typeof desc, "object");
      7  assertEq(desc.writable, writable);
      8  assertEq(desc.enumerable, enumerable);
      9  assertEq(desc.configurable, configurable);
     10 }
     11 
     12 function assertThrowsTypeError(thunk) {
     13  let error;
     14  try {
     15    thunk();
     16  } catch (e) {
     17    error = e;
     18  }
     19  assertEq(error instanceof TypeError, true);
     20 }
     21 
     22 // 3.1 The FinalizationRegistry Constructor
     23 assertEq(typeof this.FinalizationRegistry, "function");
     24 
     25 // 3.1.1 FinalizationRegistry ( cleanupCallback ) 
     26 assertThrowsTypeError(() => new FinalizationRegistry());
     27 assertThrowsTypeError(() => new FinalizationRegistry(1));
     28 new FinalizationRegistry(x => 0);
     29 
     30 // 3.2 Properties of the FinalizationRegistry Constructor
     31 assertEq(Object.getPrototypeOf(FinalizationRegistry), Function.prototype);
     32 
     33 // 3.2.1 FinalizationRegistry.prototype
     34 checkPropertyDescriptor(FinalizationRegistry, 'prototype', false, false, false);
     35 
     36 // 3.3 Properties of the FinalizationRegistry Prototype Object
     37 let proto = FinalizationRegistry.prototype;
     38 assertEq(Object.getPrototypeOf(proto), Object.prototype);
     39 
     40 // 3.3.1 FinalizationRegistry.prototype.constructor
     41 assertEq(proto.constructor, FinalizationRegistry);
     42 
     43 // 3.3.2 FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] )
     44 assertEq(proto.hasOwnProperty('register'), true);
     45 assertEq(typeof proto.register, 'function');
     46 
     47 // 3.3.3 FinalizationRegistry.prototype.unregister ( unregisterToken )
     48 assertEq(proto.hasOwnProperty('unregister'), true);
     49 assertEq(typeof proto.unregister, 'function');
     50 
     51 // 3.3.4 FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
     52 assertEq(proto.hasOwnProperty('cleanupSome'), true);
     53 assertEq(typeof proto.cleanupSome, 'function');
     54 
     55 // 3.3.5 FinalizationRegistry.prototype [ @@toStringTag ]
     56 assertEq(proto[Symbol.toStringTag], "FinalizationRegistry");
     57 checkPropertyDescriptor(proto, Symbol.toStringTag, false, false, true);
     58 
     59 // 3.4 Properties of FinalizationRegistry Instances
     60 let registry = new FinalizationRegistry(x => 0);
     61 assertEq(Object.getPrototypeOf(registry), proto);
     62 assertEq(Object.getOwnPropertyNames(registry).length, 0);
     63 
     64 let heldValues = [];
     65 registry = new FinalizationRegistry(value => {
     66  heldValues.push(value);
     67 });
     68 
     69 // Test a single target.
     70 heldValues = [];
     71 registry.register({}, 42);
     72 gc();
     73 drainJobQueue();
     74 assertEq(heldValues.length, 1);
     75 assertEq(heldValues[0], 42);
     76 
     77 // Test multiple targets.
     78 heldValues = [];
     79 for (let i = 0; i < 100; i++) {
     80  registry.register({}, i);
     81 }
     82 gc();
     83 drainJobQueue();
     84 assertEq(heldValues.length, 100);
     85 heldValues = heldValues.sort((a, b) => a - b);
     86 for (let i = 0; i < 100; i++) {
     87  assertEq(heldValues[i], i);
     88 }
     89 
     90 // Test a single object in multiple registries
     91 heldValues = [];
     92 let heldValues2 = [];
     93 let registry2 = new FinalizationRegistry(value => {
     94  heldValues2.push(value);
     95 });
     96 {
     97  let object = {};
     98  registry.register(object, 1);
     99  registry2.register(object, 2);
    100  object = null;
    101 }
    102 gc();
    103 drainJobQueue();
    104 assertEq(heldValues.length, 1);
    105 assertEq(heldValues[0], 1);
    106 assertEq(heldValues2.length, 1);
    107 assertEq(heldValues2[0], 2);
    108 
    109 // Unregister a single target.
    110 heldValues = [];
    111 let token = {};
    112 registry.register({}, 1, token);
    113 registry.unregister(token);
    114 gc();
    115 drainJobQueue();
    116 assertEq(heldValues.length, 0);
    117 
    118 // Unregister multiple targets.
    119 heldValues = [];
    120 let token2 = {};
    121 registry.register({}, 1, token);
    122 registry.register({}, 2, token2);
    123 registry.register({}, 3, token);
    124 registry.register({}, 4, token2);
    125 registry.unregister(token);
    126 gc();
    127 drainJobQueue();
    128 assertEq(heldValues.length, 2);
    129 heldValues = heldValues.sort((a, b) => a - b);
    130 assertEq(heldValues[0], 2);
    131 assertEq(heldValues[1], 4);
    132 
    133 // Watch object in another global.
    134 let other = newGlobal({newCompartment: true});
    135 heldValues = [];
    136 registry.register(evalcx('({})', other), 1);
    137 gc();
    138 drainJobQueue();
    139 assertEq(heldValues.length, 1);
    140 assertEq(heldValues[0], 1);
    141 
    142 // Pass heldValues from another global.
    143 let heldValue = evalcx('{}', other);
    144 heldValues = [];
    145 registry.register({}, heldValue);
    146 gc();
    147 drainJobQueue();
    148 assertEq(heldValues.length, 1);
    149 assertEq(heldValues[0], heldValue);
    150 
    151 // Pass unregister token from another global.
    152 token = evalcx('({})', other);
    153 heldValues = [];
    154 registry.register({}, 1, token);
    155 gc();
    156 drainJobQueue();
    157 assertEq(heldValues.length, 1);
    158 assertEq(heldValues[0], 1);
    159 heldValues = [];
    160 registry.register({}, 1, token);
    161 registry.unregister(token);
    162 gc();
    163 drainJobQueue();
    164 assertEq(heldValues.length, 0);
    165 
    166 // FinalizationRegistry is designed to be subclassable.
    167 class MyRegistry extends FinalizationRegistry {
    168  constructor(callback) {
    169    super(callback);
    170  }
    171 }
    172 let r2 = new MyRegistry(value => {
    173  heldValues.push(value);
    174 });
    175 heldValues = [];
    176 r2.register({}, 42);
    177 gc();
    178 drainJobQueue();
    179 assertEq(heldValues.length, 1);
    180 assertEq(heldValues[0], 42);
    181 
    182 // Test cleanupSome.
    183 heldValues = [];
    184 let r5 = new FinalizationRegistry(v => heldValues.push(v));
    185 r5.register({}, 1);
    186 r5.register({}, 2);
    187 r5.register({}, 3);
    188 gc();
    189 r5.cleanupSome();
    190 assertEq(heldValues.length, 3);
    191 heldValues = heldValues.sort((a, b) => a - b);
    192 assertEq(heldValues[0], 1);
    193 assertEq(heldValues[1], 2);
    194 assertEq(heldValues[2], 3);
    195 
    196 // Test trying to call cleanupSome in callback.
    197 let r6 = new FinalizationRegistry(x => {
    198  r6.cleanupSome();
    199 });
    200 r6.register({}, 1);
    201 gc();
    202 drainJobQueue();
    203 
    204 // Test trying to call cleanupSome in callback with multiple values.
    205 let callbackCounter7 = 0;
    206 let r7 = new FinalizationRegistry(x => {
    207  callbackCounter7++;
    208  r7.cleanupSome();
    209 });
    210 r7.register({}, 1);
    211 r7.register({}, 2);
    212 r7.register({}, 3);
    213 r7.register({}, 4);
    214 gc();
    215 drainJobQueue();
    216 assertEq(callbackCounter7, 4);
    217 
    218 // Test that targets don't keep the finalization registry alive.
    219 let target = {};
    220 registry = new FinalizationRegistry(value => undefined);
    221 registry.register(target, 1);
    222 let weakRef = new WeakRef(registry);
    223 registry = undefined;
    224 assertEq(typeof weakRef.deref(), 'object');
    225 drainJobQueue();
    226 gc();
    227 assertEq(weakRef.deref(), undefined);
    228 assertEq(typeof target, 'object');
    229 
    230 // Test that targets don't keep the finalization registry alive when also
    231 // used as the unregister token.
    232 registry = new FinalizationRegistry(value => undefined);
    233 registry.register(target, 1, target);
    234 weakRef = new WeakRef(registry);
    235 registry = undefined;
    236 assertEq(typeof weakRef.deref(), 'object');
    237 drainJobQueue();
    238 gc();
    239 assertEq(weakRef.deref(), undefined);
    240 assertEq(typeof target, 'object');
    241 
    242 // Test that cleanup doesn't happen if the finalization registry dies.
    243 // todo: ok per spec if they both die in the same GC?
    244 heldValues = [];
    245 new FinalizationRegistry(value => {
    246  heldValues.push(value);
    247 }).register({}, 1);
    248 gc();
    249 drainJobQueue();
    250 assertEq(heldValues.length, 0);