LibJS/Bytecode: Implement for await of

Summary:
    Diff Tests:
        +391    +15    +2 💥️    -408 📝
This commit is contained in:
Luke Wilde 2023-06-27 19:24:34 +01:00 committed by Andreas Kling
parent 9b8b8c0e04
commit 363bf114c0
Notes: sideshowbarker 2024-07-17 10:10:18 +09:00
4 changed files with 43 additions and 19 deletions

View file

@ -996,6 +996,8 @@ public:
}
virtual Completion execute(Interpreter&) const override;
virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override;
virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&) const override;
virtual Completion loop_evaluation(Interpreter&, Vector<DeprecatedFlyString> const&) const override;
virtual void dump(int indent) const override;

View file

@ -2290,7 +2290,7 @@ Bytecode::CodeGenerationErrorOr<void> ThisExpression::generate_bytecode(Bytecode
return {};
}
Bytecode::CodeGenerationErrorOr<void> 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<void> 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::Op::Yield>(Bytecode::Label { continuation_block });
generator.switch_to_basic_block(continuation_block);
@ -2337,6 +2335,12 @@ Bytecode::CodeGenerationErrorOr<void> AwaitExpression::generate_bytecode(Bytecod
generator.switch_to_basic_block(normal_completion_continuation_block);
generator.emit<Bytecode::Op::Load>(received_completion_value_register);
}
Bytecode::CodeGenerationErrorOr<void> AwaitExpression::generate_bytecode(Bytecode::Generator& generator) const
{
TRY(m_argument->generate_bytecode(generator));
generate_await(generator);
return {};
}
@ -2450,29 +2454,23 @@ static Bytecode::CodeGenerationErrorOr<ForInOfHeadEvaluationResult> 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<Bytecode::Op::GetIterator>();
generator.emit<Bytecode::Op::GetIterator>(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<void> for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant<NonnullRefPtr<ASTNode const>, NonnullRefPtr<BindingPattern const>> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Vector<DeprecatedFlyString> const& label_set, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update)
static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant<NonnullRefPtr<ASTNode const>, NonnullRefPtr<BindingPattern const>> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Vector<DeprecatedFlyString> const& label_set, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update, IteratorHint iterator_kind = IteratorHint::Sync)
{
auto iterator_register = generator.allocate_register();
generator.emit<Bytecode::Op::Store>(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<void> for_in_of_body_evaluation(Bytecode:
generator.emit<Bytecode::Op::Load>(iterator_register);
generator.emit<Bytecode::Op::IteratorNext>();
// 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<Bytecode::Op::ThrowIfNotObject>();
// d. Let done be ? IteratorComplete(nextResult).
auto iterator_result_register = generator.allocate_register();
@ -2698,6 +2697,23 @@ Bytecode::CodeGenerationErrorOr<void> 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<void> ForAwaitOfStatement::generate_bytecode(Bytecode::Generator& generator) const
{
return generate_labelled_evaluation(generator, {});
}
Bytecode::CodeGenerationErrorOr<void> ForAwaitOfStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<DeprecatedFlyString> 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<void> MetaProperty::generate_bytecode(Bytecode::Generator& generator) const
{

View file

@ -1008,7 +1008,7 @@ ThrowCompletionOr<void> DeleteByValue::execute_impl(Bytecode::Interpreter& inter
ThrowCompletionOr<void> 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

View file

@ -18,6 +18,7 @@
#include <LibJS/Heap/Cell.h>
#include <LibJS/Runtime/Environment.h>
#include <LibJS/Runtime/EnvironmentCoordinate.h>
#include <LibJS/Runtime/IteratorOperations.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueTraits.h>
@ -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 {