Optimize spread call for sealed, frozen objects

Also add mjsunit test for spread call with non-extensible objects

Micro-benchmark JSTests/ObjectFreeze shows ~7x improvement

Before:
SpreadCall
SpreadCall-Numbers(Score): 239

After:
SpreadCall
SpreadCall-Numbers(Score): 1461

Bug: v8:6831
Change-Id: Icefd89ad790ac159b7f0617d0a012eefd90d3b1d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1614296
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#61669}
This commit is contained in:
Z Duong Nguyen-Huu 2019-05-16 12:53:04 -07:00 committed by Commit Bot
parent 3bebee412f
commit 9ccad33c97
5 changed files with 72 additions and 4 deletions

View File

@ -151,7 +151,7 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
TNode<Int32T> kind = LoadMapElementsKind(arguments_list_map);
GotoIf(Int32GreaterThan(kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
GotoIf(IsElementsKindGreaterThan(kind, LAST_FROZEN_ELEMENTS_KIND),
&if_runtime);
Branch(Word32And(kind, Int32Constant(1)), &if_holey_array, &if_done);
}
@ -306,11 +306,13 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
var_elements = LoadElements(spread_array);
// Check elements kind of {spread}.
GotoIf(Int32LessThan(spread_kind, Int32Constant(PACKED_DOUBLE_ELEMENTS)),
GotoIf(IsElementsKindLessThanOrEqual(spread_kind, HOLEY_ELEMENTS),
&if_smiorobject);
GotoIf(IsElementsKindLessThanOrEqual(spread_kind, LAST_FAST_ELEMENTS_KIND),
&if_double);
Branch(
Int32GreaterThan(spread_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
&if_generic, &if_double);
IsElementsKindLessThanOrEqual(spread_kind, LAST_FROZEN_ELEMENTS_KIND),
&if_smiorobject, &if_generic);
}
BIND(&if_generic);

View File

@ -14,6 +14,9 @@ function tests() {
assertEquals(3, countArgs(...[1.1, 2, 3])); // Double
assertEquals(4, countArgs(...[1.1, 2, , 3])); // HoleyDouble
assertEquals(3, countArgs(...[{valueOf: () => 0}, 1.1, '2'])); // Object
assertEquals(3, countArgs(...Object.freeze([{valueOf: () => 0}, 1.1, '2']))); // Frozen Object
assertEquals(3, countArgs(...Object.seal([{valueOf: () => 0}, 1.1, '2']))); // Sealed Object
assertEquals(3, countArgs(...Object.preventExtensions([{valueOf: () => 0}, 1.1, '2']))); // Non-extensible Object
assertEquals(
4, countArgs(...[{valueOf: () => 0}, 1.1, , '2'])); // HoleyObject

View File

@ -756,3 +756,24 @@ arr.length = 3;
assertEquals(arr.length, 2);
arr.length = 0;
assertEquals(arr.length, 2);
// Spread with array
var arr = ['a', 'b', 'c'];
Object.freeze(arr);
var arrSpread = [...arr];
assertEquals(arrSpread.length, arr.length);
assertEquals(arrSpread[0], 'a');
assertEquals(arrSpread[1], 'b');
assertEquals(arrSpread[2], 'c');
// Spread with array-like
function returnArgs() {
return Object.freeze(arguments);
}
var arrLike = returnArgs('a', 'b', 'c');
assertTrue(Object.isFrozen(arrLike));
var arrSpread = [...arrLike];
assertEquals(arrSpread.length, arrLike.length);
assertEquals(arrSpread[0], 'a');
assertEquals(arrSpread[1], 'b');
assertEquals(arrSpread[2], 'c');

View File

@ -420,3 +420,24 @@ arr.length = 3;
assertEquals(arr.length, 3);
arr.length = 0;
assertEquals(arr.length, 0);
// Spread with array
var arr = ['a', 'b', 'c'];
Object.preventExtensions(arr);
var arrSpread = [...arr];
assertEquals(arrSpread.length, arr.length);
assertEquals(arrSpread[0], 'a');
assertEquals(arrSpread[1], 'b');
assertEquals(arrSpread[2], 'c');
// Spread with array-like
function returnArgs() {
return Object.preventExtensions(arguments);
}
var arrLike = returnArgs('a', 'b', 'c');
assertFalse(Object.isExtensible(arrLike));
var arrSpread = [...arrLike];
assertEquals(arrSpread.length, arrLike.length);
assertEquals(arrSpread[0], 'a');
assertEquals(arrSpread[1], 'b');
assertEquals(arrSpread[2], 'c');

View File

@ -728,3 +728,24 @@ arr.length = 3;
assertEquals(arr.length, 3);
arr.length = 0;
assertEquals(arr.length, 1);
// Spread with array
var arr = ['a', 'b', 'c'];
Object.seal(arr);
var arrSpread = [...arr];
assertEquals(arrSpread.length, arr.length);
assertEquals(arrSpread[0], 'a');
assertEquals(arrSpread[1], 'b');
assertEquals(arrSpread[2], 'c');
// Spread with array-like
function returnArgs() {
return Object.seal(arguments);
}
var arrLike = returnArgs('a', 'b', 'c');
assertTrue(Object.isSealed(arrLike));
var arrSpread = [...arrLike];
assertEquals(arrSpread.length, arrLike.length);
assertEquals(arrSpread[0], 'a');
assertEquals(arrSpread[1], 'b');
assertEquals(arrSpread[2], 'c');