Source code

Revision control

Copy as Markdown

Other Tools

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