From 11292be321fb7e8412fb588db4597ec5c6e863ab Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 7 Apr 2021 07:16:09 +0000 Subject: [PATCH] Bug 1700052 part 16 - Add tests for accessor properties. r=jonco Differential Revision: https://phabricator.services.mozilla.com/D110263 --- dom/bindings/test/mochitest.ini | 1 + dom/bindings/test/test_proxy_accessors.html | 78 +++++++++++ .../tests/cacheir/getter-setter-guards1.js | 64 +++++++++ .../tests/cacheir/getter-setter-guards2.js | 130 ++++++++++++++++++ 4 files changed, 273 insertions(+) create mode 100644 dom/bindings/test/test_proxy_accessors.html create mode 100644 js/src/jit-test/tests/cacheir/getter-setter-guards1.js create mode 100644 js/src/jit-test/tests/cacheir/getter-setter-guards2.js diff --git a/dom/bindings/test/mochitest.ini b/dom/bindings/test/mochitest.ini index 1f12fcf2a298..7b1df7006995 100644 --- a/dom/bindings/test/mochitest.ini +++ b/dom/bindings/test/mochitest.ini @@ -49,6 +49,7 @@ tags = webrtc [test_named_getter_enumerability.html] [test_Object.prototype_props.html] [test_proxy_expandos.html] +[test_proxy_accessors.html] [test_returnUnion.html] skip-if = debug == false [test_usvstring.html] diff --git a/dom/bindings/test/test_proxy_accessors.html b/dom/bindings/test/test_proxy_accessors.html new file mode 100644 index 000000000000..9474369688fe --- /dev/null +++ b/dom/bindings/test/test_proxy_accessors.html @@ -0,0 +1,78 @@ + + + + + + Test for Bug 1700052 + + + + +Mozilla Bug 1700052 +

