mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-12 18:08:15 +02:00
Avoids a heap allocation per generator/async-generator resumption by storing the pending completion value and type directly on the GeneratorObject / AsyncGenerator, instead of allocating a separate CompletionCell and passing it into the executable. GetCompletionFields and SetCompletionType now read/write the fields on the generator object directly.
83 lines
3.1 KiB
C++
83 lines
3.1 KiB
C++
/*
|
|
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
|
|
* Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Variant.h>
|
|
#include <LibJS/Runtime/ExecutionContext.h>
|
|
#include <LibJS/Runtime/Object.h>
|
|
#include <LibJS/Runtime/VM.h>
|
|
|
|
namespace JS {
|
|
|
|
// 27.6.2 Properties of AsyncGenerator Instances, https://tc39.es/ecma262/#sec-properties-of-asyncgenerator-intances
|
|
class AsyncGenerator final : public Object {
|
|
JS_OBJECT(AsyncGenerator, Object);
|
|
GC_DECLARE_ALLOCATOR(AsyncGenerator);
|
|
|
|
public:
|
|
enum class State {
|
|
SuspendedStart,
|
|
SuspendedYield,
|
|
Executing,
|
|
AwaitingReturn,
|
|
Completed,
|
|
};
|
|
|
|
static GC::Ref<AsyncGenerator> create(Realm&, Variant<GC::Ref<ECMAScriptFunctionObject>, GC::Ref<NativeJavaScriptBackedFunction>>, NonnullOwnPtr<ExecutionContext>);
|
|
|
|
virtual ~AsyncGenerator() override;
|
|
|
|
void async_generator_enqueue(Completion, GC::Ref<PromiseCapability>);
|
|
ThrowCompletionOr<void> resume(VM&, Completion completion);
|
|
void await_return();
|
|
void complete_step(Completion, bool done, Realm* realm = nullptr);
|
|
void drain_queue();
|
|
|
|
State async_generator_state() const { return m_async_generator_state; }
|
|
void set_async_generator_state(Badge<AsyncGeneratorPrototype>, State value);
|
|
|
|
Optional<String> const& generator_brand() const { return m_generator_brand; }
|
|
|
|
void set_pending_completion(Completion const& completion)
|
|
{
|
|
m_pending_completion_value = completion.value();
|
|
m_pending_completion_type = completion.type();
|
|
}
|
|
Value pending_completion_value() const { return m_pending_completion_value; }
|
|
Completion::Type pending_completion_type() const { return m_pending_completion_type; }
|
|
void set_pending_completion_type(Completion::Type completion_type) { m_pending_completion_type = completion_type; }
|
|
void clear_pending_completion()
|
|
{
|
|
m_pending_completion_value = js_undefined();
|
|
m_pending_completion_type = Completion::Type::Normal;
|
|
}
|
|
|
|
private:
|
|
AsyncGenerator(Realm&, Object* prototype, NonnullOwnPtr<ExecutionContext>, GC::Ref<Bytecode::Executable>);
|
|
|
|
virtual void visit_edges(Cell::Visitor&) override;
|
|
|
|
void execute(VM&, Completion completion);
|
|
ThrowCompletionOr<void> await(Value);
|
|
|
|
// At the time of constructing an AsyncGenerator, we still need to point to an
|
|
// execution context on the stack, but later need to 'adopt' it.
|
|
State m_async_generator_state { State::SuspendedStart }; // [[AsyncGeneratorState]]
|
|
NonnullOwnPtr<ExecutionContext> m_async_generator_context; // [[AsyncGeneratorContext]]
|
|
Vector<AsyncGeneratorRequest> m_async_generator_queue; // [[AsyncGeneratorQueue]]
|
|
Optional<String> m_generator_brand; // [[GeneratorBrand]]
|
|
|
|
GC::Ref<Bytecode::Executable> m_generating_executable;
|
|
u32 m_yield_continuation { ExecutionContext::no_yield_continuation };
|
|
GC::Ptr<Promise> m_current_promise;
|
|
Value m_pending_completion_value { js_undefined() };
|
|
Completion::Type m_pending_completion_type { Completion::Type::Normal };
|
|
};
|
|
|
|
}
|