Explorar o código

LibJS: Update spec numbers for the Iterator Helpers proposal

This proposal has reached stage 4 and was merged into the ECMA-262 spec.
See: https://github.com/tc39/ecma262/commit/961f269
Timothy Flynn hai 9 meses
pai
achega
84ad36de06

+ 39 - 32
Userland/Libraries/LibJS/Runtime/Iterator.cpp

@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
  * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
- * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -35,7 +35,19 @@ Iterator::Iterator(Object& prototype)
 {
 }
 
-// 7.4.2 GetIteratorFromMethod ( obj, method ), https://tc39.es/ecma262/#sec-getiteratorfrommethod
+// 7.4.2 GetIteratorDirect ( obj ), https://tc39.es/ecma262/#sec-getiteratordirect
+ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM& vm, Object& object)
+{
+    // 1. Let nextMethod be ? Get(obj, "next").
+    auto next_method = TRY(object.get(vm.names.next));
+
+    // 2. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
+    // 3. Return iteratorRecord.
+    auto& realm = *vm.current_realm();
+    return vm.heap().allocate<IteratorRecord>(realm, realm, object, next_method, false);
+}
+
+// 7.4.3 GetIteratorFromMethod ( obj, method ), https://tc39.es/ecma262/#sec-getiteratorfrommethod
 ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM& vm, Value object, NonnullGCPtr<FunctionObject> method)
 {
     // 1. Let iterator be ? Call(method, obj).
@@ -56,7 +68,7 @@ ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM& vm,
     return iterator_record;
 }
 
-// 7.4.3 GetIterator ( obj, kind ), https://tc39.es/ecma262/#sec-getiterator
+// 7.4.4 GetIterator ( obj, kind ), https://tc39.es/ecma262/#sec-getiterator
 ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM& vm, Value object, IteratorHint kind)
 {
     JS::GCPtr<FunctionObject> method;
@@ -96,29 +108,24 @@ ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM& vm, Value objec
     return TRY(get_iterator_from_method(vm, object, *method));
 }
 
-// 2.1.1 GetIteratorDirect ( obj ), https://tc39.es/proposal-iterator-helpers/#sec-getiteratorflattenable
-ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM& vm, Object& object)
-{
-    // 1. Let nextMethod be ? Get(obj, "next").
-    auto next_method = TRY(object.get(vm.names.next));
-
-    // 2. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
-    // 3. Return iteratorRecord.
-    auto& realm = *vm.current_realm();
-    return vm.heap().allocate<IteratorRecord>(realm, realm, object, next_method, false);
-}
-
-// 2.1.2 GetIteratorFlattenable ( obj, stringHandling ), https://tc39.es/proposal-iterator-helpers/#sec-getiteratorflattenable
-ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM& vm, Value object, StringHandling string_handling)
+// 7.4.5 GetIteratorFlattenable ( obj, primitiveHandling ), https://tc39.es/ecma262/#sec-getiteratorflattenable
+ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM& vm, Value object, PrimitiveHandling primitive_handling)
 {
     // 1. If obj is not an Object, then
     if (!object.is_object()) {
-        // a. If stringHandling is reject-strings or obj is not a String, throw a TypeError exception.
-        if (string_handling == StringHandling::RejectStrings || !object.is_string())
+        // a. If primitiveHandling is reject-primitives, throw a TypeError exception.
+        if (primitive_handling == PrimitiveHandling::RejectPrimitives)
             return vm.throw_completion<TypeError>(ErrorType::NotAnObject, object.to_string_without_side_effects());
+
+        // b. Assert: primitiveHandling is iterate-string-primitives.
+        ASSERT(primitive_handling == PrimitiveHandling::IterateStringPrimitives);
+
+        // c. If obj is not a String, throw a TypeError exception.
+        if (!object.is_string())
+            return vm.throw_completion<TypeError>(ErrorType::NotAString, object.to_string_without_side_effects());
     }
 
-    // 2. Let method be ? GetMethod(obj, @@iterator).
+    // 2. Let method be ? GetMethod(obj, %Symbol.iterator%).
     auto method = TRY(object.get_method(vm, vm.well_known_symbol_iterator()));
 
     Value iterator;
@@ -142,7 +149,7 @@ ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM& vm,
     return TRY(get_iterator_direct(vm, iterator.as_object()));
 }
 
-// 7.4.4 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext
+// 7.4.6 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext
 ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord& iterator_record, Optional<Value> value)
 {
     auto result = [&]() {
@@ -183,21 +190,21 @@ ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord& it
     return result_value.as_object();
 }
 
-// 7.4.5 IteratorComplete ( iterResult ), https://tc39.es/ecma262/#sec-iteratorcomplete
+// 7.4.7 IteratorComplete ( iteratorResult ), https://tc39.es/ecma262/#sec-iteratorcomplete
 ThrowCompletionOr<bool> iterator_complete(VM& vm, Object& iterator_result)
 {
     // 1. Return ToBoolean(? Get(iterResult, "done")).
     return TRY(iterator_result.get(vm.names.done)).to_boolean();
 }
 
-// 7.4.6 IteratorValue ( iterResult ), https://tc39.es/ecma262/#sec-iteratorvalue
+// 7.4.8 IteratorValue ( iteratorResult ), https://tc39.es/ecma262/#sec-iteratorvalue
 ThrowCompletionOr<Value> iterator_value(VM& vm, Object& iterator_result)
 {
     // 1. Return ? Get(iterResult, "value").
     return TRY(iterator_result.get(vm.names.value));
 }
 
-// 7.4.7 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep
+// 7.4.9 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep
 ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord& iterator_record)
 {
     // 1. Let result be ? IteratorNext(iteratorRecord).
@@ -231,7 +238,7 @@ ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord& iterator_
     return result;
 }
 
-// 7.4.8 IteratorStepValue ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstepvalue
+// 7.4.10 IteratorStepValue ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstepvalue
 ThrowCompletionOr<Optional<Value>> iterator_step_value(VM& vm, IteratorRecord& iterator_record)
 {
     // 1. Let result be ? IteratorStep(iteratorRecord).
@@ -256,8 +263,8 @@ ThrowCompletionOr<Optional<Value>> iterator_step_value(VM& vm, IteratorRecord& i
     return TRY(value);
 }
 
-// 7.4.9 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose
-// 7.4.11 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
+// 7.4.11 IteratorClose ( iteratorRecord, completion , https://tc39.es/ecma262/#sec-iteratorclose
+// 7.4.13 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
 // NOTE: These only differ in that async awaits the inner value after the call.
 static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_record, Completion completion, IteratorHint iterator_hint)
 {
@@ -307,19 +314,19 @@ static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_rec
     return completion;
 }
 
