@@ -3082,32 +3082,8 @@ static bool CopyArrayElements(JSContext* cx, HandleObject obj, uint64_t begin,
30823082// Helpers for array_splice_impl() and array_to_spliced()
30833083//
30843084// Initialize variables common to splice() and toSpliced():
3085- // - GetActualStart() returns the index at which to start deleting elements.
30863085// - GetItemCount() returns the number of new elements being added.
30873086// - GetActualDeleteCount() returns the number of elements being deleted.
3088- static bool GetActualStart (JSContext* cx, HandleValue start, uint64_t len,
3089- uint64_t * result) {
3090- MOZ_ASSERT (len < DOUBLE_INTEGRAL_PRECISION_LIMIT);
3091-
3092- // Steps from proposal: https://github.com/tc39/proposal-change-array-by-copy
3093- // Array.prototype.toSpliced()
3094-
3095- // Step 3. Let relativeStart be ? ToIntegerOrInfinity(start).
3096- double relativeStart;
3097- if (!ToInteger (cx, start, &relativeStart)) {
3098- return false ;
3099- }
3100-
3101- // Steps 4-5. If relativeStart is -∞, let actualStart be 0.
3102- // Else if relativeStart < 0, let actualStart be max(len + relativeStart, 0).
3103- if (relativeStart < 0 ) {
3104- *result = uint64_t (std::max (double (len) + relativeStart, 0.0 ));
3105- } else {
3106- // Step 6. Else, let actualStart be min(relativeStart, len).
3107- *result = uint64_t (std::min (relativeStart, double (len)));
3108- }
3109- return true ;
3110- }
31113087
31123088static uint32_t GetItemCount (const CallArgs& args) {
31133089 if (args.length () < 2 ) {
@@ -3124,9 +3100,6 @@ static bool GetActualDeleteCount(JSContext* cx, const CallArgs& args,
31243100 MOZ_ASSERT (actualStart <= len);
31253101 MOZ_ASSERT (insertCount == GetItemCount (args));
31263102
3127- // Steps from proposal: https://github.com/tc39/proposal-change-array-by-copy
3128- // Array.prototype.toSpliced()
3129-
31303103 if (args.length () < 1 ) {
31313104 // Step 8. If start is not present, then let actualDeleteCount be 0.
31323105 *actualDeleteCount = 0 ;
@@ -3181,10 +3154,13 @@ static bool array_splice_impl(JSContext* cx, unsigned argc, Value* vp,
31813154 /* Steps 3-6. */
31823155 /* actualStart is the index after which elements will be
31833156 deleted and/or new elements will be added */
3184- uint64_t actualStart;
3185- if (!GetActualStart (cx, args.get (0 ), len, &actualStart)) {
3186- return false ;
3157+ uint64_t actualStart = 0 ;
3158+ if (args.hasDefined (0 )) {
3159+ if (!ToIntegerIndex (cx, args[0 ], len, &actualStart)) {
3160+ return false ;
3161+ }
31873162 }
3163+ MOZ_ASSERT (actualStart <= len);
31883164
31893165 /* Steps 7-10.*/
31903166 /* itemCount is the number of elements being added */
@@ -3498,8 +3474,8 @@ static void CopyDenseElementsFillHoles(ArrayObject* arr, NativeObject* nobj,
34983474 MOZ_ASSERT (arr->denseElementsArePacked ());
34993475}
35003476
3501- // https://github.com/tc39/proposal-change-array-by-copy
3502- // Array.prototype.toSpliced( )
3477+ // ES2026 draft rev a562082b031d89d00ee667181ce8a6158656bd4b
3478+ // 23.1.3.35 Array.prototype.toSpliced ( start, skipCount, ...items )
35033479static bool array_toSpliced (JSContext* cx, unsigned argc, Value* vp) {
35043480 AutoJSMethodProfilerEntry pseudoFrame (cx, " Array.prototype" , " toSpliced" );
35053481 CallArgs args = CallArgsFromVp (argc, vp);
@@ -3519,9 +3495,11 @@ static bool array_toSpliced(JSContext* cx, unsigned argc, Value* vp) {
35193495 // Steps 3-6.
35203496 // |actualStart| is the index after which elements will be deleted and/or
35213497 // new elements will be added
3522- uint64_t actualStart;
3523- if (!GetActualStart (cx, args.get (0 ), len, &actualStart)) {
3524- return false ;
3498+ uint64_t actualStart = 0 ;
3499+ if (args.hasDefined (0 )) {
3500+ if (!ToIntegerIndex (cx, args[0 ], len, &actualStart)) {
3501+ return false ;
3502+ }
35253503 }
35263504 MOZ_ASSERT (actualStart <= len);
35273505
@@ -4038,19 +4016,6 @@ static JSObject* SliceArguments(JSContext* cx, Handle<ArgumentsObject*> argsobj,
40384016 return result;
40394017}
40404018
4041- template <typename T, typename ArrayLength>
4042- static inline ArrayLength NormalizeSliceTerm (T value, ArrayLength length) {
4043- if (value < 0 ) {
4044- value += length;
4045- if (value < 0 ) {
4046- return 0 ;
4047- }
4048- } else if (double (value) > double (length)) {
4049- return length;
4050- }
4051- return ArrayLength (value);
4052- }
4053-
40544019static bool ArraySliceOrdinary (JSContext* cx, HandleObject obj, uint64_t begin,
40554020 uint64_t end, MutableHandleValue rval) {
40564021 if (begin > end) {
@@ -4141,26 +4106,19 @@ static bool array_slice(JSContext* cx, unsigned argc, Value* vp) {
41414106 return false ;
41424107 }
41434108
4109+ /* Steps 3-4. */
41444110 uint64_t k = 0 ;
4145- uint64_t final = length;
4146- if (args.length () > 0 ) {
4147- double d;
4148- /* Step 3. */
4149- if (!ToInteger (cx, args[0 ], &d)) {
4111+ if (args.hasDefined (0 )) {
4112+ if (!ToIntegerIndex (cx, args[0 ], length, &k)) {
41504113 return false ;
41514114 }
4115+ }
41524116
4153- /* Step 4. */
4154- k = NormalizeSliceTerm (d, length);
4155-
4156- if (args.hasDefined (1 )) {
4157- /* Step 5. */
4158- if (!ToInteger (cx, args[1 ], &d)) {
4159- return false ;
4160- }
4161-
4162- /* Step 6. */
4163- final = NormalizeSliceTerm (d, length);
4117+ /* Steps 5-6. */
4118+ uint64_t final = length;
4119+ if (args.hasDefined (1 )) {
4120+ if (!ToIntegerIndex (cx, args[1 ], length, &final )) {
4121+ return false ;
41644122 }
41654123 }
41664124
@@ -4218,6 +4176,13 @@ static bool array_slice(JSContext* cx, unsigned argc, Value* vp) {
42184176 return true ;
42194177}
42204178
4179+ static inline uint32_t NormalizeSliceTerm (int32_t value, uint32_t length) {
4180+ if (value >= 0 ) {
4181+ return std::min (uint32_t (value), length);
4182+ }
4183+ return uint32_t (std::max (int32_t (uint32_t (value) + length), 0 ));
4184+ }
4185+
42214186static bool ArraySliceDenseKernel (JSContext* cx, ArrayObject* arr,
42224187 int32_t beginArg, int32_t endArg,
42234188 ArrayObject* result) {
@@ -4494,8 +4459,8 @@ static bool SearchElementDense(JSContext* cx, HandleValue val, Iter iterator,
44944459 return iterator (cx, cmp, rval);
44954460}
44964461
4497- // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
4498- // 22 .1.3.14 Array.prototype.indexOf ( searchElement [ , fromIndex ] )
4462+ // ES2026 draft rev a562082b031d89d00ee667181ce8a6158656bd4b
4463+ // 23 .1.3.17 Array.prototype.indexOf ( searchElement [ , fromIndex ] )
44994464bool js::array_indexOf (JSContext* cx, unsigned argc, Value* vp) {
45004465 AutoJSMethodProfilerEntry pseudoFrame (cx, " Array.prototype" , " indexOf" );
45014466 CallArgs args = CallArgsFromVp (argc, vp);
@@ -4518,36 +4483,25 @@ bool js::array_indexOf(JSContext* cx, unsigned argc, Value* vp) {
45184483 return true ;
45194484 }
45204485
4521- // Steps 4-8 .
4486+ // Steps 4-9 .
45224487 uint64_t k = 0 ;
4523- if (args.length () > 1 ) {
4524- double n;
4525- if (!ToInteger (cx, args[1 ], &n)) {
4488+ if (args.hasDefined (1 )) {
4489+ if (!ToIntegerIndex (cx, args[1 ], len, &k)) {
45264490 return false ;
45274491 }
45284492
4529- // Step 6 .
4530- if (n >= double ( len) ) {
4493+ // Return early if |k| exceeds the current length .
4494+ if (k >= len) {
45314495 args.rval ().setInt32 (-1 );
45324496 return true ;
45334497 }
4534-
4535- // Steps 7-8.
4536- if (n >= 0 ) {
4537- k = uint64_t (n);
4538- } else {
4539- double d = double (len) + n;
4540- if (d >= 0 ) {
4541- k = uint64_t (d);
4542- }
4543- }
45444498 }
45454499
45464500 MOZ_ASSERT (k < len);
45474501
45484502 HandleValue searchElement = args.get (0 );
45494503
4550- // Steps 9 and 10 optimized for dense elements.
4504+ // Step 10 optimized for dense elements.
45514505 if (CanOptimizeForDenseStorage<ArrayAccess::Read>(obj, len)) {
45524506 MOZ_ASSERT (len <= UINT32_MAX);
45534507
@@ -4591,7 +4545,7 @@ bool js::array_indexOf(JSContext* cx, unsigned argc, Value* vp) {
45914545 args.rval ());
45924546 }
45934547
4594- // Step 9 .
4548+ // Step 10 .
45954549 RootedValue v (cx);
45964550 for (; k < len; k++) {
45974551 if (!CheckForInterrupt (cx)) {
@@ -4616,7 +4570,7 @@ bool js::array_indexOf(JSContext* cx, unsigned argc, Value* vp) {
46164570 }
46174571 }
46184572
4619- // Step 10 .
4573+ // Step 11 .
46204574 args.rval ().setInt32 (-1 );
46214575 return true ;
46224576}
@@ -4735,8 +4689,8 @@ bool js::array_lastIndexOf(JSContext* cx, unsigned argc, Value* vp) {
47354689 return true ;
47364690}
47374691
4738- // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
4739- // 22 .1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] )
4692+ // ES2026 draft rev a562082b031d89d00ee667181ce8a6158656bd4b
4693+ // 23 .1.3.16 Array.prototype.includes ( searchElement [ , fromIndex ] )
47404694bool js::array_includes (JSContext* cx, unsigned argc, Value* vp) {
47414695 AutoJSMethodProfilerEntry pseudoFrame (cx, " Array.prototype" , " includes" );
47424696 CallArgs args = CallArgsFromVp (argc, vp);
@@ -4759,35 +4713,25 @@ bool js::array_includes(JSContext* cx, unsigned argc, Value* vp) {
47594713 return true ;
47604714 }
47614715
4762- // Steps 4-7 .
4716+ // Steps 4-9 .
47634717 uint64_t k = 0 ;
4764- if (args.length () > 1 ) {
4765- double n;
4766- if (!ToInteger (cx, args[1 ], &n)) {
4718+ if (args.hasDefined (1 )) {
4719+ if (!ToIntegerIndex (cx, args[1 ], len, &k)) {
47674720 return false ;
47684721 }
47694722
4770- if (n >= double (len)) {
4723+ // Return early if |k| exceeds the current length.
4724+ if (k >= len) {
47714725 args.rval ().setBoolean (false );
47724726 return true ;
47734727 }
4774-
4775- // Steps 6-7.
4776- if (n >= 0 ) {
4777- k = uint64_t (n);
4778- } else {
4779- double d = double (len) + n;
4780- if (d >= 0 ) {
4781- k = uint64_t (d);
4782- }
4783- }
47844728 }
47854729
47864730 MOZ_ASSERT (k < len);
47874731
47884732 HandleValue searchElement = args.get (0 );
47894733
4790- // Steps 8 and 9 optimized for dense elements.
4734+ // Step 10 optimized for dense elements.
47914735 if (CanOptimizeForDenseStorage<ArrayAccess::Read>(obj, len)) {
47924736 MOZ_ASSERT (len <= UINT32_MAX);
47934737
@@ -4836,7 +4780,7 @@ bool js::array_includes(JSContext* cx, unsigned argc, Value* vp) {
48364780 args.rval ());
48374781 }
48384782
4839- // Step 8 .
4783+ // Step 10 .
48404784 RootedValue v (cx);
48414785 for (; k < len; k++) {
48424786 if (!CheckForInterrupt (cx)) {
@@ -4857,7 +4801,7 @@ bool js::array_includes(JSContext* cx, unsigned argc, Value* vp) {
48574801 }
48584802 }
48594803
4860- // Step 9 .
4804+ // Step 11 .
48614805 args.rval ().setBoolean (false );
48624806 return true ;
48634807}
@@ -5211,7 +5155,6 @@ static const JSFunctionSpec array_methods[] = {
52115155 JS_SELF_HOSTED_FN (" flatMap" , " ArrayFlatMap" , 1 , 0 ),
52125156 JS_SELF_HOSTED_FN (" flat" , " ArrayFlat" , 0 , 0 ),
52135157
5214- /* Proposal */
52155158 JS_SELF_HOSTED_FN (" at" , " ArrayAt" , 1 , 0 ),
52165159 JS_SELF_HOSTED_FN (" findLast" , " ArrayFindLast" , 1 , 0 ),
52175160 JS_SELF_HOSTED_FN (" findLastIndex" , " ArrayFindLastIndex" , 1 , 0 ),
0 commit comments