// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Flags: --allow-natives-syntax assertEquals(this.__proto__, Object.prototype); function TestAddingPropertyToGlobalPrototype() { let foo_func_called = 0; let bar_func_called = 0; function Foo() {} Foo.prototype.func = function() { ++foo_func_called; } delete this.func; this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Foo. o.func(); // Add the property to Bar which is a Global-mode prototype between o // and Foo. In the next iteration, it's looked up from Bar. if (i == 9) { Bar.prototype.func = function() { ++bar_func_called; } } } assertEquals(10, foo_func_called); assertEquals(1, bar_func_called); } TestAddingPropertyToGlobalPrototype(); // Same as TestAddingPropertyToGlobalPrototype, but using o["foo"] access // instead of o.foo. function TestAddingPropertyToGlobalPrototype2() { let foo_func_called = 0; let bar_func_called = 0; let name = "func"; function Foo() {} Foo.prototype[name] = function() { ++foo_func_called; } delete this[name]; this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Foo. o[name](); // Add the property to Bar which is a Global-mode prototype between o // and Foo. In the next iteration, it's looked up from Bar. if (i == 9) { Bar.prototype[name] = function() { ++bar_func_called; } } } assertEquals(10, foo_func_called); assertEquals(1, bar_func_called); } TestAddingPropertyToGlobalPrototype2(); function TestAddingPropertyToGlobalPrototype_DefineProperty() { let foo_func_called = 0; let bar_func_called = 0; function Foo() {} Foo.prototype.func = function() { ++foo_func_called; } delete this.func; this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Foo. o.func(); // Add the property to Bar which is a Global-mode prototype between o // and Foo. In the next iteration, it's looked up from Bar. if (i == 9) { Object.defineProperty(Bar.prototype, "func", { value: function() { ++bar_func_called; }, configurable:true }); } } assertEquals(10, foo_func_called); assertEquals(1, bar_func_called); } TestAddingPropertyToGlobalPrototype_DefineProperty(); function TestAddingAccessorPropertyToGlobalPrototype() { let foo_func_called = 0; let bar_func_called = 0; function Foo() {} Foo.prototype.func = function() { ++foo_func_called; } delete this.func; this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Foo. o.func(); // Add the property to Bar which is a Global-mode prototype between o // and Foo. In the next iteration, it's looked up from Bar. if (i == 9) { Object.defineProperty(Bar.prototype, "func", { get: function() { return function() { ++bar_func_called; }}, configurable: true }); } } assertEquals(10, foo_func_called); assertEquals(1, bar_func_called); } TestAddingAccessorPropertyToGlobalPrototype(); function TestRemovingPropertyFromGlobalPrototype() { let foo_func_called = 0; let bar_func_called = 0; function Foo() {} Foo.prototype.func = function() { ++foo_func_called; } delete this.func; this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; Bar.prototype.func = function() { ++bar_func_called; } let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Bar. o.func(); // Remove the property from Bar which is a Global-mode prototype between // o and Foo. In the next iteration, it's looked up from Foo. if (i == 9) { delete Bar.prototype.func; } } assertEquals(1, foo_func_called); assertEquals(10, bar_func_called); } TestRemovingPropertyFromGlobalPrototype(); // Same as TestRemovingPropertyFromGlobalPrototype, but using o["foo"] access // instead of o.foo. function TestRemovingPropertyFromGlobalPrototype2() { let foo_func_called = 0; let bar_func_called = 0; let name = "func"; function Foo() {} Foo.prototype[name] = function() { ++foo_func_called; } this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; Bar.prototype[name] = function() { ++bar_func_called; } let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Bar. o[name](); // Remove the property from Bar which is a Global-mode prototype between // o and Foo. In the next iteration, it's looked up from Foo. if (i == 9) { delete Bar.prototype[name]; } } assertEquals(1, foo_func_called); assertEquals(10, bar_func_called); } TestRemovingPropertyFromGlobalPrototype2(); function TestAddingPropertyToGlobalPrototype_MonomorphicDot() { function DoMonomorphicStoreToPrototypeDot(p, f, do_delete=true) { p.func = f; if (do_delete) { delete p.func; } } let foo_func_called = 0; let bar_func_called = 0; function Foo() {} Foo.prototype.func = function() { ++foo_func_called; } delete this.func; this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; function bar_func() { ++bar_func_called; } DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func); DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func); DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func); let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Foo. o.func(); // Add the property to Bar which is a Global-mode prototype between o // and Foo. In the next iteration, it's looked up from Bar. if (i == 9) { DoMonomorphicStoreToPrototypeDot(Bar.prototype, bar_func, false); } } assertEquals(10, foo_func_called); assertEquals(1, bar_func_called); } TestAddingPropertyToGlobalPrototype_MonomorphicDot(); function TestAddingPropertyToGlobalPrototype_MonomorphicBrackets() { function DoMonomorphicStoreToPrototypeBrackets(p, name, f, do_delete=true) { p[name] = f; if (do_delete) { delete p[name]; } } let foo_func_called = 0; let bar_func_called = 0; let name = "func"; function Foo() {} Foo.prototype[name] = function() { ++foo_func_called; } delete this[name]; this.__proto__ = Foo.prototype; function Bar() {} Bar.prototype = this; function bar_func() { ++bar_func_called; } DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func); DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func); DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func); let o = new Bar(); for (let i = 0; i < 11; ++i) { // First, the property is looked up from Foo. o.func(); // Add the property to Bar which is a Global-mode prototype between o // and Foo. In the next iteration, it's looked up from Bar. if (i == 9) { DoMonomorphicStoreToPrototypeBrackets(Bar.prototype, name, bar_func, false); } } assertEquals(10, foo_func_called); assertEquals(1, bar_func_called); } TestAddingPropertyToGlobalPrototype_MonomorphicBrackets(); function TestReconfiguringDataToAccessor() { let setter_called = 0; let name = "prop"; delete this[name]; this.__proto__ = Object.prototype; function Bar() {} Bar.prototype = this; Object.defineProperty(Bar.prototype, name, {value: 1000, writable: true, configurable: true}); for (let i = 0; i < 11; ++i) { let obj1 = new Bar(); if (i < 10) { assertEquals(1000, obj1.prop); } else { assertEquals(3000, obj1.prop); } // Add the property into the object. obj1.prop = 2000; if (i < 10) { assertEquals(2000, obj1.prop); } else { assertEquals(3000, obj1.prop); } // Make "prop" an accessor property in the prototype. if (i == 9) { Object.defineProperty(Bar.prototype, name, {get: () => 3000, set: function(val) { ++setter_called; }}); } } assertEquals(1, setter_called); } TestReconfiguringDataToAccessor();