From 363bf114c0731bc650198a783908e7eac69f9030 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Tue, 27 Jun 2023 19:24:34 +0100 Subject: [PATCH] LibJS/Bytecode: Implement for await of MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Diff Tests: +391 ✅ +15 ❌ +2 💥️ -408 📝 --- Userland/Libraries/LibJS/AST.h | 2 + .../Libraries/LibJS/Bytecode/ASTCodegen.cpp | 48 ++++++++++++------- Userland/Libraries/LibJS/Bytecode/Op.cpp | 5 +- Userland/Libraries/LibJS/Bytecode/Op.h | 7 ++- 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 332446ce47c..a149f50b937 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -996,6 +996,8 @@ public: } virtual Completion execute(Interpreter&) const override; + virtual Bytecode::CodeGenerationErrorOr generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr generate_labelled_evaluation(Bytecode::Generator&, Vector const&) const override; virtual Completion loop_evaluation(Interpreter&, Vector const&) const override; virtual void dump(int indent) const override; diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 40fb0401265..19ae9e72af6 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2290,7 +2290,7 @@ Bytecode::CodeGenerationErrorOr ThisExpression::generate_bytecode(Bytecode return {}; } -Bytecode::CodeGenerationErrorOr AwaitExpression::generate_bytecode(Bytecode::Generator& generator) const +static void generate_await(Bytecode::Generator& generator) { VERIFY(generator.is_in_async_function()); @@ -2303,8 +2303,6 @@ Bytecode::CodeGenerationErrorOr AwaitExpression::generate_bytecode(Bytecod auto type_identifier = generator.intern_identifier("type"); auto value_identifier = generator.intern_identifier("value"); - TRY(m_argument->generate_bytecode(generator)); - auto& continuation_block = generator.make_block(); generator.emit(Bytecode::Label { continuation_block }); generator.switch_to_basic_block(continuation_block); @@ -2337,6 +2335,12 @@ Bytecode::CodeGenerationErrorOr AwaitExpression::generate_bytecode(Bytecod generator.switch_to_basic_block(normal_completion_continuation_block); generator.emit(received_completion_value_register); +} + +Bytecode::CodeGenerationErrorOr AwaitExpression::generate_bytecode(Bytecode::Generator& generator) const +{ + TRY(m_argument->generate_bytecode(generator)); + generate_await(generator); return {}; } @@ -2450,29 +2454,23 @@ static Bytecode::CodeGenerationErrorOr for_in_of_he else { // a. Assert: iterationKind is iterate or async-iterate. // b. If iterationKind is async-iterate, let iteratorHint be async. - if (iteration_kind == IterationKind::AsyncIterate) { - return Bytecode::CodeGenerationError { - rhs.ptr(), - "Unimplemented iteration mode: AsyncIterate"sv, - }; - } // c. Else, let iteratorHint be sync. + auto iterator_hint = iteration_kind == IterationKind::AsyncIterate ? IteratorHint::Async : IteratorHint::Sync; // d. Return ? GetIterator(exprValue, iteratorHint). - generator.emit(); + generator.emit(iterator_hint); } return result; } // 14.7.5.7 ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind, lhsKind, labelSet [ , iteratorKind ] ), https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset -static Bytecode::CodeGenerationErrorOr for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant, NonnullRefPtr> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Vector const& label_set, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update) +static Bytecode::CodeGenerationErrorOr for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant, NonnullRefPtr> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Vector const& label_set, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update, IteratorHint iterator_kind = IteratorHint::Sync) { auto iterator_register = generator.allocate_register(); generator.emit(iterator_register); - // FIXME: Implement this - // 1. If iteratorKind is not present, set iteratorKind to sync. + // 1. If iteratorKind is not present, set iteratorKind to sync. // 2. Let oldEnv be the running execution context's LexicalEnvironment. bool has_lexical_binding = false; @@ -2502,11 +2500,12 @@ static Bytecode::CodeGenerationErrorOr for_in_of_body_evaluation(Bytecode: generator.emit(iterator_register); generator.emit(); - // FIXME: Implement this: - // b. If iteratorKind is async, set nextResult to ? Await(nextResult). + // b. If iteratorKind is async, set nextResult to ? Await(nextResult). + if (iterator_kind == IteratorHint::Async) + generate_await(generator); // c. If Type(nextResult) is not Object, throw a TypeError exception. - // NOTE: IteratorComplete already does this. + generator.emit(); // d. Let done be ? IteratorComplete(nextResult). auto iterator_result_register = generator.allocate_register(); @@ -2698,6 +2697,23 @@ Bytecode::CodeGenerationErrorOr ForOfStatement::generate_labelled_evaluati return for_in_of_body_evaluation(generator, *this, m_lhs, body(), head_result, label_set, loop_end, loop_update); } +Bytecode::CodeGenerationErrorOr ForAwaitOfStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + return generate_labelled_evaluation(generator, {}); +} + +Bytecode::CodeGenerationErrorOr ForAwaitOfStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set) const +{ + auto& loop_end = generator.make_block(); + auto& loop_update = generator.make_block(); + generator.begin_breakable_scope(Bytecode::Label { loop_end }, label_set); + + auto head_result = TRY(for_in_of_head_evaluation(generator, IterationKind::AsyncIterate, m_lhs, m_rhs)); + + // Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over. + return for_in_of_body_evaluation(generator, *this, m_lhs, m_body, head_result, label_set, loop_end, loop_update, IteratorHint::Async); +} + // 13.3.12.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation Bytecode::CodeGenerationErrorOr MetaProperty::generate_bytecode(Bytecode::Generator& generator) const { diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 5f49f4d92bb..e48c4af61f5 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -1008,7 +1008,7 @@ ThrowCompletionOr DeleteByValue::execute_impl(Bytecode::Interpreter& inter ThrowCompletionOr GetIterator::execute_impl(Bytecode::Interpreter& interpreter) const { auto& vm = interpreter.vm(); - auto iterator = TRY(get_iterator(vm, interpreter.accumulator())); + auto iterator = TRY(get_iterator(vm, interpreter.accumulator(), m_hint)); interpreter.accumulator() = iterator_to_object(vm, iterator); return {}; } @@ -1525,7 +1525,8 @@ DeprecatedString DeleteByValue::to_deprecated_string_impl(Bytecode::Executable c DeprecatedString GetIterator::to_deprecated_string_impl(Executable const&) const { - return "GetIterator"; + auto hint = m_hint == IteratorHint::Sync ? "sync" : "async"; + return DeprecatedString::formatted("GetIterator hint:{}", hint); } DeprecatedString GetMethod::to_deprecated_string_impl(Bytecode::Executable const& executable) const diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 7c4b5245a46..588ed811193 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1125,8 +1126,9 @@ private: class GetIterator final : public Instruction { public: - GetIterator() + GetIterator(IteratorHint hint = IteratorHint::Sync) : Instruction(Type::GetIterator) + , m_hint(hint) { } @@ -1134,6 +1136,9 @@ public: DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; void replace_references_impl(BasicBlock const&, BasicBlock const&) { } void replace_references_impl(Register, Register) { } + +private: + IteratorHint m_hint { IteratorHint::Sync }; }; class GetMethod final : public Instruction {