-// 7.4.9 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose
+// 7.4.11 IteratorClose ( iteratorRecord, completion , https://tc39.es/ecma262/#sec-iteratorclose
 Completion iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion)
 {
     return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Sync);
 }
 
-// 7.4.11 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
+// 7.4.13 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
 Completion async_iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion)
 {
     return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Async);
 }
 
-// 7.4.12 CreateIterResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject
+// 7.4.14 CreateIteratorResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject
 NonnullGCPtr<Object> create_iterator_result_object(VM& vm, Value value, bool done)
 {
     auto& realm = *vm.current_realm();
@@ -337,7 +344,7 @@ NonnullGCPtr<Object> create_iterator_result_object(VM& vm, Value value, bool don
     return object;
 }
 
-// 7.4.14 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist
+// 7.4.16 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist
 ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM& vm, IteratorRecord& iterator_record)
 {
     // 1. Let values be a new empty List.
@@ -359,7 +366,7 @@ ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM& vm, IteratorRecord&
     }
 }
 
-// 2.1 SetterThatIgnoresPrototypeProperties ( this, home, p, v ), https://tc39.es/proposal-iterator-helpers/#sec-SetterThatIgnoresPrototypeProperties
+// 7.3.36 SetterThatIgnoresPrototypeProperties ( thisValue, home, p, v ), https://tc39.es/ecma262/#sec-SetterThatIgnoresPrototypeProperties
 ThrowCompletionOr<void> setter_that_ignores_prototype_properties(VM& vm, Value this_, Object const& home, PropertyKey const& property, Value value)
 {
     // 1. If this is not an Object, then

+ 8 - 8
Userland/Libraries/LibJS/Runtime/Iterator.h

@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
  * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
- * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -65,20 +65,20 @@ enum class IteratorHint {
     Async,
 };
 
-enum class StringHandling {
-    IterateStrings,
-    RejectStrings,
+enum class PrimitiveHandling {
+    IterateStringPrimitives,
+    RejectPrimitives,
 };
 
+ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM&, Object&);
 ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM&, Value, NonnullGCPtr<FunctionObject>);
 ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM&, Value, IteratorHint);
-ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM&, Object&);
-ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM&, Value, StringHandling);
+ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM&, Value, PrimitiveHandling);
 ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM&, IteratorRecord&, Optional<Value> = {});
-ThrowCompletionOr<GCPtr<Object>> iterator_step(VM&, IteratorRecord&);
-ThrowCompletionOr<Optional<Value>> iterator_step_value(VM&, IteratorRecord&);
 ThrowCompletionOr<bool> iterator_complete(VM&, Object& iterator_result);
 ThrowCompletionOr<Value> iterator_value(VM&, Object& iterator_result);
+ThrowCompletionOr<GCPtr<Object>> iterator_step(VM&, IteratorRecord&);
+ThrowCompletionOr<Optional<Value>> iterator_step_value(VM&, IteratorRecord&);
 Completion iterator_close(VM&, IteratorRecord const&, Completion);
 Completion async_iterator_close(VM&, IteratorRecord const&, Completion);
 NonnullGCPtr<Object> create_iterator_result_object(VM&, Value, bool done);

+ 9 - 9
Userland/Libraries/LibJS/Runtime/IteratorConstructor.cpp

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -16,7 +16,7 @@ namespace JS {
 
 JS_DEFINE_ALLOCATOR(IteratorConstructor);
 
-// 3.1.1.1 The Iterator Constructor, https://tc39.es/proposal-iterator-helpers/#sec-iterator-constructor
+// 27.1.3.1 The Iterator Constructor, https://tc39.es/ecma262/#sec-iterator-constructor
 IteratorConstructor::IteratorConstructor(Realm& realm)
     : Base(realm.vm().names.Iterator.as_string(), realm.intrinsics().function_prototype())
 {
@@ -28,7 +28,7 @@ void IteratorConstructor::initialize(Realm& realm)
 
     auto& vm = this->vm();
 
-    // 3.1.1.2.1 Iterator.prototype, https://tc39.es/proposal-iterator-helpers/#sec-iterator.prototype
+    // 27.1.3.2.2 Iterator.prototype Iterator.prototype, https://tc39.es/ecma262/#sec-iterator.prototype
     define_direct_property(vm.names.prototype, realm.intrinsics().iterator_prototype(), 0);
 
     u8 attr = Attribute::Writable | Attribute::Configurable;
@@ -37,7 +37,7 @@ void IteratorConstructor::initialize(Realm& realm)
     define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
 }
 
-// 3.1.1.1.1 Iterator ( ), https://tc39.es/proposal-iterator-helpers/#sec-iterator
+// 27.1.3.1.1 Iterator ( ), https://tc39.es/ecma262/#sec-iterator
 ThrowCompletionOr<Value> IteratorConstructor::call()
 {
     auto& vm = this->vm();
@@ -46,7 +46,7 @@ ThrowCompletionOr<Value> IteratorConstructor::call()
     return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, "Iterator");
 }
 
