1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 20:28:11 +00:00

LibJS: Implement async functions as generator functions in BC mode

This applies a simple transformation, and adds a simple wrapper that
translates the generator interface to the async function interface.
This commit is contained in:
Ali Mohammad Pur 2021-11-11 00:46:07 +03:30 committed by Linus Groh
parent c604e95993
commit 3b0bf05fa5
14 changed files with 192 additions and 43 deletions

View file

@ -13,21 +13,21 @@
namespace JS {
ThrowCompletionOr<GeneratorObject*> GeneratorObject::create(GlobalObject& global_object, Value initial_value, ECMAScriptFunctionObject* generating_function, Environment* generating_scope, Bytecode::RegisterWindow frame)
ThrowCompletionOr<GeneratorObject*> GeneratorObject::create(GlobalObject& global_object, Value initial_value, ECMAScriptFunctionObject* generating_function, ExecutionContext execution_context, Bytecode::RegisterWindow frame)
{
// This is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
auto generating_function_prototype = TRY(generating_function->get(global_object.vm().names.prototype));
auto* generating_function_prototype_object = TRY(generating_function_prototype.to_object(global_object));
auto object = global_object.heap().allocate<GeneratorObject>(global_object, global_object, *generating_function_prototype_object);
auto object = global_object.heap().allocate<GeneratorObject>(global_object, global_object, *generating_function_prototype_object, move(execution_context));
object->m_generating_function = generating_function;
object->m_environment = generating_scope;
object->m_frame = move(frame);
object->m_previous_value = initial_value;
return object;
}
GeneratorObject::GeneratorObject(GlobalObject&, Object& prototype)
GeneratorObject::GeneratorObject(GlobalObject&, Object& prototype, ExecutionContext context)
: Object(prototype)
, m_execution_context(move(context))
{
}
@ -42,12 +42,11 @@ GeneratorObject::~GeneratorObject()
void GeneratorObject::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_environment);
visitor.visit(m_generating_function);
visitor.visit(m_previous_value);
}
ThrowCompletionOr<Value> GeneratorObject::next_impl(VM& vm, GlobalObject& global_object, Optional<Value> value_to_throw)
ThrowCompletionOr<Value> GeneratorObject::next_impl(VM& vm, GlobalObject& global_object, Optional<Value> next_argument, Optional<Value> value_to_throw)
{
auto bytecode_interpreter = Bytecode::Interpreter::current();
VERIFY(bytecode_interpreter);
@ -92,20 +91,25 @@ ThrowCompletionOr<Value> GeneratorObject::next_impl(VM& vm, GlobalObject& global
// Restore the snapshot registers
bytecode_interpreter->enter_frame(m_frame);
// Temporarily switch to the captured execution context
vm.push_execution_context(m_execution_context, global_object);
// Pretend that 'yield' returned the passed value, or threw
if (value_to_throw.has_value()) {
vm.throw_exception(global_object, value_to_throw.release_value());
bytecode_interpreter->accumulator() = js_undefined();
} else {
bytecode_interpreter->accumulator() = vm.argument(0);
bytecode_interpreter->accumulator() = next_argument.value_or(js_undefined());
}
// Temporarily switch to the captured environment record
TemporaryChange change { vm.running_execution_context().lexical_environment, m_environment };
// Temporarily switch to the captured execution context
vm.push_execution_context(m_execution_context, global_object);
m_previous_value = bytecode_interpreter->run(*m_generating_function->bytecode_executable(), next_block);
bytecode_interpreter->leave_frame();
m_frame = move(*bytecode_interpreter->pop_frame());
vm.pop_execution_context();
m_done = TRY(generated_continuation(m_previous_value)) == nullptr;