LibWeb: Make EventLoop, TaskQueue, and Task GC-allocated

...and use HeapFunction instead of SafeFunction for task steps.

Since there is only one EventLoop per process, it lives as a global
handle in the VM custom data.

This makes it much easier to reason about lifetimes of tasks, task
steps, and random stuff captured by them.
This commit is contained in:
Andreas Kling
2024-04-04 12:06:50 +02:00
parent 5485e2a940
commit 2ef37c0b06
20 changed files with 167 additions and 124 deletions

View File

@@ -15,7 +15,9 @@
namespace Web::HTML {
class EventLoop {
class EventLoop : public JS::Cell {
JS_CELL(EventLoop, Cell);
public:
enum class Type {
// https://html.spec.whatwg.org/multipage/webappapis.html#window-event-loop
@@ -26,16 +28,15 @@ public:
Worklet,
};
EventLoop();
~EventLoop();
virtual ~EventLoop() override;
Type type() const { return m_type; }
TaskQueue& task_queue() { return m_task_queue; }
TaskQueue const& task_queue() const { return m_task_queue; }
TaskQueue& task_queue() { return *m_task_queue; }
TaskQueue const& task_queue() const { return *m_task_queue; }
TaskQueue& microtask_queue() { return m_microtask_queue; }
TaskQueue const& microtask_queue() const { return m_microtask_queue; }
TaskQueue& microtask_queue() { return *m_microtask_queue; }
TaskQueue const& microtask_queue() const { return *m_microtask_queue; }
void spin_until(JS::SafeFunction<bool()> goal_condition);
void spin_processing_tasks_with_source_until(Task::Source, JS::SafeFunction<bool()> goal_condition);
@@ -48,11 +49,6 @@ public:
Task const* currently_running_task() const { return m_currently_running_task; }
JS::VM& vm() { return *m_vm; }
JS::VM const& vm() const { return *m_vm; }
void set_vm(JS::VM&);
void schedule();
void perform_a_microtask_checkpoint();
@@ -79,21 +75,23 @@ public:
bool execution_paused() const { return m_execution_paused; }
private:
EventLoop();
virtual void visit_edges(Visitor&) override;
Type m_type { Type::Window };
TaskQueue m_task_queue;
TaskQueue m_microtask_queue;
JS::GCPtr<TaskQueue> m_task_queue;
JS::GCPtr<TaskQueue> m_microtask_queue;
// https://html.spec.whatwg.org/multipage/webappapis.html#currently-running-task
Task* m_currently_running_task { nullptr };
JS::GCPtr<Task> m_currently_running_task { nullptr };
// https://html.spec.whatwg.org/multipage/webappapis.html#last-render-opportunity-time
double m_last_render_opportunity_time { 0 };
// https://html.spec.whatwg.org/multipage/webappapis.html#last-idle-period-start-time
double m_last_idle_period_start_time { 0 };
JS::VM* m_vm { nullptr };
RefPtr<Platform::Timer> m_system_event_loop_timer;
// https://html.spec.whatwg.org/#performing-a-microtask-checkpoint
@@ -102,7 +100,8 @@ private:
Vector<WeakPtr<DOM::Document>> m_documents;
// Used to implement step 4 of "perform a microtask checkpoint".
Vector<JS::NonnullGCPtr<EnvironmentSettingsObject>> m_related_environment_settings_objects;
// NOTE: These are weak references! ESO registers and unregisters itself from the event loop manually.
Vector<RawPtr<EnvironmentSettingsObject>> m_related_environment_settings_objects;
// https://html.spec.whatwg.org/multipage/webappapis.html#backup-incumbent-settings-object-stack
Vector<JS::NonnullGCPtr<EnvironmentSettingsObject>> m_backup_incumbent_settings_object_stack;
@@ -116,8 +115,8 @@ private:
};
EventLoop& main_thread_event_loop();
int queue_global_task(HTML::Task::Source, JS::Object&, JS::SafeFunction<void()> steps);
void queue_a_microtask(DOM::Document const*, JS::SafeFunction<void()> steps);
int queue_global_task(HTML::Task::Source, JS::Object&, Function<void()> steps);
void queue_a_microtask(DOM::Document const*, Function<void()> steps);
void perform_a_microtask_checkpoint();
}