-// 3.1.1.1.1 Iterator ( ), https://tc39.es/proposal-iterator-helpers/#sec-iterator
+// 27.1.3.1.1 Iterator ( ), https://tc39.es/ecma262/#sec-iterator
 ThrowCompletionOr<NonnullGCPtr<Object>> IteratorConstructor::construct(FunctionObject& new_target)
 {
     auto& vm = this->vm();
@@ -59,15 +59,15 @@ ThrowCompletionOr<NonnullGCPtr<Object>> IteratorConstructor::construct(FunctionO
     return TRY(ordinary_create_from_constructor<Iterator>(vm, new_target, &Intrinsics::iterator_prototype));
 }
 
-// 3.1.1.2.2 Iterator.from ( O ), https://tc39.es/proposal-iterator-helpers/#sec-iterator.from
+// 27.1.3.2.1 Iterator.from ( O ), https://tc39.es/ecma262/#sec-iterator.from
 JS_DEFINE_NATIVE_FUNCTION(IteratorConstructor::from)
 {
     auto& realm = *vm.current_realm();
 
     auto object = vm.argument(0);
 
-    // 1. Let iteratorRecord be ? GetIteratorFlattenable(O, iterate-strings).
-    auto iterator_record = TRY(get_iterator_flattenable(vm, object, StringHandling::IterateStrings));
+    // 1. Let iteratorRecord be ? GetIteratorFlattenable(O, iterate-string-primitives).
+    auto iterator_record = TRY(get_iterator_flattenable(vm, object, PrimitiveHandling::IterateStringPrimitives));
 
     // 2. Let hasInstance be ? OrdinaryHasInstance(%Iterator%, iteratorRecord.[[Iterator]]).
     auto has_instance = TRY(ordinary_has_instance(vm, iterator_record->iterator, realm.intrinsics().iterator_constructor()));
@@ -80,7 +80,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorConstructor::from)
 
     // 4. Let wrapper be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, « [[Iterated]] »).
     // 5. Set wrapper.[[Iterated]] to iteratorRecord.
-    auto wrapper = Iterator::create(realm, realm.intrinsics().wrap_for_valid_iterator_prototype(), move(iterator_record));
+    auto wrapper = Iterator::create(realm, realm.intrinsics().wrap_for_valid_iterator_prototype(), iterator_record);
 
     // 6. Return wrapper.
     return wrapper;

+ 5 - 4
Userland/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -12,6 +12,7 @@ namespace JS {
 
 JS_DEFINE_ALLOCATOR(IteratorHelperPrototype);
 
+// 27.1.2.1 The %IteratorHelperPrototype% Object, https://tc39.es/ecma262/#sec-%iteratorhelperprototype%-object
 IteratorHelperPrototype::IteratorHelperPrototype(Realm& realm)
     : PrototypeObject(realm.intrinsics().iterator_prototype())
 {
@@ -26,11 +27,11 @@ void IteratorHelperPrototype::initialize(Realm& realm)
     define_native_function(realm, vm.names.next, next, 0, attr);
     define_native_function(realm, vm.names.return_, return_, 0, attr);
 
-    // 3.1.2.1.3 %IteratorHelperPrototype% [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-%iteratorhelperprototype%-@@tostringtag
+    // 27.1.2.1.3 %IteratorHelperPrototype% [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-%iteratorhelperprototype%-%symbol.tostringtag%
     define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Iterator Helper"_string), Attribute::Configurable);
 }
 
-// 3.1.2.1.1 %IteratorHelperPrototype%.next ( ), https://tc39.es/proposal-iterator-helpers/#sec-%iteratorhelperprototype%.next
+// 27.1.2.1.1 %IteratorHelperPrototype%.next ( ), https://tc39.es/ecma262/#sec-%iteratorhelperprototype%.next
 JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::next)
 {
     auto iterator = TRY(typed_this_object(vm));
@@ -39,7 +40,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::next)
     return iterator->resume(vm, js_undefined(), "Iterator Helper"sv);
 }
 
-// 3.1.2.1.2 %IteratorHelperPrototype%.return ( ), https://tc39.es/proposal-iterator-helpers/#sec-%iteratorhelperprototype%.return
+// 27.1.2.1.2 %IteratorHelperPrototype%.return ( ), https://tc39.es/ecma262/#sec-%iteratorhelperprototype%.return
 JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::return_)
 {
     // 1. Let O be this value.

+ 325 - 324
Userland/Libraries/LibJS/Runtime/IteratorPrototype.cpp

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
+ * Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -32,33 +33,26 @@ void IteratorPrototype::initialize(Realm& realm)
 
     u8 attr = Attribute::Writable | Attribute::Configurable;
     define_native_function(realm, vm.well_known_symbol_iterator(), symbol_iterator, 0, attr);
-    define_native_function(realm, vm.names.map, map, 1, attr);
-    define_native_function(realm, vm.names.filter, filter, 1, attr);
-    define_native_function(realm, vm.names.take, take, 1, attr);
     define_native_function(realm, vm.names.drop, drop, 1, attr);
+    define_native_function(realm, vm.names.every, every, 1, attr);
+    define_native_function(realm, vm.names.filter, filter, 1, attr);
+    define_native_function(realm, vm.names.find, find, 1, attr);
     define_native_function(realm, vm.names.flatMap, flat_map, 1, attr);
-    define_native_function(realm, vm.names.reduce, reduce, 1, attr);
-    define_native_function(realm, vm.names.toArray, to_array, 0, attr);
     define_native_function(realm, vm.names.forEach, for_each, 1, attr);
+    define_native_function(realm, vm.names.map, map, 1, attr);
+    define_native_function(realm, vm.names.reduce, reduce, 1, attr);
     define_native_function(realm, vm.names.some, some, 1, attr);
-    define_native_function(realm, vm.names.every, every, 1, attr);
-    define_native_function(realm, vm.names.find, find, 1, attr);
+    define_native_function(realm, vm.names.take, take, 1, attr);
+    define_native_function(realm, vm.names.toArray, to_array, 0, attr);
 
-    // 3.1.3.1 Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.constructor
+    // 27.1.4.1 Iterator.prototype.constructor, https://tc39.es/ecma262/#sec-iterator.prototype.constructor
     define_native_accessor(realm, vm.names.constructor, constructor_getter, constructor_setter, Attribute::Configurable);
 
-    // 3.1.3.13 Iterator.prototype [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype-@@tostringtag
+    // 27.1.4.14 Iterator.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-iterator.prototype-%symbol.tostringtag%
     define_native_accessor(realm, vm.well_known_symbol_to_string_tag(), to_string_tag_getter, to_string_tag_setter, Attribute::Configurable);
 }
 
-// 27.1.2.1 %IteratorPrototype% [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::symbol_iterator)
-{
-    // 1. Return the this value.
-    return vm.this_value();
-}
-
-// 3.1.3.1.1 get Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-get-iteratorprototype-constructor
+// 27.1.4.1.1 get Iterator.prototype.constructor, https://tc39.es/ecma262/#sec-get-iterator.prototype.constructor
 JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
 {
     auto& realm = *vm.current_realm();
@@ -67,7 +61,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
     return realm.intrinsics().iterator_constructor();
 }
 
-// 3.1.3.1.2 set Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-set-iteratorprototype-constructor
+// 27.1.4.1.2 set Iterator.prototype.constructor, https://tc39.es/ecma262/#sec-set-iterator.prototype.constructor
 JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_setter)
 {
     auto& realm = *vm.current_realm();
@@ -79,30 +73,54 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_setter)
     return js_undefined();
 }
 
