summaryrefslogtreecommitdiff
path: root/deps/v8/test/mjsunit/dictionary-prototypes.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/mjsunit/dictionary-prototypes.js')
-rw-r--r--deps/v8/test/mjsunit/dictionary-prototypes.js409
1 files changed, 409 insertions, 0 deletions
diff --git a/deps/v8/test/mjsunit/dictionary-prototypes.js b/deps/v8/test/mjsunit/dictionary-prototypes.js
new file mode 100644
index 0000000000..109f8d42a6
--- /dev/null
+++ b/deps/v8/test/mjsunit/dictionary-prototypes.js
@@ -0,0 +1,409 @@
+// 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
+
+function EnsureDictionaryMode(obj, properties=1500) {
+ for (let i = 0; i < properties; i++) {
+ obj["x" + i] = 0;
+ }
+ assertFalse(%HasFastProperties(obj));
+}
+
+function EnsureAlmostDictionaryMode(obj) {
+ for (let i = 0; i < 1020; i++) {
+ obj["x" + i] = 0;
+ }
+}
+
+function TestAddingPropertyToDictionaryPrototype() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+
+ function Foo() {}
+ Foo.prototype.func = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+
+ 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 dictionary-mode prototype between o
+ // and Foo. In the next iteration, it's looked up from Bar.
+ if (i == 9) {
+ // The UNINITIALIZED -> PREMONOMORPHIC transition of StoreIC should
+ // properly invalidate prototype chains.
+ Bar.prototype.func = function() { ++bar_func_called; }
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingPropertyToDictionaryPrototype();
+
+// Same as TestAddingPropertyToDictionaryPrototype, but using o["foo"] access
+// instead of o.foo.
+function TestAddingPropertyToDictionaryPrototype2() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+ let name = "func";
+
+ function Foo() {}
+ Foo.prototype[name] = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+
+ 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 dictionary-mode prototype between o
+ // and Foo. In the next iteration, it's looked up from Bar.
+ if (i == 9) {
+ // The UNINITIALIZED -> PREMONOMORPHIC transition of KeyedStoreIC should
+ // properly invalidate prototype chains.
+ Bar.prototype[name] = function() { ++bar_func_called; }
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingPropertyToDictionaryPrototype2();
+
+function TestAddingPropertyToDictionaryPrototype_DefineProperty() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+
+ function Foo() {}
+ Foo.prototype.func = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+
+ 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 dictionary-mode prototype between o
+ // and Foo. In the next iteration, it's looked up from Bar.
+ if (i == 9) {
+ // The runtime should properly invalidate prototype chains.
+ Object.defineProperty(Bar.prototype, "func", {value: function() { ++bar_func_called; }});
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingPropertyToDictionaryPrototype_DefineProperty();
+
+function TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+
+ function Foo() {}
+ Foo.prototype.func = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ // The magic number ensures that the next addition to the dictionary will
+ // trigger the slow path.
+ EnsureDictionaryMode(Bar.prototype, 2731);
+
+ 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 dictionary-mode prototype between o
+ // and Foo. In the next iteration, it's looked up from Bar.
+ if (i == 9) {
+ // -> slow path for dictionary add
+ Bar.prototype.func = function() { ++bar_func_called; }
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath();
+
+function TestAddingAccessorPropertyToDictionaryPrototype() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+
+ function Foo() {}
+ Foo.prototype.func = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+
+ 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 dictionary-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; }}});
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingAccessorPropertyToDictionaryPrototype();
+
+function TestRemovingPropertyFromDictionaryPrototype() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+
+ function Foo() {}
+ Foo.prototype.func = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+ 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 dictionary-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);
+}
+
+TestRemovingPropertyFromDictionaryPrototype();
+
+// Same as TestRemovingPropertyFromDictionaryPrototype, but using o["foo"] access
+// instead of o.foo.
+function TestRemovingPropertyFromDictionaryPrototype2() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+ let name = "func";
+
+ function Foo() {}
+ Foo.prototype[name] = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+ 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 dictionary-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);
+}
+
+TestRemovingPropertyFromDictionaryPrototype2();
+
+function TestAddingPropertyToDictionaryPrototype_Monomorphic() {
+ function DoMonomorphicStoreToPrototype(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; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+
+ function bar_func() {
+ ++bar_func_called;
+ }
+ DoMonomorphicStoreToPrototype(Bar.prototype, bar_func);
+ DoMonomorphicStoreToPrototype(Bar.prototype, bar_func);
+ DoMonomorphicStoreToPrototype(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 dictionary-mode prototype between o
+ // and Foo. In the next iteration, it's looked up from Bar.
+ if (i == 9) {
+ DoMonomorphicStoreToPrototype(Bar.prototype, bar_func, false);
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingPropertyToDictionaryPrototype_Monomorphic();
+
+function TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic() {
+ function DoMonomorphicKeyedStoreToPrototype(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; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureDictionaryMode(Bar.prototype);
+
+ function bar_func() {
+ ++bar_func_called;
+ }
+ DoMonomorphicKeyedStoreToPrototype(Bar.prototype, name, bar_func);
+ DoMonomorphicKeyedStoreToPrototype(Bar.prototype, name, bar_func);
+ DoMonomorphicKeyedStoreToPrototype(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 dictionary-mode prototype between o
+ // and Foo. In the next iteration, it's looked up from Bar.
+ if (i == 9) {
+ DoMonomorphicKeyedStoreToPrototype(Bar.prototype, name, bar_func, false);
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic();
+
+// Like TestAddingPropertyToDictionaryPrototype, except that the prototype isn't
+// in dictionary mode yet, but turns to dictionary mode after the interesting
+// property is added.
+function TestAddingPropertyToAlmostDictionaryPrototype() {
+ let foo_func_called = 0;
+ let bar_func_called = 0;
+
+ function Foo() {}
+ Foo.prototype.func = function() { ++foo_func_called; }
+
+ function Bar() {}
+ Bar.prototype = Object.create(Foo.prototype);
+ EnsureAlmostDictionaryMode(Bar.prototype);
+
+ let o = new Bar();
+ for (let i = 0; i < 2; ++i) {
+ o.x0;
+ }
+ assertTrue(%HasFastProperties(Bar.prototype));
+
+ for (let i = 0; i < 11; ++i) {
+ // First, the property is looked up from Foo.
+ o.func();
+
+ // Add the property to Bar which will now turn permanently into dictionary
+ // mode. In the next iteration, it's looked up from Bar.
+ if (i == 9) {
+ Bar.prototype.func = function() { ++bar_func_called; }
+ assertFalse(%HasFastProperties(Bar.prototype));
+ }
+ }
+
+ assertEquals(10, foo_func_called);
+ assertEquals(1, bar_func_called);
+}
+
+TestAddingPropertyToAlmostDictionaryPrototype();
+
+function TestReconfiguringDataToAccessor() {
+ let setter_called = 0;
+
+ function Bar() {}
+ EnsureDictionaryMode(Bar.prototype);
+ let name = "prop";
+ 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();