summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/basic/shape-teleporting-invalidation.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/basic/shape-teleporting-invalidation.js')
-rw-r--r--js/src/jit-test/tests/basic/shape-teleporting-invalidation.js144
1 files changed, 144 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/basic/shape-teleporting-invalidation.js b/js/src/jit-test/tests/basic/shape-teleporting-invalidation.js
new file mode 100644
index 0000000000..37769bcb5a
--- /dev/null
+++ b/js/src/jit-test/tests/basic/shape-teleporting-invalidation.js
@@ -0,0 +1,144 @@
+// The shape teleporting optimization can be disabled for an object that's used
+// as prototype when either it's involved in prototype changes or it had a property
+// shadowed on another prototype object.
+
+function changeProps(o) {
+ Object.assign(o, {x: 1, y: 2, z: 3});
+ o.foo = 4;
+ delete o.x;
+}
+
+function testProtoChange() {
+ var receiver = {};
+ var A = Object.create(null);
+ var B = Object.create(A);
+
+ // Change |receiver|'s proto: receiver => B => A => null
+ // Because |receiver| is not used as a prototype object, this doesn't affect
+ // teleporting.
+ Object.setPrototypeOf(receiver, B);
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(A), false);
+ assertEq(hasInvalidatedTeleporting(B), false);
+
+ // Change B's proto to C: receiver => B => C => null
+ // Because B is used as prototype object, both A and B invalidate teleporting.
+ var C = Object.create(null);
+ Object.setPrototypeOf(B, C);
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(A), true);
+ assertEq(hasInvalidatedTeleporting(B), true);
+ assertEq(hasInvalidatedTeleporting(C), false);
+
+ // Change B's proto a second time: receiver => B => D => null
+ // Now C has teleporting invalidated too.
+ var D = Object.create(null);
+ Object.setPrototypeOf(B, D);
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(A), true);
+ assertEq(hasInvalidatedTeleporting(B), true);
+ assertEq(hasInvalidatedTeleporting(C), true);
+ assertEq(hasInvalidatedTeleporting(D), false);
+
+ // Changing properties (without shadowing) must not affect teleporting state.
+ changeProps(C);
+ changeProps(D);
+ assertEq(hasInvalidatedTeleporting(C), true);
+ assertEq(hasInvalidatedTeleporting(D), false);
+}
+testProtoChange();
+
+function testShadowingProp() {
+ // receiver => C => B => A => null
+ var A = Object.create(null);
+ var B = Object.create(A);
+ var C = Object.create(B);
+ var receiver = Object.create(C);
+
+ // Adding non-shadowing properties doesn't affect teleporting.
+ A.a = 1;
+ B.b = 1;
+ C.c = 1;
+ receiver.receiver = 1;
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), false);
+ assertEq(hasInvalidatedTeleporting(A), false);
+
+ // Objects not used as prototype can shadow properties without affecting
+ // teleporting.
+ receiver.a = 1;
+ receiver.b = 2;
+ receiver.c = 3;
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), false);
+ assertEq(hasInvalidatedTeleporting(A), false);
+
+ // Shadowing a property of B on C invalidates teleporting for B.
+ C.b = 1;
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), true);
+ assertEq(hasInvalidatedTeleporting(A), false);
+
+ // Shadowing a property of A on C invalidates teleporting for A.
+ C.a = 2;
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), true);
+ assertEq(hasInvalidatedTeleporting(A), true);
+
+ // Changing properties (without shadowing) must not affect teleporting state.
+ changeProps(C);
+ changeProps(B);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), true);
+}
+testShadowingProp();
+
+function testShadowingPropStopsAtFirst() {
+ // receiver => C => B{x,y} => A{x,y,z} => null
+ var A = Object.create(null);
+ A.x = 1;
+ A.y = 2;
+ A.z = 3;
+ var B = Object.create(A);
+ B.x = 1;
+ B.y = 2;
+ var C = Object.create(B);
+ var receiver = Object.create(C);
+
+ // Teleporting is supported.
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), false);
+ assertEq(hasInvalidatedTeleporting(A), false);
+
+ // Shadowing a property of B (and A) on C.
+ // This invalidates teleporting for B but not for A, because the search stops
+ // at B.
+ C.x = 1;
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), true);
+ assertEq(hasInvalidatedTeleporting(A), false);
+
+ // "y" is similar.
+ C.y = 2;
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), true);
+ assertEq(hasInvalidatedTeleporting(A), false);
+
+ // "z" is only defined on A, so now A is affected.
+ C.z = 3;
+ assertEq(hasInvalidatedTeleporting(receiver), false);
+ assertEq(hasInvalidatedTeleporting(C), false);
+ assertEq(hasInvalidatedTeleporting(B), true);
+ assertEq(hasInvalidatedTeleporting(A), true);
+}
+testShadowingPropStopsAtFirst();
+
+// Ensure teleporting properties on Object.prototype is still possible.
+assertEq(hasInvalidatedTeleporting(Object.prototype), false);