-// 3.1.3.2 Iterator.prototype.map ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.map
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
+// 27.1.4.2 Iterator.prototype.drop ( limit ), https://tc39.es/ecma262/#sec-iterator.prototype.drop
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop)
 {
     auto& realm = *vm.current_realm();
 
-    auto mapper = vm.argument(0);
+    auto limit = vm.argument(0);
 
     // 1. Let O be the this value.
     // 2. If O is not an Object, throw a TypeError exception.
     auto object = TRY(this_object(vm));
 
-    // 3. If IsCallable(mapper) is false, throw a TypeError exception.
-    if (!mapper.is_function())
-        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "mapper"sv);
+    // 3. Let numLimit be ? ToNumber(limit).
+    auto numeric_limit = TRY(limit.to_number(vm));
 
-    // 4. Let iterated be ? GetIteratorDirect(O).
+    // 4. If numLimit is NaN, throw a RangeError exception.
+    if (numeric_limit.is_nan())
+        return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
+
+    // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
+    auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
+
+    // 6. If integerLimit < 0, throw a RangeError exception.
+    if (integer_limit < 0)
+        return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
+
+    // 7. Let iterated be ? GetIteratorDirect(O).
     auto iterated = TRY(get_iterator_direct(vm, object));
 
-    // 5. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
-    auto closure = JS::create_heap_function(realm.heap(), [mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
+    // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
+    auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
         auto& iterated = iterator.underlying_iterator();
 
-        // a. Let counter be 0.
-        // b. Repeat,
+        // a. Let remaining be integerLimit.
+        // b. Repeat, while remaining > 0,
+        while (iterator.counter() < integer_limit) {
+            // i. If remaining is not +∞, then
+            //     1. Set remaining to remaining - 1.
+            iterator.increment_counter();
+
+            // ii. Let next be ? IteratorStep(iterated).
+            auto next = TRY(iterator_step(vm, iterated));
+
+            // iii. If next is false, return undefined.
+            if (!next)
+                return iterator.result(js_undefined());
+        }
+
+        // c. Repeat,
 
         // i. Let value be ? IteratorStepValue(iterated).
         auto value = TRY(iterator_step_value(vm, iterated));
@@ -111,31 +129,64 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
         if (!value.has_value())
             return iterator.result(js_undefined());
 
-        // iii. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
-        auto mapped = call(vm, *mapper, js_undefined(), *value, Value { iterator.counter() });
+        // iii. Let completion be Completion(Yield(value)).
+        // iv. IfAbruptCloseIterator(completion, iterated).
+        return iterator.result(*value);
+    });
 
-        // iv. IfAbruptCloseIterator(mapped, iterated).
-        if (mapped.is_error())
-            return iterator.close_result(vm, mapped.release_error());
+    // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
+    // 10. Set result.[[UnderlyingIterator]] to iterated.
+    auto result = TRY(IteratorHelper::create(realm, iterated, closure));
 
-        // vii. Set counter to counter + 1.
-        // NOTE: We do this step early to ensure it occurs before returning.
-        iterator.increment_counter();
+    // 11. Return result.
+    return result;
+}
 
-        // v. Let completion be Completion(Yield(mapped)).
-        // vi. IfAbruptCloseIterator(completion, iterated).
-        return iterator.result(mapped.release_value());
-    });
+// 27.1.4.3 Iterator.prototype.every ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.every
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::every)
+{
+    auto predicate = vm.argument(0);
 
-    // 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
-    // 7. Set result.[[UnderlyingIterator]] to iterated.
-    auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
+    // 1. Let O be the this value.
+    // 2. If O is not an Object, throw a TypeError exception.
+    auto object = TRY(this_object(vm));
 
-    // 8. Return result.
-    return result;
+    // 3. If IsCallable(predicate) is false, throw a TypeError exception.
+    if (!predicate.is_function())
+        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
+
+    // 4. Let iterated be ? GetIteratorDirect(O).
+    auto iterated = TRY(get_iterator_direct(vm, object));
+
+    // 5. Let counter be 0.
+    size_t counter = 0;
+
+    // 6. Repeat,
+    while (true) {
+        // a. Let value be ? IteratorStepValue(iterated).
+        auto value = TRY(iterator_step_value(vm, iterated));
+
+        // b. If value is done, return undefined.
+        if (!value.has_value())
+            return Value { true };
+
+        // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
+        auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
+
+        // d. IfAbruptCloseIterator(result, iterated).
+        if (result.is_error())
+            return *TRY(iterator_close(vm, iterated, result.release_error()));
+
+        // e. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)).
+        if (!result.value().to_boolean())
+            return *TRY(iterator_close(vm, iterated, normal_completion(Value { false })));
+
+        // f. Set counter to counter + 1.
+        ++counter;
+    }
 }
 
-// 3.1.3.3 Iterator.prototype.filter ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.filter
+// 27.1.4.4 Iterator.prototype.filter ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.filter
 JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::filter)
 {
     auto& realm = *vm.current_realm();
@@ -190,144 +241,54 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::filter)
 
     // 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
     // 7. Set result.[[UnderlyingIterator]] to iterated.
-    auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
+    auto result = TRY(IteratorHelper::create(realm, iterated, closure));
 
     // 8. Return result.
     return result;
 }
 
