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);