tor-browser

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

shape-teleporting-invalidation.js (5617B)


      1 // The shape teleporting optimization can be disabled for an object that's used
      2 // as prototype when either it's involved in prototype changes or it had a property
      3 // shadowed on another prototype object.
      4 
      5 let usingDictionary = getPrefValue("experimental.dictionary_teleporting");
      6 
      7 if (usingDictionary) {
      8  // Use this to cause us to exceed the reshape limit to ensure we test the
      9  // invalidation path.
     10  function exceed_dictionary_limit() {
     11    let o = Object.create(null);
     12    o = Object.create(o);
     13    o = Object.create(o);
     14    let l = o;
     15    o = Object.create(o);
     16    let u = o;
     17    o = Object.create(o);
     18    o = Object.create(o);
     19 
     20    print("Attempt")
     21    for (let i = 0; i < 10_000; i++) {
     22      Object.setPrototypeOf(u, null);
     23      Object.setPrototypeOf(u, l);
     24    }
     25  }
     26  exceed_dictionary_limit();
     27 }
     28 
     29 function changeProps(o) {
     30  Object.assign(o, { x: 1, y: 2, z: 3 });
     31  o.foo = 4;
     32  delete o.x;
     33 }
     34 
     35 function testProtoChange() {
     36  var receiver = {};
     37  var A = Object.create(null);
     38  var B = Object.create(A);
     39 
     40  // Change |receiver|'s proto: receiver => B => A => null
     41  // Because |receiver| is not used as a prototype object, this doesn't affect
     42  // teleporting.
     43  Object.setPrototypeOf(receiver, B);
     44  assertEq(hasInvalidatedTeleporting(receiver), false);
     45  assertEq(hasInvalidatedTeleporting(A), false);
     46  assertEq(hasInvalidatedTeleporting(B), false);
     47 
     48  // Change B's proto to C: receiver => B => C => null
     49  // Because B is used as prototype object, both A and B invalidate teleporting.
     50  var C = Object.create(null);
     51  Object.setPrototypeOf(B, C);
     52  assertEq(hasInvalidatedTeleporting(receiver), false);
     53  assertEq(hasInvalidatedTeleporting(A), true);
     54  assertEq(hasInvalidatedTeleporting(B), true);
     55  assertEq(hasInvalidatedTeleporting(C), false);
     56 
     57  // Change B's proto a second time: receiver => B => D => null
     58  // Now C has teleporting invalidated too.
     59  var D = Object.create(null);
     60  Object.setPrototypeOf(B, D);
     61  assertEq(hasInvalidatedTeleporting(receiver), false);
     62  assertEq(hasInvalidatedTeleporting(A), true);
     63  assertEq(hasInvalidatedTeleporting(B), true);
     64  assertEq(hasInvalidatedTeleporting(C), true);
     65  assertEq(hasInvalidatedTeleporting(D), false);
     66 
     67  // Changing properties (without shadowing) must not affect teleporting state.
     68  changeProps(C);
     69  changeProps(D);
     70  assertEq(hasInvalidatedTeleporting(C), true);
     71  assertEq(hasInvalidatedTeleporting(D), false);
     72 }
     73 testProtoChange();
     74 
     75 function testShadowingProp() {
     76  // receiver => C => B => A => null
     77  var A = Object.create(null);
     78  var B = Object.create(A);
     79  var C = Object.create(B);
     80  var receiver = Object.create(C);
     81 
     82  // Adding non-shadowing properties doesn't affect teleporting.
     83  A.a = 1;
     84  B.b = 1;
     85  C.c = 1;
     86  receiver.receiver = 1;
     87  assertEq(hasInvalidatedTeleporting(receiver), false);
     88  assertEq(hasInvalidatedTeleporting(C), false);
     89  assertEq(hasInvalidatedTeleporting(B), false);
     90  assertEq(hasInvalidatedTeleporting(A), false);
     91 
     92  // Objects not used as prototype can shadow properties without affecting
     93  // teleporting.
     94  receiver.a = 1;
     95  receiver.b = 2;
     96  receiver.c = 3;
     97  assertEq(hasInvalidatedTeleporting(receiver), false);
     98  assertEq(hasInvalidatedTeleporting(C), false);
     99  assertEq(hasInvalidatedTeleporting(B), false);
    100  assertEq(hasInvalidatedTeleporting(A), false);
    101 
    102  // Shadowing a property of B on C invalidates teleporting for B.
    103  C.b = 1;
    104  assertEq(hasInvalidatedTeleporting(receiver), false);
    105  assertEq(hasInvalidatedTeleporting(C), false);
    106  assertEq(hasInvalidatedTeleporting(B), true);
    107  assertEq(hasInvalidatedTeleporting(A), false);
    108 
    109  // Shadowing a property of A on C invalidates teleporting for A.
    110  C.a = 2;
    111  assertEq(hasInvalidatedTeleporting(receiver), false);
    112  assertEq(hasInvalidatedTeleporting(C), false);
    113  assertEq(hasInvalidatedTeleporting(B), true);
    114  assertEq(hasInvalidatedTeleporting(A), true);
    115 
    116  // Changing properties (without shadowing) must not affect teleporting state.
    117  changeProps(C);
    118  changeProps(B);
    119  assertEq(hasInvalidatedTeleporting(C), false);
    120  assertEq(hasInvalidatedTeleporting(B), true);
    121 }
    122 testShadowingProp();
    123 
    124 function testShadowingPropStopsAtFirst() {
    125  // receiver => C => B{x,y} => A{x,y,z} => null
    126  var A = Object.create(null);
    127  A.x = 1;
    128  A.y = 2;
    129  A.z = 3;
    130  var B = Object.create(A);
    131  B.x = 1;
    132  B.y = 2;
    133  var C = Object.create(B);
    134  var receiver = Object.create(C);
    135 
    136  // Teleporting is supported.
    137  assertEq(hasInvalidatedTeleporting(receiver), false);
    138  assertEq(hasInvalidatedTeleporting(C), false);
    139  assertEq(hasInvalidatedTeleporting(B), false);
    140  assertEq(hasInvalidatedTeleporting(A), false);
    141 
    142  // Shadowing a property of B (and A) on C.
    143  // This invalidates teleporting for B but not for A, because the search stops
    144  // at B.
    145  C.x = 1;
    146  assertEq(hasInvalidatedTeleporting(receiver), false);
    147  assertEq(hasInvalidatedTeleporting(C), false);
    148  assertEq(hasInvalidatedTeleporting(B), true);
    149  assertEq(hasInvalidatedTeleporting(A), false);
    150 
    151  // "y" is similar.
    152  C.y = 2;
    153  assertEq(hasInvalidatedTeleporting(receiver), false);
    154  assertEq(hasInvalidatedTeleporting(C), false);
    155  assertEq(hasInvalidatedTeleporting(B), true);
    156  assertEq(hasInvalidatedTeleporting(A), false);
    157 
    158  // "z" is only defined on A, so now A is affected.
    159  C.z = 3;
    160  assertEq(hasInvalidatedTeleporting(receiver), false);
    161  assertEq(hasInvalidatedTeleporting(C), false);
    162  assertEq(hasInvalidatedTeleporting(B), true);
    163  assertEq(hasInvalidatedTeleporting(A), true);
    164 }
    165 testShadowingPropStopsAtFirst();
    166 
    167 // Ensure teleporting properties on Object.prototype is still possible.
    168 assertEq(hasInvalidatedTeleporting(Object.prototype), false);