-// 3.1.3.4 Iterator.prototype.take ( limit ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.take
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::take)
+// 27.1.4.5 Iterator.prototype.find ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.find
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::find)
 {
-    auto& realm = *vm.current_realm();
-
-    auto limit = vm.argument(0);
+    auto predicate = vm.argument(0);
 
     // 1. Let O be the this value.
     // 2. If O is not an Object, throw a TypeError exception.
     auto object = TRY(this_object(vm));
 
-    // 3. Let numLimit be ? ToNumber(limit).
-    auto numeric_limit = TRY(limit.to_number(vm));
-
-    // 4. If numLimit is NaN, throw a RangeError exception.
-    if (numeric_limit.is_nan())
-        return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
-
-    // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
-    auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
-
-    // 6. If integerLimit < 0, throw a RangeError exception.
-    if (integer_limit < 0)
-        return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
+    // 3. If IsCallable(predicate) is false, throw a TypeError exception.
+    if (!predicate.is_function())
+        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
 
-    // 7. Let iterated be ? GetIteratorDirect(O).
+    // 4. Let iterated be ? GetIteratorDirect(O).
     auto iterated = TRY(get_iterator_direct(vm, object));
 
-    // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
-    auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
-        auto& iterated = iterator.underlying_iterator();
-
-        // a. Let remaining be integerLimit.
-        // b. Repeat,
-
-        // i. If remaining is 0, then
-        if (iterator.counter() >= integer_limit) {
-            // 1. Return ? IteratorClose(iterated, NormalCompletion(undefined)).
-            return iterator.close_result(vm, normal_completion(js_undefined()));
-        }
-
-        // ii. If remaining is not +∞, then
-        //     1. Set remaining to remaining - 1.
-        iterator.increment_counter();
+    // 5. Let counter be 0.
+    size_t counter = 0;
 
-        // iii. Let value be ? IteratorStepValue(iterated).
+    // 6. Repeat,
+    while (true) {
+        // a. Let value be ? IteratorStepValue(iterated).
         auto value = TRY(iterator_step_value(vm, iterated));
 
-        // iv. If value is done, return undefined.
+        // b. If value is done, return undefined.
         if (!value.has_value())
-            return iterator.result(js_undefined());
-
-        // v. Let completion be Completion(Yield(value)).
-        // vi. IfAbruptCloseIterator(completion, iterated).
-        return iterator.result(*value);
-    });
-
-    // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
-    // 10. Set result.[[UnderlyingIterator]] to iterated.
-    auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
-
-    // 11. Return result.
-    return result;
-}
-
-// 3.1.3.5 Iterator.prototype.drop ( limit ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.drop
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop)
-{
-    auto& realm = *vm.current_realm();
-
-    auto limit = vm.argument(0);
-
-    // 1. Let O be the this value.
-    // 2. If O is not an Object, throw a TypeError exception.
-    auto object = TRY(this_object(vm));
-
-    // 3. Let numLimit be ? ToNumber(limit).
-    auto numeric_limit = TRY(limit.to_number(vm));
-
-    // 4. If numLimit is NaN, throw a RangeError exception.
-    if (numeric_limit.is_nan())
-        return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
-
-    // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
-    auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
-
-    // 6. If integerLimit < 0, throw a RangeError exception.
-    if (integer_limit < 0)
-        return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
-
-    // 7. Let iterated be ? GetIteratorDirect(O).
-    auto iterated = TRY(get_iterator_direct(vm, object));
-
-    // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
-    auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
-        auto& iterated = iterator.underlying_iterator();
-
-        // a. Let remaining be integerLimit.
-        // b. Repeat, while remaining > 0,
-        while (iterator.counter() < integer_limit) {
-            // i. If remaining is not +∞, then
-            //     1. Set remaining to remaining - 1.
-            iterator.increment_counter();
-
-            // ii. Let next be ? IteratorStep(iterated).
-            auto next = TRY(iterator_step(vm, iterated));
-
-            // iii. If next is false, return undefined.
-            if (!next)
-                return iterator.result(js_undefined());
-        }
-
-        // c. Repeat,
-
-        // i. Let value be ? IteratorStepValue(iterated).
-        auto value = TRY(iterator_step_value(vm, iterated));
+            return js_undefined();
 
-        // ii. If value is done, return undefined.
-        if (!value.has_value())
-            return iterator.result(js_undefined());
+        // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
+        auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
 
-        // iii. Let completion be Completion(Yield(value)).
-        // iv. IfAbruptCloseIterator(completion, iterated).
-        return iterator.result(*value);
-    });
+        // d. IfAbruptCloseIterator(result, iterated).
+        if (result.is_error())
+            return *TRY(iterator_close(vm, iterated, result.release_error()));
 
-    // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
-    // 10. Set result.[[UnderlyingIterator]] to iterated.
-    auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
+        // e. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(value)).
+        if (result.value().to_boolean())
+            return *TRY(iterator_close(vm, iterated, normal_completion(value)));
 
-    // 11. Return result.
-    return result;
+        // f. Set counter to counter + 1.
+        ++counter;
+    }
 }
 
 class FlatMapIterator : public Cell {
@@ -385,8 +346,8 @@ private:
         if (mapped.is_error())
             return iterator.close_result(vm, mapped.release_error());
 
-        // v. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-strings)).
-        auto inner_iterator = get_iterator_flattenable(vm, mapped.release_value(), StringHandling::RejectStrings);
+        // v. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-primitives)).
+        auto inner_iterator = get_iterator_flattenable(vm, mapped.release_value(), PrimitiveHandling::RejectPrimitives);
 
         // vi. IfAbruptCloseIterator(innerIterator, iterated).
         if (inner_iterator.is_error())
@@ -403,39 +364,117 @@ private:
         return next_inner_iterator(vm, iterated, iterator, mapper);
     }
 
