Skip to content

Commit e427300

Browse files
ajkleinCommit bot
authored andcommitted
Properly handle holes following spreads in array literals
Before this change, the spread desugaring would naively call `%AppendElement($R, the_hole)` and in some cases $R would have a non-holey elements kind, putting the array into the bad state of exposing holes to author code. This patch avoids calling %AppendElement with a hole, instead simply incrementing $R.length when it sees a hole in the literal (this is safe because $R is known to be an Array). The existing logic for elements transitions takes care of giving the array a holey ElementsKind. BUG=chromium:644215 Review-Url: https://codereview.chromium.org/2321533003 Cr-Commit-Position: refs/heads/master@{#39294}
1 parent cd86053 commit e427300

4 files changed

Lines changed: 41 additions & 9 deletions

File tree

src/ast/ast-value-factory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ class AstValue : public ZoneObject {
296296
F(eval, "eval") \
297297
F(function, "function") \
298298
F(get_space, "get ") \
299+
F(length, "length") \
299300
F(let, "let") \
300301
F(native, "native") \
301302
F(new_target, ".new.target") \

src/parsing/parser.cc

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4979,15 +4979,32 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
49794979
if (spread == nullptr) {
49804980
// If the element is not a spread, we're adding a single:
49814981
// %AppendElement($R, value)
4982-
ZoneList<Expression*>* append_element_args = NewExpressionList(2);
4983-
append_element_args->Add(factory()->NewVariableProxy(result), zone());
4984-
append_element_args->Add(value, zone());
4985-
do_block->statements()->Add(
4986-
factory()->NewExpressionStatement(
4987-
factory()->NewCallRuntime(Runtime::kAppendElement,
4988-
append_element_args, kNoSourcePosition),
4989-
kNoSourcePosition),
4990-
zone());
4982+
// or, in case of a hole,
4983+
// ++($R.length)
4984+
if (!value->IsLiteral() ||
4985+
!value->AsLiteral()->raw_value()->IsTheHole()) {
4986+
ZoneList<Expression*>* append_element_args = NewExpressionList(2);
4987+
append_element_args->Add(factory()->NewVariableProxy(result), zone());
4988+
append_element_args->Add(value, zone());
4989+
do_block->statements()->Add(
4990+
factory()->NewExpressionStatement(
4991+
factory()->NewCallRuntime(Runtime::kAppendElement,
4992+
append_element_args,
4993+
kNoSourcePosition),
4994+
kNoSourcePosition),
4995+
zone());
4996+
} else {
4997+
Property* length_property = factory()->NewProperty(
4998+
factory()->NewVariableProxy(result),
4999+
factory()->NewStringLiteral(ast_value_factory()->length_string(),
5000+
kNoSourcePosition),
5001+
kNoSourcePosition);
5002+
CountOperation* count_op = factory()->NewCountOperation(
5003+
Token::INC, true /* prefix */, length_property, kNoSourcePosition);
5004+
do_block->statements()->Add(
5005+
factory()->NewExpressionStatement(count_op, kNoSourcePosition),
5006+
zone());
5007+
}
49915008
} else {
49925009
// If it's a spread, we're adding a for/of loop iterating through it.
49935010
Variable* each = NewTemporary(ast_value_factory()->dot_for_string());

src/runtime/runtime-object.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ RUNTIME_FUNCTION(Runtime_AppendElement) {
418418

419419
CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
420420
CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
421+
CHECK(!value->IsTheHole(isolate));
421422

422423
uint32_t index;
423424
CHECK(array->length()->ToArrayIndex(&index));
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2016 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --allow-natives-syntax
6+
7+
var arr = [...[],,];
8+
assertTrue(%HasFastHoleyElements(arr));
9+
assertEquals(1, arr.length);
10+
assertFalse(arr.hasOwnProperty(0));
11+
assertEquals(undefined, arr[0]);
12+
// Should not crash.
13+
assertThrows(() => arr[0][0], TypeError);

0 commit comments

Comments
 (0)