diff --git a/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp b/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp index 6087c5b99e2..0007ee97d1b 100644 --- a/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp +++ b/Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp @@ -131,11 +131,8 @@ void AsyncFunctionDriverWrapper::continue_async_execution(VM& vm, Value value, b return generator_result.throw_completion(); auto result = generator_result.release_value(); - VERIFY(result.is_object()); - - auto promise_value = TRY(result.get(vm, vm.names.value)); - - if (TRY(result.get(vm, vm.names.done)).to_boolean()) { + auto promise_value = result.value; + if (result.done) { // When returning a promise, we need to unwrap it. if (promise_value.is_object() && is(promise_value.as_object())) { auto& returned_promise = static_cast(promise_value.as_object()); diff --git a/Libraries/LibJS/Runtime/GeneratorObject.cpp b/Libraries/LibJS/Runtime/GeneratorObject.cpp index 8cf2f67958b..e7749ea5bd7 100644 --- a/Libraries/LibJS/Runtime/GeneratorObject.cpp +++ b/Libraries/LibJS/Runtime/GeneratorObject.cpp @@ -78,7 +78,7 @@ ThrowCompletionOr GeneratorObject::validate(VM& return state; } -ThrowCompletionOr GeneratorObject::execute(VM& vm, Completion const& completion) +ThrowCompletionOr GeneratorObject::execute(VM& vm, Completion const& completion) { // Loosely based on step 4 of https://tc39.es/ecma262/#sec-generatorstart mixed with https://tc39.es/ecma262/#sec-generatoryield at the end. @@ -115,24 +115,26 @@ ThrowCompletionOr GeneratorObject::execute(VM& vm, Completion const& comp if (result_value.is_throw_completion()) { // Uncaught exceptions disable the generator. m_generator_state = GeneratorState::Completed; - return result_value; + return result_value.throw_completion(); } m_previous_value = result_value.release_value(); bool done = !generated_continuation(m_previous_value).has_value(); m_generator_state = done ? GeneratorState::Completed : GeneratorState::SuspendedYield; - return create_iterator_result_object(vm, generated_value(m_previous_value), done); + + return IterationResult(generated_value(m_previous_value), done); } // 27.5.3.3 GeneratorResume ( generator, value, generatorBrand ), https://tc39.es/ecma262/#sec-generatorresume -ThrowCompletionOr GeneratorObject::resume(VM& vm, Value value, Optional const& generator_brand) +ThrowCompletionOr GeneratorObject::resume(VM& vm, Value value, Optional const& generator_brand) { // 1. Let state be ? GeneratorValidate(generator, generatorBrand). auto state = TRY(validate(vm, generator_brand)); // 2. If state is completed, return CreateIterResultObject(undefined, true). - if (state == GeneratorState::Completed) - return create_iterator_result_object(vm, js_undefined(), true); + if (state == GeneratorState::Completed) { + return IterationResult(js_undefined(), true); + } // 3. Assert: state is either suspendedStart or suspendedYield. VERIFY(state == GeneratorState::SuspendedStart || state == GeneratorState::SuspendedYield); @@ -163,7 +165,7 @@ ThrowCompletionOr GeneratorObject::resume(VM& vm, Value value, Optional GeneratorObject::resume_abrupt(JS::VM& vm, JS::Completion abrupt_completion, Optional const& generator_brand) +ThrowCompletionOr GeneratorObject::resume_abrupt(JS::VM& vm, JS::Completion abrupt_completion, Optional const& generator_brand) { // 1. Let state be ? GeneratorValidate(generator, generatorBrand). auto state = TRY(validate(vm, generator_brand)); @@ -185,7 +187,7 @@ ThrowCompletionOr GeneratorObject::resume_abrupt(JS::VM& vm, JS::Completi // a. If abruptCompletion.[[Type]] is return, then if (abrupt_completion.type() == Completion::Type::Return) { // i. Return CreateIterResultObject(abruptCompletion.[[Value]], true). - return create_iterator_result_object(vm, abrupt_completion.value(), true); + return IterationResult(abrupt_completion.value(), true); } // b. Return ? abruptCompletion. diff --git a/Libraries/LibJS/Runtime/GeneratorObject.h b/Libraries/LibJS/Runtime/GeneratorObject.h index ca3f59593ca..39286d932aa 100644 --- a/Libraries/LibJS/Runtime/GeneratorObject.h +++ b/Libraries/LibJS/Runtime/GeneratorObject.h @@ -21,8 +21,20 @@ public: virtual ~GeneratorObject() override = default; void visit_edges(Cell::Visitor&) override; - ThrowCompletionOr resume(VM&, Value value, Optional const& generator_brand); - ThrowCompletionOr resume_abrupt(VM&, JS::Completion abrupt_completion, Optional const& generator_brand); + struct IterationResult { + IterationResult() = delete; + explicit IterationResult(Value value, bool done) + : done(done) + , value(value) + { + } + + bool done { false }; + Value value; + }; + + ThrowCompletionOr resume(VM&, Value value, Optional const& generator_brand); + ThrowCompletionOr resume_abrupt(VM&, JS::Completion abrupt_completion, Optional const& generator_brand); enum class GeneratorState { SuspendedStart, @@ -37,7 +49,7 @@ protected: GeneratorObject(Realm&, Object& prototype, NonnullOwnPtr, Optional generator_brand = {}); ThrowCompletionOr validate(VM&, Optional const& generator_brand); - virtual ThrowCompletionOr execute(VM&, JS::Completion const& completion); + virtual ThrowCompletionOr execute(VM&, JS::Completion const& completion); private: NonnullOwnPtr m_execution_context; diff --git a/Libraries/LibJS/Runtime/GeneratorPrototype.cpp b/Libraries/LibJS/Runtime/GeneratorPrototype.cpp index 2a971ad8629..aae817f9a21 100644 --- a/Libraries/LibJS/Runtime/GeneratorPrototype.cpp +++ b/Libraries/LibJS/Runtime/GeneratorPrototype.cpp @@ -34,7 +34,8 @@ JS_DEFINE_NATIVE_FUNCTION(GeneratorPrototype::next) { // 1. Return ? GeneratorResume(this value, value, empty). auto generator_object = TRY(typed_this_object(vm)); - return generator_object->resume(vm, vm.argument(0), {}); + auto iteration_result = TRY(generator_object->resume(vm, vm.argument(0), {})); + return create_iterator_result_object(vm, iteration_result.value, iteration_result.done); } // 27.5.1.3 Generator.prototype.return ( value ), https://tc39.es/ecma262/#sec-generator.prototype.return @@ -47,7 +48,8 @@ JS_DEFINE_NATIVE_FUNCTION(GeneratorPrototype::return_) auto completion = Completion(Completion::Type::Return, vm.argument(0)); // 3. Return ? GeneratorResumeAbrupt(g, C, empty). - return generator_object->resume_abrupt(vm, completion, {}); + auto iteration_result = TRY(generator_object->resume_abrupt(vm, completion, {})); + return create_iterator_result_object(vm, iteration_result.value, iteration_result.done); } // 27.5.1.4 Generator.prototype.throw ( exception ), https://tc39.es/ecma262/#sec-generator.prototype.throw @@ -60,7 +62,8 @@ JS_DEFINE_NATIVE_FUNCTION(GeneratorPrototype::throw_) auto completion = throw_completion(vm.argument(0)); // 3. Return ? GeneratorResumeAbrupt(g, C, empty). - return generator_object->resume_abrupt(vm, completion, {}); + auto iteration_result = TRY(generator_object->resume_abrupt(vm, completion, {})); + return create_iterator_result_object(vm, iteration_result.value, iteration_result.done); } } diff --git a/Libraries/LibJS/Runtime/IteratorHelper.cpp b/Libraries/LibJS/Runtime/IteratorHelper.cpp index ea14a4a2958..b256d6e0edd 100644 --- a/Libraries/LibJS/Runtime/IteratorHelper.cpp +++ b/Libraries/LibJS/Runtime/IteratorHelper.cpp @@ -46,24 +46,27 @@ ThrowCompletionOr IteratorHelper::close_result(VM& vm, Completion complet return TRY(iterator_close(vm, underlying_iterator(), move(completion))); } -ThrowCompletionOr IteratorHelper::execute(VM& vm, JS::Completion const& completion) +ThrowCompletionOr IteratorHelper::execute(VM& vm, JS::Completion const& completion) { ScopeGuard guard { [&] { vm.pop_execution_context(); } }; if (completion.is_abrupt()) { - if (m_abrupt_closure) - return m_abrupt_closure->function()(vm, *this, completion); - return close_result(vm, completion); + if (m_abrupt_closure) { + auto abrupt_result = TRY(m_abrupt_closure->function()(vm, *this, completion)); + return IterationResult(abrupt_result, true); + } + auto close_result = TRY(this->close_result(vm, completion)); + return IterationResult(close_result, true); } auto result_value = m_closure->function()(vm, *this); if (result_value.is_throw_completion()) { set_generator_state(GeneratorState::Completed); - return result_value; + return result_value.throw_completion(); } - return create_iterator_result_object(vm, result(result_value.release_value()), generator_state() == GeneratorState::Completed); + return IterationResult(result(result_value.release_value()), generator_state() == GeneratorState::Completed); } } diff --git a/Libraries/LibJS/Runtime/IteratorHelper.h b/Libraries/LibJS/Runtime/IteratorHelper.h index 2ee4e7b64e6..f7aee61ff14 100644 --- a/Libraries/LibJS/Runtime/IteratorHelper.h +++ b/Libraries/LibJS/Runtime/IteratorHelper.h @@ -37,7 +37,7 @@ private: IteratorHelper(Realm&, Object& prototype, GC::Ref, GC::Ref, GC::Ptr); virtual void visit_edges(Visitor&) override; - virtual ThrowCompletionOr execute(VM&, JS::Completion const& completion) override; + virtual ThrowCompletionOr execute(VM&, JS::Completion const& completion) override; GC::Ref m_underlying_iterator; // [[UnderlyingIterator]] GC::Ref m_closure; diff --git a/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp b/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp index e09b404b818..2a4599487e2 100644 --- a/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp +++ b/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp @@ -37,7 +37,8 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::next) auto iterator = TRY(typed_this_object(vm)); // 1. Return ? GeneratorResume(this value, undefined, "Iterator Helper"). - return iterator->resume(vm, js_undefined(), "Iterator Helper"sv); + auto iteration_result = TRY(iterator->resume(vm, js_undefined(), "Iterator Helper"sv)); + return create_iterator_result_object(vm, iteration_result.value, iteration_result.done); } // 27.1.2.1.2 %IteratorHelperPrototype%.return ( ), https://tc39.es/ecma262/#sec-%iteratorhelperprototype%.return @@ -66,7 +67,8 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::return_) Completion completion { Completion::Type::Return, js_undefined() }; // 6. Return ? GeneratorResumeAbrupt(O, C, "Iterator Helper"). - return TRY(iterator->resume_abrupt(vm, move(completion), "Iterator Helper"sv)); + auto iteration_result = TRY(iterator->resume_abrupt(vm, move(completion), "Iterator Helper"sv)); + return create_iterator_result_object(vm, iteration_result.value, iteration_result.done); } }