-    ThrowCompletionOr<Value> next_inner_iterator(VM& vm, IteratorRecord& iterated, IteratorHelper& iterator, FunctionObject& mapper)
-    {
-        VERIFY(m_inner_iterator);
+    ThrowCompletionOr<Value> next_inner_iterator(VM& vm, IteratorRecord& iterated, IteratorHelper& iterator, FunctionObject& mapper)
+    {
+        VERIFY(m_inner_iterator);
+
+        // 1. Let innerValue be Completion(IteratorStepValue(innerIterator)).
+        auto inner_value = iterator_step_value(vm, *m_inner_iterator);
+
+        // 2. IfAbruptCloseIterator(innerValue, iterated).
+        if (inner_value.is_error())
+            return iterator.close_result(vm, inner_value.release_error());
+
+        // 3. If innerValue is done, then
+        if (!inner_value.value().has_value()) {
+            // a. Set innerAlive to false.
+            m_inner_iterator = nullptr;
+
+            return next_outer_iterator(vm, iterated, iterator, mapper);
+        }
+        // 4. Else,
+        else {
+            // a. Let completion be Completion(Yield(innerValue)).
+            // NOTE: Step b is implemented via on_abrupt_completion.
+            return *inner_value.release_value();
+        }
+    }
+
+    GCPtr<IteratorRecord> m_inner_iterator;
+};
+
+JS_DEFINE_ALLOCATOR(FlatMapIterator);
+
+// 27.1.4.6 Iterator.prototype.flatMap ( mapper ), https://tc39.es/ecma262/#sec-iterator.prototype.flatmap
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
+{
+    auto& realm = *vm.current_realm();
+
+    auto mapper = vm.argument(0);
+
+    // 1. Let O be the this value.
+    // 2. If O is not an Object, throw a TypeError exception.
+    auto object = TRY(this_object(vm));
+
+    // 3. If IsCallable(mapper) is false, throw a TypeError exception.
+    if (!mapper.is_function())
+        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "mapper"sv);
+
+    // 4. Let iterated be ? GetIteratorDirect(O).
+    auto iterated = TRY(get_iterator_direct(vm, object));
+
+    auto flat_map_iterator = vm.heap().allocate<FlatMapIterator>(realm);
+
+    // 5. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
+    auto closure = JS::create_heap_function(realm.heap(), [flat_map_iterator, mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) mutable -> ThrowCompletionOr<Value> {
+        auto& iterated = iterator.underlying_iterator();
+        return flat_map_iterator->next(vm, iterated, iterator, *mapper);
+    });
+
+    auto abrupt_closure = JS::create_heap_function(realm.heap(), [flat_map_iterator](VM& vm, IteratorHelper& iterator, Completion const& completion) -> ThrowCompletionOr<Value> {
+        return flat_map_iterator->on_abrupt_completion(vm, iterator, completion);
+    });
+
+    // 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
+    // 7. Set result.[[UnderlyingIterator]] to iterated.
+    auto result = TRY(IteratorHelper::create(realm, iterated, closure, move(abrupt_closure)));
+
+    // 8. Return result.
+    return result;
+}
+
+// 27.1.4.7 Iterator.prototype.forEach ( procedure ), https://tc39.es/ecma262/#sec-iterator.prototype.foreach
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::for_each)
+{
+    auto function = vm.argument(0);
+
+    // 1. Let O be the this value.
+    // 2. If O is not an Object, throw a TypeError exception.
+    auto object = TRY(this_object(vm));
+
+    // 3. If IsCallable(fn) is false, throw a TypeError exception.
+    if (!function.is_function())
+        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "fn"sv);
+
+    // 4. Let iterated be ? GetIteratorDirect(O).
+    auto iterated = TRY(get_iterator_direct(vm, object));
 
-        // 1. Let innerValue be Completion(IteratorStepValue(innerIterator)).
-        auto inner_value = iterator_step_value(vm, *m_inner_iterator);
+    // 5. Let counter be 0.
+    size_t counter = 0;
 
-        // 2. IfAbruptCloseIterator(innerValue, iterated).
-        if (inner_value.is_error())
-            return iterator.close_result(vm, inner_value.release_error());
+    // 6. Repeat,
+    while (true) {
+        // a. Let value be ? IteratorStepValue(iterated).
+        auto value = TRY(iterator_step_value(vm, iterated));
 
-        // 3. If innerValue is done, then
-        if (!inner_value.value().has_value()) {
-            // a. Set innerAlive to false.
-            m_inner_iterator = nullptr;
+        // b. If value is done, return undefined.
+        if (!value.has_value())
+            return js_undefined();
 
-            return next_outer_iterator(vm, iterated, iterator, mapper);
-        }
-        // 4. Else,
-        else {
-            // a. Let completion be Completion(Yield(innerValue)).
-            // NOTE: Step b is implemented via on_abrupt_completion.
-            return *inner_value.release_value();
-        }
-    }
+        // c. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
+        auto result = call(vm, function.as_function(), js_undefined(), *value, Value { counter });
 
-    GCPtr<IteratorRecord> m_inner_iterator;
-};
+        // d. IfAbruptCloseIterator(result, iterated).
+        if (result.is_error())
+            return *TRY(iterator_close(vm, iterated, result.release_error()));
 
-JS_DEFINE_ALLOCATOR(FlatMapIterator);
+        // e. Set counter to counter + 1.
+        ++counter;
+    }
+}
 
-// 3.1.3.6 Iterator.prototype.flatMap ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.flatmap
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
+// 27.1.4.8 Iterator.prototype.map ( mapper ), https://tc39.es/ecma262/#sec-iterator.prototype.map
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
 {
     auto& realm = *vm.current_realm();
 
@@ -452,27 +491,45 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
     // 4. Let iterated be ? GetIteratorDirect(O).
     auto iterated = TRY(get_iterator_direct(vm, object));
 
-    auto flat_map_iterator = vm.heap().allocate<FlatMapIterator>(realm);
-
     // 5. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
-    auto closure = JS::create_heap_function(realm.heap(), [flat_map_iterator, mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) mutable -> ThrowCompletionOr<Value> {
+    auto closure = JS::create_heap_function(realm.heap(), [mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
         auto& iterated = iterator.underlying_iterator();
-        return flat_map_iterator->next(vm, iterated, iterator, *mapper);
-    });
 
-    auto abrupt_closure = JS::create_heap_function(realm.heap(), [flat_map_iterator](VM& vm, IteratorHelper& iterator, Completion const& completion) -> ThrowCompletionOr<Value> {
-        return flat_map_iterator->on_abrupt_completion(vm, iterator, completion);
+        // a. Let counter be 0.
+        // b. Repeat,
+
+        // i. Let value be ? IteratorStepValue(iterated).
+        auto value = TRY(iterator_step_value(vm, iterated));
+
+        // ii. If value is done, return undefined.
+        if (!value.has_value())
+            return iterator.result(js_undefined());
+
+        // iii. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
+        auto mapped = call(vm, *mapper, js_undefined(), *value, Value { iterator.counter() });
+
+        // iv. IfAbruptCloseIterator(mapped, iterated).
+        if (mapped.is_error())
+            return iterator.close_result(vm, mapped.release_error());
+
+        // vii. Set counter to counter + 1.
+        // NOTE: We do this step early to ensure it occurs before returning.
+        iterator.increment_counter();
+
+        // v. Let completion be Completion(Yield(mapped)).
+        // vi. IfAbruptCloseIterator(completion, iterated).
+        return iterator.result(mapped.release_value());
     });
 
     // 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
     // 7. Set result.[[UnderlyingIterator]] to iterated.
-    auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure), move(abrupt_closure)));
+    auto result = TRY(IteratorHelper::create(realm, iterated, closure));
 
     // 8. Return result.
     return result;
 }
 
