From 9ccad33c977f124e29254e1b7a614fed80bf2b9a Mon Sep 17 00:00:00 2001 From: Z Duong Nguyen-Huu Date: Thu, 16 May 2019 12:53:04 -0700 Subject: [PATCH] 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 Commit-Queue: Z Nguyen-Huu Cr-Commit-Position: refs/heads/master@{#61669} --- src/builtins/builtins-call-gen.cc | 10 ++++++---- test/mjsunit/compiler/spread-call.js | 3 +++ test/mjsunit/object-freeze.js | 21 +++++++++++++++++++++ test/mjsunit/object-prevent-extensions.js | 21 +++++++++++++++++++++ test/mjsunit/object-seal.js | 21 +++++++++++++++++++++ 5 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/builtins/builtins-call-gen.cc b/src/builtins/builtins-call-gen.cc index 0721bb7d14..e793481ffa 100644 --- a/src/builtins/builtins-call-gen.cc +++ b/src/builtins/builtins-call-gen.cc @@ -151,7 +151,7 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike( TNode 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); diff --git a/test/mjsunit/compiler/spread-call.js b/test/mjsunit/compiler/spread-call.js index 0a8527ed76..12234edaf3 100644 --- a/test/mjsunit/compiler/spread-call.js +++ b/test/mjsunit/compiler/spread-call.js @@ -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 diff --git a/test/mjsunit/object-freeze.js b/test/mjsunit/object-freeze.js index 78259b1fd9..19297605f4 100644 --- a/test/mjsunit/object-freeze.js +++ b/test/mjsunit/object-freeze.js @@ -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'); diff --git a/test/mjsunit/object-prevent-extensions.js b/test/mjsunit/object-prevent-extensions.js index d84a84a013..ccbf32f13c 100644 --- a/test/mjsunit/object-prevent-extensions.js +++ b/test/mjsunit/object-prevent-extensions.js @@ -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'); diff --git a/test/mjsunit/object-seal.js b/test/mjsunit/object-seal.js index 05635579bb..895605a865 100644 --- a/test/mjsunit/object-seal.js +++ b/test/mjsunit/object-seal.js @@ -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');