Commit c35c40ae authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[literals] Document that literals with simple getters cause dict-properties

Drive-by-fix: increase coverage in object literals test.

Change-Id: Iccfdf35b29229f63b3e8c1d961bee56ee03da688
Reviewed-on: https://chromium-review.googlesource.com/751661Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49105}
parent eee9fcbc
// 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.
(function TestModifedPrototypeInObjectLiteral() {
// The prototype chain should not be used if the definition
// happens in the object literal.
Object.defineProperty(Object.prototype, 'c', {
get: function () {
return 21;
},
set: function () {
}
});
var o = {};
o.c = 7;
assertEquals(21, o.c);
var l = {c: 7};
assertEquals(7, l.c);
delete Object.prototype.c;
})();
...@@ -27,14 +27,14 @@ ...@@ -27,14 +27,14 @@
// Flags: --allow-natives-syntax // Flags: --allow-natives-syntax
function runTest(fn) { function runLiteralsTest(fn) {
// The first run creates an copy directly from the boilerplate decsription. // The first run creates an copy directly from the boilerplate decsription.
fn(); fn();
// The second run will create the boilerplate. // The second run will create the boilerplate.
fn(); fn();
// The third run might copy literals directly in the stub. // The third run might copy literals directly in the stub.
fn(); fn();
// Several invocations more to trigger map deprecations. // Several invocations more to trigger potential map deprecations.
fn(); fn();
fn(); fn();
fn(); fn();
...@@ -43,7 +43,25 @@ function runTest(fn) { ...@@ -43,7 +43,25 @@ function runTest(fn) {
fn(); fn();
} }
function testBasicPrototype() {
runLiteralsTest(function testEmptyObjectLiteral() {
let object = {};
assertTrue(%HasFastProperties(object));
assertTrue(%HasObjectElements(object ));
assertTrue(%HasHoleyElements(object));
assertEquals([], Object.keys(object));
});
runLiteralsTest(function testSingleGetter() {
let object = { get foo() { return 1 } };
// For now getters create dict mode objects.
assertFalse(%HasFastProperties(object));
assertTrue(%HasObjectElements(object ));
assertTrue(%HasHoleyElements(object));
assertEquals(['foo'], Object.keys(object));
});
runLiteralsTest(function testBasicPrototype() {
var obj = { var obj = {
a: 7, a: 7,
b: { x: 12, y: 24 }, b: { x: 12, y: 24 },
...@@ -56,11 +74,9 @@ function testBasicPrototype() { ...@@ -56,11 +74,9 @@ function testBasicPrototype() {
assertEquals('Zebra', obj.c); assertEquals('Zebra', obj.c);
assertEquals(Object.getPrototypeOf(obj), Object.prototype); assertEquals(Object.getPrototypeOf(obj), Object.prototype);
assertEquals(Object.getPrototypeOf(obj.b), Object.prototype); assertEquals(Object.getPrototypeOf(obj.b), Object.prototype);
}; });
testBasicPrototype();
testBasicPrototype();
function testDynamicValue() { runLiteralsTest(function testDynamicValue() {
var z = 24; var z = 24;
var obj2 = { var obj2 = {
...@@ -73,11 +89,9 @@ function testDynamicValue() { ...@@ -73,11 +89,9 @@ function testDynamicValue() {
assertEquals(12, obj2.b.x); assertEquals(12, obj2.b.x);
assertEquals(24, obj2.b.y); assertEquals(24, obj2.b.y);
assertEquals('Zebra', obj2.c); assertEquals('Zebra', obj2.c);
} });
testDynamicValue();
testDynamicValue();
(function testMultipleInstatiations() { runLiteralsTest(function testMultipleInstatiations() {
var arr = []; var arr = [];
for (var i = 0; i < 2; i++) { for (var i = 0; i < 2; i++) {
arr[i] = { arr[i] = {
...@@ -90,174 +104,182 @@ testDynamicValue(); ...@@ -90,174 +104,182 @@ testDynamicValue();
arr[0].b.x = 2; arr[0].b.x = 2;
assertEquals(2, arr[0].b.x); assertEquals(2, arr[0].b.x);
assertEquals(12, arr[1].b.x); assertEquals(12, arr[1].b.x);
})(); });
function testSparseElements() {
let sa1 = { runLiteralsTest(function TestSparseElements() {
'0': { x: 12, y: 24 }, function createSparseElements() {
'1000000': { x: 1, y: 2 } let sa1 = {
}; '0': { x: 12, y: 24 },
%HeapObjectVerify(sa1); '1000000': { x: 1, y: 2 }
assertEquals(['0', '1000000'], Object.keys(sa1)); };
assertEquals(12, sa1[0].x); %HeapObjectVerify(sa1);
assertEquals(24, sa1[0].y); assertEquals(['0', '1000000'], Object.keys(sa1));
assertEquals(['x', 'y'], Object.keys(sa1[0])); assertEquals(12, sa1[0].x);
assertEquals(1, sa1[1000000].x); assertEquals(24, sa1[0].y);
assertEquals(2, sa1[1000000].y); assertEquals(['x', 'y'], Object.keys(sa1[0]));
assertEquals(['x', 'y'], Object.keys(sa1[1000000])); assertEquals(1, sa1[1000000].x);
assertEquals(Object.prototype, Object.getPrototypeOf(sa1)); assertEquals(2, sa1[1000000].y);
assertEquals(Object.prototype, Object.getPrototypeOf(sa1[0])); assertEquals(['x', 'y'], Object.keys(sa1[1000000]));
assertEquals(Object.prototype, Object.getPrototypeOf(sa1[1000000])); assertEquals(Object.prototype, Object.getPrototypeOf(sa1));
return sa1; assertEquals(Object.prototype, Object.getPrototypeOf(sa1[0]));
} assertEquals(Object.prototype, Object.getPrototypeOf(sa1[1000000]));
return sa1;
let object = testSparseElements();
// modify the object and rerun the test, ensuring the literal didn't change.
object[1] = "a";
object[0].x = -12;
testSparseElements();
// Test that non-constant literals work.
var n = new Object();
function makeNonConstantArray() { return [ [ n ] ]; }
var a = makeNonConstantArray();
var b = makeNonConstantArray();
assertTrue(a[0][0] === n);
assertTrue(b[0][0] === n);
assertFalse(a[0] === b[0]);
a[0][0].foo = "bar";
assertEquals("bar", n.foo);
function makeNonConstantObject() { return { a: { b: n } }; }
a = makeNonConstantObject();
b = makeNonConstantObject();
assertFalse(a.a === b.a);
assertTrue(a.a.b === b.a.b);
a.a.b.bar = "foo";
assertEquals("foo", n.bar);
// Test that exceptions for regexps still hold.
function makeRegexpInArray() { return [ [ /a*/, {} ] ]; }
a = makeRegexpInArray();
b = makeRegexpInArray();
assertFalse(a[0][0] === b[0][0]);
assertFalse(a[0][1] === b[0][1]);
assertEquals(Array.prototype, Object.getPrototypeOf(a));
assertEquals(Array.prototype, Object.getPrototypeOf(b));
assertEquals(Array.prototype, Object.getPrototypeOf(a[0]));
assertEquals(Array.prototype, Object.getPrototypeOf(b[0]));
assertEquals(RegExp.prototype, Object.getPrototypeOf(a[0][0]));
assertEquals(RegExp.prototype, Object.getPrototypeOf(b[0][0]));
function makeRegexpInObject() { return { a: { b: /b*/, c: {} } }; }
a = makeRegexpInObject();
b = makeRegexpInObject();
assertFalse(a.a.b === b.a.b);
assertFalse(a.a.c === b.a.c);
assertEquals(RegExp.prototype, Object.getPrototypeOf(a.a.b));
assertEquals(RegExp.prototype, Object.getPrototypeOf(b.a.b));
// Test keywords are valid as property names in initializers and dot-access.
var keywords = [
"break",
"case",
"catch",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"false",
"finally",
"for",
"function",
"if",
"in",
"instanceof",
"new",
"null",
"return",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with"
];
function testKeywordProperty(keyword) {
var exception = false;
try {
// Sanity check that what we get is a keyword.
eval("var " + keyword + " = 42;");
} catch (e) {
exception = true;
} }
assertTrue(exception);
// Simple property, read and write.
var x = eval("({" + keyword + ": 42})");
assertEquals(42, x[keyword]);
assertEquals(42, eval("x." + keyword));
eval("x." + keyword + " = 37");
assertEquals(37, x[keyword]);
assertEquals(37, eval("x." + keyword));
// Getter/setter property, read and write.
var y = eval("({value : 42, get " + keyword + "(){return this.value}," +
" set " + keyword + "(v) { this.value = v; }})");
assertEquals(42, y[keyword]);
assertEquals(42, eval("y." + keyword));
eval("y." + keyword + " = 37");
assertEquals(37, y[keyword]);
assertEquals(37, eval("y." + keyword));
// Quoted keyword works is read back by unquoted as well.
var z = eval("({\"" + keyword + "\": 42})");
assertEquals(42, z[keyword]);
assertEquals(42, eval("z." + keyword));
// Function property, called. let object = createSparseElements();
var was_called; // modify the object and rerun the test, ensuring the literal didn't change.
function test_call() { this.was_called = true; was_called = true; } object[1] = "a";
var w = eval("({" + keyword + ": test_call, was_called: false})"); object[0].x = -12;
eval("w." + keyword + "();"); createSparseElements();
assertTrue(was_called); });
assertTrue(w.was_called);
runLiteralsTest(function TestNonConstLiterals() {
// Function property, constructed. // Test that non-constant literals work.
function construct() { this.constructed = true; } var n = new Object();
var v = eval("({" + keyword + ": construct})");
var vo = eval("new v." + keyword + "()"); function makeNonConstantArray() { return [ [ n ] ]; }
assertTrue(vo instanceof construct);
assertTrue(vo.constructed); var a = makeNonConstantArray();
} var b = makeNonConstantArray();
assertTrue(a[0][0] === n);
assertTrue(b[0][0] === n);
assertFalse(a[0] === b[0]);
a[0][0].foo = "bar";
assertEquals("bar", n.foo);
function makeNonConstantObject() { return { a: { b: n } }; }
a = makeNonConstantObject();
b = makeNonConstantObject();
assertFalse(a.a === b.a);
assertTrue(a.a.b === b.a.b);
a.a.b.bar = "foo";
assertEquals("foo", n.bar);
});
runLiteralsTest(function TestRegexpInArray() {
// Test that exceptions for regexps still hold.
function makeRegexpInArray() { return [ [ /a*/, {} ] ]; }
let a = makeRegexpInArray();
let b = makeRegexpInArray();
assertFalse(a[0][0] === b[0][0]);
assertFalse(a[0][1] === b[0][1]);
assertEquals(Array.prototype, Object.getPrototypeOf(a));
assertEquals(Array.prototype, Object.getPrototypeOf(b));
assertEquals(Array.prototype, Object.getPrototypeOf(a[0]));
assertEquals(Array.prototype, Object.getPrototypeOf(b[0]));
assertEquals(RegExp.prototype, Object.getPrototypeOf(a[0][0]));
assertEquals(RegExp.prototype, Object.getPrototypeOf(b[0][0]));
});
runLiteralsTest(function TestRegexpInObject() {
function makeRegexpInObject() { return { a: { b: /b*/, c: {} } }; }
let a = makeRegexpInObject();
let b = makeRegexpInObject();
assertFalse(a.a.b === b.a.b);
assertFalse(a.a.c === b.a.c);
assertEquals(RegExp.prototype, Object.getPrototypeOf(a.a.b));
assertEquals(RegExp.prototype, Object.getPrototypeOf(b.a.b));
});
runLiteralsTest(function TestKeywordProperties() {
// Test keywords are valid as property names in initializers and dot-access.
var keywords = [
"break",
"case",
"catch",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"false",
"finally",
"for",
"function",
"if",
"in",
"instanceof",
"new",
"null",
"return",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with"
];
function testKeywordProperty(keyword) {
var exception = false;
try {
// Sanity check that what we get is a keyword.
eval("var " + keyword + " = 42;");
} catch (e) {
exception = true;
}
assertTrue(exception);
// Simple property, read and write.
var x = eval("({" + keyword + ": 42})");
assertEquals(42, x[keyword]);
assertEquals(42, eval("x." + keyword));
eval("x." + keyword + " = 37");
assertEquals(37, x[keyword]);
assertEquals(37, eval("x." + keyword));
// Getter/setter property, read and write.
var y = eval("({value : 42, get " + keyword + "(){return this.value}," +
" set " + keyword + "(v) { this.value = v; }})");
assertEquals(42, y[keyword]);
assertEquals(42, eval("y." + keyword));
eval("y." + keyword + " = 37");
assertEquals(37, y[keyword]);
assertEquals(37, eval("y." + keyword));
// Quoted keyword works is read back by unquoted as well.
var z = eval("({\"" + keyword + "\": 42})");
assertEquals(42, z[keyword]);
assertEquals(42, eval("z." + keyword));
// Function property, called.
var was_called;
function test_call() { this.was_called = true; was_called = true; }
var w = eval("({" + keyword + ": test_call, was_called: false})");
eval("w." + keyword + "();");
assertTrue(was_called);
assertTrue(w.was_called);
// Function property, constructed.
function construct() { this.constructed = true; }
var v = eval("({" + keyword + ": construct})");
var vo = eval("new v." + keyword + "()");
assertTrue(vo instanceof construct);
assertTrue(vo.constructed);
}
for (var i = 0; i < keywords.length; i++) { for (var i = 0; i < keywords.length; i++) {
testKeywordProperty(keywords[i]); testKeywordProperty(keywords[i]);
} }
});
function TestSimpleElements() { runLiteralsTest(function TestSimpleElements() {
var o = { 0:"zero", 1:"one", 2:"two" }; var o = { 0:"zero", 1:"one", 2:"two" };
assertEquals({0:"zero", 1:"one", 2:"two"}, o); assertEquals({0:"zero", 1:"one", 2:"two"}, o);
o[0] = 0; o[0] = 0;
assertEquals({0:0, 1:"one", 2:"two"}, o); assertEquals({0:0, 1:"one", 2:"two"}, o);
} });
TestSimpleElements();
TestSimpleElements();
function TestNumericNames() { runLiteralsTest(function TestNumericNames() {
var o = { var o = {
1: 1, 1: 1,
2.: 2, 2.: 2,
...@@ -278,11 +300,9 @@ function TestNumericNames() { ...@@ -278,11 +300,9 @@ function TestNumericNames() {
}; };
%HeapObjectVerify(o); %HeapObjectVerify(o);
assertEquals(['1.2', '1.3'], Object.keys(o)); assertEquals(['1.2', '1.3'], Object.keys(o));
} });
TestNumericNames();
TestNumericNames();
function TestDictionaryElements() { runLiteralsTest(function TestDictionaryElements() {
let o = {1024: true}; let o = {1024: true};
assertTrue(%HasDictionaryElements(o)); assertTrue(%HasDictionaryElements(o));
assertEquals(true, o[1024]); assertEquals(true, o[1024]);
...@@ -300,13 +320,9 @@ function TestDictionaryElements() { ...@@ -300,13 +320,9 @@ function TestDictionaryElements() {
%HeapObjectVerify(o2); %HeapObjectVerify(o2);
o2[1024] = "test"; o2[1024] = "test";
assertEquals(["test"], Object.values(o2)); assertEquals(["test"], Object.values(o2));
} });
TestDictionaryElements();
TestDictionaryElements();
%OptimizeFunctionOnNextCall(TestDictionaryElements);
TestDictionaryElements();
function TestLiteralElementsKind() { runLiteralsTest(function TestLiteralElementsKind() {
let o = {0:0, 1:1, 2:2}; let o = {0:0, 1:1, 2:2};
assertTrue(%HasObjectElements(o)); assertTrue(%HasObjectElements(o));
assertTrue(%HasHoleyElements(o)); assertTrue(%HasHoleyElements(o));
...@@ -329,13 +345,9 @@ function TestLiteralElementsKind() { ...@@ -329,13 +345,9 @@ function TestLiteralElementsKind() {
assertTrue(%HasHoleyElements(o)); assertTrue(%HasHoleyElements(o));
assertTrue(%HasDictionaryElements({0xFFFFFF:true})); assertTrue(%HasDictionaryElements({0xFFFFFF:true}));
} });
TestLiteralElementsKind();
TestLiteralElementsKind();
%OptimizeFunctionOnNextCall(TestLiteralElementsKind);
TestLiteralElementsKind();
function TestNonNumberElementValues() { runLiteralsTest(function TestNonNumberElementValues() {
var o = { var o = {
1: true, 1: true,
2: false, 2: false,
...@@ -387,15 +399,10 @@ function TestNonNumberElementValues() { ...@@ -387,15 +399,10 @@ function TestNonNumberElementValues() {
}; };
%HeapObjectVerify(o4); %HeapObjectVerify(o4);
assertEquals(['1', '2', '3', '4', 'a', 'b'], Object.keys(o4)); assertEquals(['1', '2', '3', '4', 'a', 'b'], Object.keys(o4));
} })
TestNonNumberElementValues();
TestNonNumberElementValues();
TestNonNumberElementValues();
%OptimizeFunctionOnNextCall(TestNonNumberElementValues);
TestNonNumberElementValues();
function numericGetters() { runLiteralsTest(function numericGetters() {
function TestNumericNamesGetter(expectedKeys, object) { function TestNumericNamesGetter(expectedKeys, object) {
assertEquals(expectedKeys, Object.keys(object)); assertEquals(expectedKeys, Object.keys(object));
expectedKeys.forEach(function(key) { expectedKeys.forEach(function(key) {
...@@ -418,11 +425,9 @@ function numericGetters() { ...@@ -418,11 +425,9 @@ function numericGetters() {
get 1.2() {}, get 1.2() {},
get 1.30() {} get 1.30() {}
}); });
} });
numericGetters();
numericGetters();
function numericSetters() { runLiteralsTest(function numericSetters() {
function TestNumericNamesSetter(expectedKeys, object) { function TestNumericNamesSetter(expectedKeys, object) {
assertEquals(expectedKeys, Object.keys(object)); assertEquals(expectedKeys, Object.keys(object));
expectedKeys.forEach(function(key) { expectedKeys.forEach(function(key) {
...@@ -445,12 +450,10 @@ function numericSetters() { ...@@ -445,12 +450,10 @@ function numericSetters() {
set 1.2(_) {; }, set 1.2(_) {; },
set 1.30(_) {; } set 1.30(_) {; }
}); });
}; });
numericSetters();
numericSetters();
function TestProxyWithDefinitionInObjectLiteral() { runLiteralsTest(function TestProxyWithDefinitionInObjectLiteral() {
// Trap for set should not be used if the definition // Trap for set should not be used if the definition
// happens in the object literal. // happens in the object literal.
var handler = { var handler = {
...@@ -467,11 +470,9 @@ function TestProxyWithDefinitionInObjectLiteral() { ...@@ -467,11 +470,9 @@ function TestProxyWithDefinitionInObjectLiteral() {
var l = new Proxy({[prop]: 'my value'}, handler); var l = new Proxy({[prop]: 'my value'}, handler);
assertEquals('my value', l[prop]); assertEquals('my value', l[prop]);
}; });
TestProxyWithDefinitionInObjectLiteral();
TestProxyWithDefinitionInObjectLiteral();
(function TestLiteralWithNullProto() { runLiteralsTest(function TestLiteralWithNullProto() {
// Assume dictionary usage for simple null prototype literal objects, // Assume dictionary usage for simple null prototype literal objects,
// this is equivalent to Object.create(null). Note that on the first call // this is equivalent to Object.create(null). Note that on the first call
// the literal boilerplate is initialized, and from then on we use a the // the literal boilerplate is initialized, and from then on we use a the
...@@ -498,9 +499,9 @@ TestProxyWithDefinitionInObjectLiteral(); ...@@ -498,9 +499,9 @@ TestProxyWithDefinitionInObjectLiteral();
testDictModeNullProtoLiteral(() => ({a:1, b:2, __proto__:null})); testDictModeNullProtoLiteral(() => ({a:1, b:2, __proto__:null}));
testDictModeNullProtoLiteral(() => ({["a"]: 1, __proto__: null})); testDictModeNullProtoLiteral(() => ({["a"]: 1, __proto__: null}));
testDictModeNullProtoLiteral(() => ({a: Object, __proto__: null})); testDictModeNullProtoLiteral(() => ({a: Object, __proto__: null}));
})(); });
function testNestedNullProtoLiteral() { runLiteralsTest(function testNestedNullProtoLiteral() {
let obj; let obj;
obj = { foo: { __proto__:Math, bar:"barValue"}}; obj = { foo: { __proto__:Math, bar:"barValue"}};
assertTrue(%HasFastProperties(obj)); assertTrue(%HasFastProperties(obj));
...@@ -523,12 +524,10 @@ function testNestedNullProtoLiteral() { ...@@ -523,12 +524,10 @@ function testNestedNullProtoLiteral() {
assertEquals("barValue", obj.foo.bar); assertEquals("barValue", obj.foo.bar);
obj.foo.bar = "barValue2"; obj.foo.bar = "barValue2";
assertEquals("barValue2", obj.foo.bar); assertEquals("barValue2", obj.foo.bar);
} });
testNestedNullProtoLiteral();
testNestedNullProtoLiteral();
function TestSlowLiteralOptimized() { runLiteralsTest(function TestSlowLiteralOptimized() {
function f() { function f() {
return {__proto__:null, bar:"barValue"}; return {__proto__:null, bar:"barValue"};
} }
...@@ -548,11 +547,9 @@ function TestSlowLiteralOptimized() { ...@@ -548,11 +547,9 @@ function TestSlowLiteralOptimized() {
assertEquals("barValue", obj.bar); assertEquals("barValue", obj.bar);
obj.bar = "barValue2"; obj.bar = "barValue2";
assertEquals("barValue2", obj.bar); assertEquals("barValue2", obj.bar);
}; });
TestSlowLiteralOptimized();
TestSlowLiteralOptimized();
(function TestLargeDictionaryLiteral() { runLiteralsTest(function TestLargeDictionaryLiteral() {
// Create potential large-space object literal. // Create potential large-space object literal.
function createObject() { function createObject() {
// This literal has least kMaxRegularHeapObjectSize / 64 number of // This literal has least kMaxRegularHeapObjectSize / 64 number of
...@@ -1568,27 +1565,4 @@ TestSlowLiteralOptimized(); ...@@ -1568,27 +1565,4 @@ TestSlowLiteralOptimized();
assertFalse(%HasFastProperties(object2)); assertFalse(%HasFastProperties(object2));
assertEquals(Object.getPrototypeOf(object2), null); assertEquals(Object.getPrototypeOf(object2), null);
assertEquals(keys, Object.keys(object2)); assertEquals(keys, Object.keys(object2));
})(); });
(function TestPrototypeInObjectLiteral() {
// The prototype chain should not be used if the definition
// happens in the object literal.
Object.defineProperty(Object.prototype, 'c', {
get: function () {
return 21;
},
set: function () {
}
});
var o = {};
o.c = 7;
assertEquals(21, o.c);
var l = {c: 7};
assertEquals(7, l.c);
delete Object.prototype.c;
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment