Skip to content

Commit

Permalink
Normative: Remove ToUint32 from array literal evaluation
Browse files Browse the repository at this point in the history
Previously, array literals (including spreads) had their indices and
lengths calculated with a ToUint32 operation. As Georg Neis noted
in tc39#1095, such a calculation isn't quite right, as 2**32-1 is not
an array index. These semantics are unlikely to be observable in many
current JavaScript implementations due to resource limitations, but
the strange behavior may appear in future, resource-rich
implementations.

This patch takes Allen Wirfs-Brock's suggestion to simply remove the
ToUint32 wraparounds and write to larger indices. When the length
is written to, it will throw an exception, after having exhausted
any iterators in the literal. Note that too-long Array literals throw
only as a runtime exception, not as an early error.

In the theoretical case of array indices which exceed the safe numerical
integer range, the same semantics will apply--the iterator will be
exhausted, and then the write to the length will throw. Internally, the
same index will be written repeatedly.

This patch includes appropriate use of ? and ! in modified operations.
  • Loading branch information
littledan committed Mar 2, 2018
1 parent f812bc5 commit c584571
Showing 1 changed file with 9 additions and 9 deletions.
18 changes: 9 additions & 9 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -11565,7 +11565,7 @@ <h1>Runtime Semantics: ArrayAccumulation</h1>
1. Let _padding_ be the ElisionWidth of |Elision|; if |Elision| is not present, use the numeric value zero.
1. Let _initResult_ be the result of evaluating |AssignmentExpression|.
1. Let _initValue_ be ? GetValue(_initResult_).
1. Let _created_ be CreateDataProperty(_array_, ToString(ToUint32(_nextIndex_+_padding_)), _initValue_).
1. Let _created_ be ! CreateDataProperty(_array_, ToString(_nextIndex_ + _padding_), _initValue_).
1. Assert: _created_ is *true*.
1. Return _nextIndex_+_padding_+1.
</emu-alg>
Expand All @@ -11581,7 +11581,7 @@ <h1>Runtime Semantics: ArrayAccumulation</h1>
1. Let _padding_ be the ElisionWidth of |Elision|; if |Elision| is not present, use the numeric value zero.
1. Let _initResult_ be the result of evaluating |AssignmentExpression|.
1. Let _initValue_ be ? GetValue(_initResult_).
1. Let _created_ be CreateDataProperty(_array_, ToString(ToUint32(_postIndex_+_padding_)), _initValue_).
1. Let _created_ be ! CreateDataProperty(_array_, ToString(_postIndex_ + _padding_), _initValue_).
1. Assert: _created_ is *true*.
1. Return _postIndex_+_padding_+1.
</emu-alg>
Expand All @@ -11601,7 +11601,7 @@ <h1>Runtime Semantics: ArrayAccumulation</h1>
1. Let _next_ be ? IteratorStep(_iteratorRecord_).
1. If _next_ is *false*, return _nextIndex_.
1. Let _nextValue_ be ? IteratorValue(_next_).
1. Let _status_ be CreateDataProperty(_array_, ToString(ToUint32(_nextIndex_)), _nextValue_).
1. Let _status_ be ! CreateDataProperty(_array_, ToString(_nextIndex_), _nextValue_).
1. Assert: _status_ is *true*.
1. Let _nextIndex_ be _nextIndex_ + 1.
</emu-alg>
Expand All @@ -11617,17 +11617,17 @@ <h1>Runtime Semantics: Evaluation</h1>
<emu-alg>
1. Let _array_ be ! ArrayCreate(0).
1. Let _pad_ be the ElisionWidth of |Elision|; if |Elision| is not present, use the numeric value zero.
1. Perform Set(_array_, `"length"`, ToUint32(_pad_), *false*).
1. NOTE: The above Set cannot fail because of the nature of the object returned by ArrayCreate.
1. Perform ? Set(_array_, `"length"`, _pad_, *true*).
1. NOTE: The above Set may throw in the case of an Array literal which exceeds 2<sup>32</sup>-1 elements.
1. Return _array_.
</emu-alg>
<emu-grammar>ArrayLiteral : `[` ElementList `]`</emu-grammar>
<emu-alg>
1. Let _array_ be ! ArrayCreate(0).
1. Let _len_ be the result of performing ArrayAccumulation for |ElementList| with arguments _array_ and 0.
1. ReturnIfAbrupt(_len_).
1. Perform Set(_array_, `"length"`, ToUint32(_len_), *false*).
1. NOTE: The above Set cannot fail because of the nature of the object returned by ArrayCreate.
1. Perform ? Set(_array_, `"length"`, _len_, *true*).
1. NOTE: The above Set may throw in the case of an Array literal which exceeds 2<sup>32</sup>-1 elements.
1. Return _array_.
</emu-alg>
<emu-grammar>ArrayLiteral : `[` ElementList `,` Elision? `]`</emu-grammar>
Expand All @@ -11636,8 +11636,8 @@ <h1>Runtime Semantics: Evaluation</h1>
1. Let _len_ be the result of performing ArrayAccumulation for |ElementList| with arguments _array_ and 0.
1. ReturnIfAbrupt(_len_).
1. Let _padding_ be the ElisionWidth of |Elision|; if |Elision| is not present, use the numeric value zero.
1. Perform Set(_array_, `"length"`, ToUint32(_padding_+_len_), *false*).
1. NOTE: The above Set cannot fail because of the nature of the object returned by ArrayCreate.
1. Perform ? Set(_array_, `"length"`, _padding_ + _len_, *true*).
1. NOTE: The above Set may throw in the case of an Array literal which exceeds 2<sup>32</sup>-1 elements.
1. Return _array_.
</emu-alg>
</emu-clause>
Expand Down

0 comments on commit c584571

Please sign in to comment.