From 737856a7d98d353fc750458d9f7cb938cbcd6761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Wed, 27 Nov 2024 07:20:43 +0000 Subject: [PATCH] Bug 1931350: Add initial implementation for the Iterator Sequencing proposal. r=mgaudet Test PR: https://github.com/tc39/test262/pull/4326 Differential Revision: https://phabricator.services.mozilla.com/D229014 --- js/src/builtin/Iterator.js | 81 +++++++++++++++++++++++++++++++-- js/src/vm/CommonPropertyNames.h | 1 + js/src/vm/Iteration.cpp | 1 + js/src/vm/JSObject.cpp | 9 ++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/js/src/builtin/Iterator.js b/js/src/builtin/Iterator.js index 501f8dd22c0d4..ad838791e19e3 100644 --- a/js/src/builtin/Iterator.js +++ b/js/src/builtin/Iterator.js @@ -974,11 +974,84 @@ function IteratorFind(predicate) { } } - #ifdef NIGHTLY_BUILD -/** +/** + * Iterator.concat ( ...items ) + * + * https://tc39.es/proposal-iterator-sequencing/ + */ +function IteratorConcat() { + // Step 1. + // + // Stored in reversed order to simplify removing processed items. + var index = ArgumentsLength() * 2; + var iterables = std_Array(index); + + // Step 2. + for (var i = 0; i < ArgumentsLength(); i++) { + var item = GetArgument(i); + + // Step 2.a. + if (!IsObject(item)) { + ThrowTypeError(JSMSG_OBJECT_REQUIRED, typeof item); + } + + // Step 2.b. (Inlined GetMethod) + var method = item[GetBuiltinSymbol("iterator")]; + + // Step 2.c. + if (!IsCallable(method)) { + ThrowTypeError(JSMSG_NOT_ITERABLE, ToSource(item)); + } + + // Step 2.d. + DefineDataProperty(iterables, --index, item); + DefineDataProperty(iterables, --index, method); + } + assert(index === 0, "all items stored"); + + // Steps 3-5. + var result = NewIteratorHelper(); + var generator = IteratorConcatGenerator(iterables); + UnsafeSetReservedSlot( + result, + ITERATOR_HELPER_GENERATOR_SLOT, + generator + ); + + // Step 6. + return result; +} + +/** + * Iterator.concat ( ...items ) + * + * https://tc39.es/proposal-iterator-sequencing/ + */ +function* IteratorConcatGenerator(iterables) { + assert(IsArray(iterables), "iterables is an array"); + assert(iterables.length % 2 === 0, "iterables contains pairs (item, method)"); + + // Step 3.a. + for (var i = iterables.length; i > 0; ) { + var item = iterables[--i]; + var method = iterables[--i]; + + // Remove processed items to avoid keeping them alive. + iterables.length -= 2; + + // Steps 3.a.i-v. + for (var innerValue of allowContentIterWith(item, method)) { + // Steps 3.a.v.1-3. (Implicit through for-of loop) + + yield innerValue; + } + } +} + +/** * Iterator.zip (iterables [, options]) - * + * * https://tc39.es/proposal-joint-iteration/#sec-iterator.zip */ function IteratorZip(predicate) { @@ -993,4 +1066,4 @@ function IteratorZip(predicate) { function IteratorZipKeyed(predicate) { return false; } -#endif \ No newline at end of file +#endif diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 14d456228cb10..1530375a2d3bb 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -98,6 +98,7 @@ MACRO_(compact, "compact") \ MACRO_(compactDisplay, "compactDisplay") \ MACRO_(compare, "compare") \ + MACRO_(concat, "concat") \ MACRO_(configurable, "configurable") \ MACRO_(const_, "const") \ MACRO_(constrain, "constrain") \ diff --git a/js/src/vm/Iteration.cpp b/js/src/vm/Iteration.cpp index 9acf7457b67a2..09ed9e4f34138 100644 --- a/js/src/vm/Iteration.cpp +++ b/js/src/vm/Iteration.cpp @@ -1939,6 +1939,7 @@ void js::AssertDenseElementsNotIterated(NativeObject* obj) { static const JSFunctionSpec iterator_static_methods[] = { JS_SELF_HOSTED_FN("from", "IteratorFrom", 1, 0), #ifdef NIGHTLY_BUILD + JS_SELF_HOSTED_FN("concat", "IteratorConcat", 0, 0), JS_SELF_HOSTED_FN("range", "IteratorRange", 1, 0), JS_SELF_HOSTED_FN("zip", "IteratorZip", 1, 0), JS_SELF_HOSTED_FN("zipKeyed", "IteratorZipKeyed", 1, 0), diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp index 5befd1b2c23ae..0bd256a63b633 100644 --- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -2339,6 +2339,15 @@ JS_PUBLIC_API bool js::ShouldIgnorePropertyDefinition(JSContext* cx, return true; } + // It's gently surprising that this is JSProto_Function, but the trick + // to realize is that this is a -constructor function-, not a function + // on the prototype; and the proto of the constructor is JSProto_Function. + if (key == JSProto_Function && + !JS::Prefs::experimental_iterator_sequencing() && + id == NameToId(cx->names().concat)) { + return true; + } + if (key == JSProto_Atomics && !JS::Prefs::experimental_atomics_pause() && id == NameToId(cx->names().pause)) { return true;