-// 3.1.3.7 Iterator.prototype.reduce ( reducer [ , initialValue ] ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.reduce
+// 27.1.4.9 Iterator.prototype.reduce ( reducer [ , initialValue ] ), https://tc39.es/ecma262/#sec-iterator.prototype.reduce
 JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::reduce)
 {
     auto reducer = vm.argument(0);
@@ -538,76 +595,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::reduce)
     }
 }
 
-// 3.1.3.8 Iterator.prototype.toArray ( ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.toarray
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_array)
-{
-    auto& realm = *vm.current_realm();
-
-    // 1. Let O be the this value.
-    // 2. If O is not an Object, throw a TypeError exception.
-    auto object = TRY(this_object(vm));
-
-    // 3. Let iterated be ? GetIteratorDirect(O).
-    auto iterated = TRY(get_iterator_direct(vm, object));
-
-    // 4. Let items be a new empty List.
-    Vector<Value> items;
-
-    // 5. Repeat,
-    while (true) {
-        // a. Let value be ? IteratorStepValue(iterated).
-        auto value = TRY(iterator_step_value(vm, iterated));
-
-        // b. If value is done, return CreateArrayFromList(items).
-        if (!value.has_value())
-            return Array::create_from(realm, items);
-
-        // c. Append value to items.
-        TRY_OR_THROW_OOM(vm, items.try_append(*value));
-    }
-}
-
-// 3.1.3.9 Iterator.prototype.forEach ( fn ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.foreach
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::for_each)
-{
-    auto function = vm.argument(0);
-
-    // 1. Let O be the this value.
-    // 2. If O is not an Object, throw a TypeError exception.
-    auto object = TRY(this_object(vm));
-
-    // 3. If IsCallable(fn) is false, throw a TypeError exception.
-    if (!function.is_function())
-        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "fn"sv);
-
-    // 4. Let iterated be ? GetIteratorDirect(O).
-    auto iterated = TRY(get_iterator_direct(vm, object));
-
-    // 5. Let counter be 0.
-    size_t counter = 0;
-
-    // 6. Repeat,
-    while (true) {
-        // a. Let value be ? IteratorStepValue(iterated).
-        auto value = TRY(iterator_step_value(vm, iterated));
-
-        // b. If value is done, return undefined.
-        if (!value.has_value())
-            return js_undefined();
-
-        // c. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
-        auto result = call(vm, function.as_function(), js_undefined(), *value, Value { counter });
-
-        // d. IfAbruptCloseIterator(result, iterated).
-        if (result.is_error())
-            return *TRY(iterator_close(vm, iterated, result.release_error()));
-
-        // e. Set counter to counter + 1.
-        ++counter;
-    }
-}
-
-// 3.1.3.10 Iterator.prototype.some ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.some
+// 27.1.4.10 Iterator.prototype.some ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.some
 JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::some)
 {
     auto predicate = vm.argument(0);
@@ -651,102 +639,115 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::some)
     }
 }
 
-// 3.1.3.11 Iterator.prototype.every ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.every
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::every)
+// 27.1.4.11 Iterator.prototype.take ( limit ), https://tc39.es/ecma262/#sec-iterator.prototype.take
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::take)
 {
-    auto predicate = vm.argument(0);
+    auto& realm = *vm.current_realm();
+
+    auto limit = vm.argument(0);
 
     // 1. Let O be the this value.
     // 2. If O is not an Object, throw a TypeError exception.
     auto object = TRY(this_object(vm));
 
-    // 3. If IsCallable(predicate) is false, throw a TypeError exception.
-    if (!predicate.is_function())
-        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
+    // 3. Let numLimit be ? ToNumber(limit).
+    auto numeric_limit = TRY(limit.to_number(vm));
 
-    // 4. Let iterated be ? GetIteratorDirect(O).
+    // 4. If numLimit is NaN, throw a RangeError exception.
+    if (numeric_limit.is_nan())
+        return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
+
+    // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
+    auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
+
+    // 6. If integerLimit < 0, throw a RangeError exception.
+    if (integer_limit < 0)
+        return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
+
+    // 7. Let iterated be ? GetIteratorDirect(O).
     auto iterated = TRY(get_iterator_direct(vm, object));
 
-    // 5. Let counter be 0.
-    size_t counter = 0;
+    // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
+    auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
+        auto& iterated = iterator.underlying_iterator();
 
-    // 6. Repeat,
-    while (true) {
-        // a. Let value be ? IteratorStepValue(iterated).
+        // a. Let remaining be integerLimit.
+        // b. Repeat,
+
+        // i. If remaining is 0, then
+        if (iterator.counter() >= integer_limit) {
+            // 1. Return ? IteratorClose(iterated, NormalCompletion(undefined)).
+            return iterator.close_result(vm, normal_completion(js_undefined()));
+        }
+
+        // ii. If remaining is not +∞, then
+        //     1. Set remaining to remaining - 1.
+        iterator.increment_counter();
+
+        // iii. Let value be ? IteratorStepValue(iterated).
         auto value = TRY(iterator_step_value(vm, iterated));
 
-        // b. If value is done, return undefined.
+        // iv. If value is done, return undefined.
         if (!value.has_value())
-            return Value { true };
-
-        // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
-        auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
+            return iterator.result(js_undefined());
 
-        // d. IfAbruptCloseIterator(result, iterated).
-        if (result.is_error())
-            return *TRY(iterator_close(vm, iterated, result.release_error()));
+        // v. Let completion be Completion(Yield(value)).
+        // vi. IfAbruptCloseIterator(completion, iterated).
+        return iterator.result(*value);
+    });
 
-        // e. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)).
-        if (!result.value().to_boolean())
-            return *TRY(iterator_close(vm, iterated, normal_completion(Value { false })));
+    // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
+    // 10. Set result.[[UnderlyingIterator]] to iterated.
+    auto result = TRY(IteratorHelper::create(realm, iterated, closure));
 
-        // f. Set counter to counter + 1.
-        ++counter;
-    }
+    // 11. Return result.
+    return result;
 }
 