+
+
+
+
+ + diff --git a/js/src/jit-test/tests/cacheir/getter-setter-guards1.js b/js/src/jit-test/tests/cacheir/getter-setter-guards1.js new file mode 100644 index 000000000000..9ca64dd7da07 --- /dev/null +++ b/js/src/jit-test/tests/cacheir/getter-setter-guards1.js @@ -0,0 +1,64 @@ +// Objects with same shape but different getter/setter. +function testOwnProp() { + var count = 0; + var objects = [{get x() { count += 1; }, set x(v) { count += 2; }}, + {get x() { count += 3; }, set x(v) { count += 4; }}, + {get x() { count += 5; }, set x(v) { count += 6; }}]; + assertEq(shapeOf(objects[0]), shapeOf(objects[1])); + assertEq(shapeOf(objects[0]), shapeOf(objects[2])); + for (var i = 0; i < 150; i++) { + var o = objects[i % objects.length]; + o.x++; + } + assertEq(count, 1050); +} +testOwnProp(); + +// Ensure optimized TypedArray length properly deoptimizes when the getter is +// redefined. +function testTypedArrayLength() { + var ta = new Int32Array(10); + var lengthHolder = Object.getPrototypeOf(Int32Array.prototype); + for (var i = 0; i < 150; i++) { + assertEq(ta.length, i <= 100 ? 10 : (i <= 130 ? "foo" : "bar")); + assertEq(ta.byteLength, 40); + assertEq(ta.byteOffset, 0); + if (i === 100) { + var desc = Object.getOwnPropertyDescriptor(lengthHolder, "length"); + desc.get = () => "foo"; + Object.defineProperty(lengthHolder, "length", desc); + } + if (i === 130) { + var desc = Object.getOwnPropertyDescriptor(lengthHolder, "length"); + desc.get = () => "bar"; + Object.defineProperty(lengthHolder, "length", desc); + } + } +} +testTypedArrayLength(); + +// Native accessors on the global object. Redefine a few times and ensure the +// right function is called. Use |useWindowProxy: false| to allow optimizing all +// native getters. +function testGlobalProp() { + var g = newGlobal({useWindowProxy: false}); + g.evaluate("" + function test() { + var arr = [Math, Object]; + var expected = 0; + for (var i = 0; i < 150; i++) { + assertEq(timesAccessed, i <= 100 ? i + 1 : (i > 130 ? Infinity : NaN)); + if (i === 100) { + var desc = Object.getOwnPropertyDescriptor(this, "timesAccessed"); + desc.get = Math.abs; + Object.defineProperty(this, "timesAccessed", desc); + } + if (i === 130) { + var desc = Object.getOwnPropertyDescriptor(this, "timesAccessed"); + desc.get = Math.min; + Object.defineProperty(this, "timesAccessed", desc); + } + } + }); + g.evaluate("test()"); +} +testGlobalProp(); diff --git a/js/src/jit-test/tests/cacheir/getter-setter-guards2.js b/js/src/jit-test/tests/cacheir/getter-setter-guards2.js new file mode 100644 index 000000000000..1f6e79cce7f0 --- /dev/null +++ b/js/src/jit-test/tests/cacheir/getter-setter-guards2.js @@ -0,0 +1,130 @@ +function testRedefineGetter() { + var callGetter = function(o) { + return o.x; + }; + + var proto = {get foo() {}, bar: 1}; + var obj = Object.create(proto); + + // Add "x" getter on the prototype. Warm up the IC. + var count1 = 0; + Object.defineProperty(proto, "x", {get: function(v) { + count1++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callGetter(obj); + } + assertEq(count1, 20); + + // Redefine "x" with a different getter. Ensure the new getter is called. + var count2 = 0; + Object.defineProperty(proto, "x", {get: function() { + count2++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callGetter(obj); + } + assertEq(count1, 20); + assertEq(count2, 20); +} +testRedefineGetter(); + +function testRedefineSetter() { + var callSetter = function(o) { + o.x = 1; + }; + + var proto = {get foo() {}, bar: 1}; + var obj = Object.create(proto); + + // Add "x" setter on the prototype. Warm up the IC. + var count1 = 0; + Object.defineProperty(proto, "x", {set: function(v) { + count1++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callSetter(obj); + } + assertEq(count1, 20); + + // Redefine "x" with a different setter. Ensure the new setter is called. + var count2 = 0; + Object.defineProperty(proto, "x", {set: function() { + count2++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callSetter(obj); + } + assertEq(count1, 20); + assertEq(count2, 20); +} +testRedefineSetter(); + +function testDeleteAdd() { + var callGetter = function(o) { + return o.x; + }; + + var proto = {get foo() {}, bar: 1}; + var obj = Object.create(proto); + + // Add "x" getter on the prototype. Warm up the IC. + var count1 = 0; + Object.defineProperty(proto, "x", {get: function() { + count1++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callGetter(obj); + } + assertEq(count1, 20); + + // Delete the getter. + delete proto.x; + + // Add "x" back with a different getter. Ensure the new getter is called. + var count2 = 0; + Object.defineProperty(proto, "x", {get: function() { + count2++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callGetter(obj); + } + assertEq(count1, 20); + assertEq(count2, 20); +} +testDeleteAdd(); + +function testAccessorToDataAndBack() { + var callGetter = function(o) { + return o.x; + }; + + var proto = {get foo() {}, bar: 1}; + var obj = Object.create(proto); + + // Add "x" getter on the prototype. Warm up the IC. + var count1 = 0; + Object.defineProperty(proto, "x", {get: function() { + count1++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callGetter(obj); + } + assertEq(count1, 20); + + // Turn the getter into a data property. + Object.defineProperty(proto, "x", {configurable: true, value: 123}); + + // Turn the data property into a (different) getter. Ensure the new getter is + // called. + var count2 = 0; + Object.defineProperty(proto, "x", {get: function() { + count2++; + }, configurable: true}); + for (var i = 0; i < 20; i++) { + callGetter(obj); + } + assertEq(count1, 20); + assertEq(count2, 20); +} +testAccessorToDataAndBack();