-// 3.1.3.12 Iterator.prototype.find ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.find
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::find)
+// 27.1.4.12 Iterator.prototype.toArray ( ), https://tc39.es/ecma262/#sec-iterator.prototype.toarray
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_array)
 {
-    auto predicate = vm.argument(0);
+    auto& realm = *vm.current_realm();
 
     // 1. Let O be the this value.
     // 2. If O is not an Object, throw a TypeError exception.
     auto object = TRY(this_object(vm));
 
-    // 3. If IsCallable(predicate) is false, throw a TypeError exception.
-    if (!predicate.is_function())
-        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
-
-    // 4. Let iterated be ? GetIteratorDirect(O).
+    // 3. Let iterated be ? GetIteratorDirect(O).
     auto iterated = TRY(get_iterator_direct(vm, object));
 
-    // 5. Let counter be 0.
-    size_t counter = 0;
+    // 4. Let items be a new empty List.
+    Vector<Value> items;
 
-    // 6. Repeat,
+    // 5. Repeat,
     while (true) {
         // a. Let value be ? IteratorStepValue(iterated).
         auto value = TRY(iterator_step_value(vm, iterated));
 
-        // b. If value is done, return undefined.
+        // b. If value is done, return CreateArrayFromList(items).
         if (!value.has_value())
-            return js_undefined();
-
-        // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
-        auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
-
-        // d. IfAbruptCloseIterator(result, iterated).
-        if (result.is_error())
-            return *TRY(iterator_close(vm, iterated, result.release_error()));
-
-        // e. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(value)).
-        if (result.value().to_boolean())
-            return *TRY(iterator_close(vm, iterated, normal_completion(value)));
+            return Array::create_from(realm, items);
 
-        // f. Set counter to counter + 1.
-        ++counter;
+        // c. Append value to items.
+        TRY_OR_THROW_OOM(vm, items.try_append(*value));
     }
 }
 
-// 3.1.3.13.1 get Iterator.prototype [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-get-iteratorprototype-@@tostringtag
+// 27.1.4.13 Iterator.prototype [ %Symbol.iterator% ] ( ), https://tc39.es/ecma262/#sec-iterator.prototype-%symbol.iterator%
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::symbol_iterator)
+{
+    // 1. Return the this value.
+    return vm.this_value();
+}
+
+// 27.1.4.14.1 get Iterator.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-get-iterator.prototype-%symbol.tostringtag%
 JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_string_tag_getter)
 {
     // 1. Return "Iterator".
     return PrimitiveString::create(vm, vm.names.Iterator.as_string());
 }
 
-// 3.1.3.13.2 set Iterator.prototype [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-set-iteratorprototype-@@tostringtag
+// 27.1.4.14.2 set Iterator.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-set-iterator.prototype-%symbol.tostringtag%
 JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_string_tag_setter)
 {
     auto& realm = *vm.current_realm();

+ 8 - 8
Userland/Libraries/LibJS/Runtime/IteratorPrototype.h

@@ -25,19 +25,19 @@ private:
     JS_DECLARE_NATIVE_FUNCTION(constructor_getter);
     JS_DECLARE_NATIVE_FUNCTION(constructor_setter);
 
-    JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
-    JS_DECLARE_NATIVE_FUNCTION(map);
-    JS_DECLARE_NATIVE_FUNCTION(filter);
-    JS_DECLARE_NATIVE_FUNCTION(take);
     JS_DECLARE_NATIVE_FUNCTION(drop);
+    JS_DECLARE_NATIVE_FUNCTION(every);
+    JS_DECLARE_NATIVE_FUNCTION(filter);
+    JS_DECLARE_NATIVE_FUNCTION(find);
     JS_DECLARE_NATIVE_FUNCTION(flat_map);
-    JS_DECLARE_NATIVE_FUNCTION(reduce);
-    JS_DECLARE_NATIVE_FUNCTION(to_array);
     JS_DECLARE_NATIVE_FUNCTION(for_each);
+    JS_DECLARE_NATIVE_FUNCTION(map);
+    JS_DECLARE_NATIVE_FUNCTION(reduce);
     JS_DECLARE_NATIVE_FUNCTION(some);
-    JS_DECLARE_NATIVE_FUNCTION(every);
-    JS_DECLARE_NATIVE_FUNCTION(find);
+    JS_DECLARE_NATIVE_FUNCTION(take);
+    JS_DECLARE_NATIVE_FUNCTION(to_array);
 
+    JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
     JS_DECLARE_NATIVE_FUNCTION(to_string_tag_getter);
     JS_DECLARE_NATIVE_FUNCTION(to_string_tag_setter);
 };

+ 4 - 4
Userland/Libraries/LibJS/Runtime/WrapForValidIteratorPrototype.cpp

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -12,7 +12,7 @@ namespace JS {
 
 JS_DEFINE_ALLOCATOR(WrapForValidIteratorPrototype);
 
-// 3.1.1.2.2.1 The %WrapForValidIteratorPrototype% Object, https://tc39.es/proposal-iterator-helpers/#sec-wrapforvaliditeratorprototype-object
+// 27.1.3.2.1.1 The %WrapForValidIteratorPrototype% Object, https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%-object
 WrapForValidIteratorPrototype::WrapForValidIteratorPrototype(Realm& realm)
     : PrototypeObject(realm.intrinsics().iterator_prototype())
 {
@@ -28,7 +28,7 @@ void WrapForValidIteratorPrototype::initialize(Realm& realm)
     define_native_function(realm, vm.names.return_, return_, 0, attr);
 }
 
-// 3.1.1.2.2.1.1 %WrapForValidIteratorPrototype%.next ( ), https://tc39.es/proposal-iterator-helpers/#sec-wrapforvaliditeratorprototype.next
+// 27.1.3.2.1.1.1 %WrapForValidIteratorPrototype%.next ( ), https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.next
 JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::next)
 {
     // 1. Let O be this value.
@@ -42,7 +42,7 @@ JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::next)
     return TRY(call(vm, iterator_record.next_method, iterator_record.iterator));
 }
 
-// 3.1.1.2.2.1.2 %WrapForValidIteratorPrototype%.return ( ), https://tc39.es/proposal-iterator-helpers/#sec-wrapforvaliditeratorprototype.return
+// 27.1.3.2.1.1.2 %WrapForValidIteratorPrototype%.return ( ), https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.return
 JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::return_)
 {
     // 1. Let O be this value.

+ 1 - 1
Userland/Libraries/LibJS/Tests/builtins/Iterator/Iterator.from.js

@@ -2,7 +2,7 @@ describe("errors", () => {
     test("called with non-Object", () => {
         expect(() => {
             Iterator.from(Symbol.hasInstance);
-        }).toThrowWithMessage(TypeError, "Symbol(Symbol.hasInstance) is not an object");
+        }).toThrowWithMessage(TypeError, "Symbol(Symbol.hasInstance) is not a string");
     });
 
     test("@@iterator is not callable", () => {