LibWeb: Make Platform::Timer GC-allocated

This will allow us to remove the use of SafeFunction in it's
implementation. This requires a fair amount of plumbing to wire up the
GC heap to the appropriate places in order to create the timers.
This commit is contained in:
Shannon Booth 2024-10-30 21:37:08 +13:00 committed by Alexander Kalenik
parent e44702f090
commit ede3c91688
Notes: github-actions[bot] 2024-10-30 19:57:28 +00:00
15 changed files with 52 additions and 38 deletions

View file

@ -28,6 +28,14 @@ ImageStyleValue::ImageStyleValue(URL::URL const& url)
ImageStyleValue::~ImageStyleValue() = default;
void ImageStyleValue::visit_edges(JS::Cell::Visitor& visitor) const
{
// FIXME: visit_edges in non-GC allocated classes is confusing pattern.
// Consider making CSSStyleValue to be GC allocated instead.
visitor.visit(m_resource_request);
visitor.visit(m_timer);
}
void ImageStyleValue::load_any_resources(DOM::Document& document)
{
if (m_resource_request)
@ -53,7 +61,7 @@ void ImageStyleValue::load_any_resources(DOM::Document& document)
auto image_data = m_resource_request->image_data();
if (image_data->is_animated() && image_data->frame_count() > 1) {
m_timer = Platform::Timer::create();
m_timer = Platform::Timer::create(m_document->heap());
m_timer->set_interval(image_data->frame_duration(0));
m_timer->on_timeout = [this] { animate(); };
m_timer->start();

View file

@ -28,12 +28,7 @@ public:
}
virtual ~ImageStyleValue() override;
void visit_edges(JS::Cell::Visitor& visitor) const
{
// FIXME: visit_edges in non-GC allocated classes is confusing pattern.
// Consider making CSSStyleValue to be GC allocated instead.
visitor.visit(m_resource_request);
}
void visit_edges(JS::Cell::Visitor& visitor) const;
virtual String to_string() const override;
virtual bool equals(CSSStyleValue const& other) const override;
@ -67,7 +62,7 @@ private:
size_t m_current_frame_index { 0 };
size_t m_loops_completed { 0 };
RefPtr<Platform::Timer> m_timer;
JS::GCPtr<Platform::Timer> m_timer;
};
}

View file

@ -48,12 +48,13 @@ void EventLoop::visit_edges(Visitor& visitor)
visitor.visit(m_currently_running_task);
visitor.visit(m_backup_incumbent_settings_object_stack);
visitor.visit(m_rendering_task_function);
visitor.visit(m_system_event_loop_timer);
}
void EventLoop::schedule()
{
if (!m_system_event_loop_timer) {
m_system_event_loop_timer = Platform::Timer::create_single_shot(0, [this] {
m_system_event_loop_timer = Platform::Timer::create_single_shot(heap(), 0, [this] {
process();
});
}

View file

@ -96,7 +96,7 @@ private:
// https://html.spec.whatwg.org/multipage/webappapis.html#last-idle-period-start-time
double m_last_idle_period_start_time { 0 };
RefPtr<Platform::Timer> m_system_event_loop_timer;
JS::GCPtr<Platform::Timer> m_system_event_loop_timer;
// https://html.spec.whatwg.org/#performing-a-microtask-checkpoint
bool m_performing_a_microtask_checkpoint { false };

View file

@ -414,8 +414,9 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
}
if (timeout.has_value() && timeout.value() > 0) {
auto timer = Platform::Timer::create_single_shot(timeout.value(), nullptr);
auto timer = Platform::Timer::create_single_shot(m_heap, timeout.value(), nullptr);
timer->on_timeout = [timer, protocol_request, timeout_callback = move(timeout_callback)] {
(void)timer;
protocol_request->stop();
if (timeout_callback)
timeout_callback();

View file

@ -7,6 +7,7 @@
#pragma once
#include <AK/Forward.h>
#include <LibJS/Heap/GCPtr.h>
#include <LibJS/SafeFunction.h>
#include <LibWeb/Forward.h>
@ -21,7 +22,7 @@ public:
virtual void spin_until(JS::SafeFunction<bool()> goal_condition) = 0;
virtual void deferred_invoke(ESCAPING JS::SafeFunction<void()>) = 0;
virtual NonnullRefPtr<Timer> create_timer() = 0;
virtual JS::NonnullGCPtr<Timer> create_timer(JS::Heap&) = 0;
virtual void quit() = 0;
};

View file

@ -25,9 +25,9 @@ void EventLoopPluginSerenity::deferred_invoke(JS::SafeFunction<void()> function)
Core::deferred_invoke(move(function));
}
NonnullRefPtr<Timer> EventLoopPluginSerenity::create_timer()
JS::NonnullGCPtr<Timer> EventLoopPluginSerenity::create_timer(JS::Heap& heap)
{
return TimerSerenity::create();
return TimerSerenity::create(heap);
}
void EventLoopPluginSerenity::quit()

View file

@ -17,7 +17,7 @@ public:
virtual void spin_until(JS::SafeFunction<bool()> goal_condition) override;
virtual void deferred_invoke(JS::SafeFunction<void()>) override;
virtual NonnullRefPtr<Timer> create_timer() override;
virtual JS::NonnullGCPtr<Timer> create_timer(JS::Heap&) override;
virtual void quit() override;
};

View file

@ -4,7 +4,6 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/NonnullRefPtr.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/Platform/Timer.h>
@ -12,23 +11,23 @@ namespace Web::Platform {
Timer::~Timer() = default;
NonnullRefPtr<Timer> Timer::create()
JS::NonnullGCPtr<Timer> Timer::create(JS::Heap& heap)
{
return EventLoopPlugin::the().create_timer();
return EventLoopPlugin::the().create_timer(heap);
}
NonnullRefPtr<Timer> Timer::create_repeating(int interval_ms, JS::SafeFunction<void()>&& timeout_handler)
JS::NonnullGCPtr<Timer> Timer::create_repeating(JS::Heap& heap, int interval_ms, JS::SafeFunction<void()>&& timeout_handler)
{
auto timer = EventLoopPlugin::the().create_timer();
auto timer = EventLoopPlugin::the().create_timer(heap);
timer->set_single_shot(false);
timer->set_interval(interval_ms);
timer->on_timeout = move(timeout_handler);
return timer;
}
NonnullRefPtr<Timer> Timer::create_single_shot(int interval_ms, JS::SafeFunction<void()>&& timeout_handler)
JS::NonnullGCPtr<Timer> Timer::create_single_shot(JS::Heap& heap, int interval_ms, JS::SafeFunction<void()>&& timeout_handler)
{
auto timer = EventLoopPlugin::the().create_timer();
auto timer = EventLoopPlugin::the().create_timer(heap);
timer->set_single_shot(true);
timer->set_interval(interval_ms);
timer->on_timeout = move(timeout_handler);

View file

@ -7,15 +7,18 @@
#pragma once
#include <AK/RefCounted.h>
#include <LibJS/Heap/Cell.h>
#include <LibJS/SafeFunction.h>
namespace Web::Platform {
class Timer : public RefCounted<Timer> {
class Timer : public JS::Cell {
JS_CELL(Timer, JS::Cell);
public:
static NonnullRefPtr<Timer> create();
static NonnullRefPtr<Timer> create_repeating(int interval_ms, JS::SafeFunction<void()>&& timeout_handler);
static NonnullRefPtr<Timer> create_single_shot(int interval_ms, JS::SafeFunction<void()>&& timeout_handler);
static JS::NonnullGCPtr<Timer> create(JS::Heap&);
static JS::NonnullGCPtr<Timer> create_repeating(JS::Heap&, int interval_ms, JS::SafeFunction<void()>&& timeout_handler);
static JS::NonnullGCPtr<Timer> create_single_shot(JS::Heap&, int interval_ms, JS::SafeFunction<void()>&& timeout_handler);
virtual ~Timer();

View file

@ -7,12 +7,13 @@
#include "TimerSerenity.h"
#include <AK/NonnullRefPtr.h>
#include <LibCore/Timer.h>
#include <LibJS/Heap/Heap.h>
namespace Web::Platform {
NonnullRefPtr<TimerSerenity> TimerSerenity::create()
JS::NonnullGCPtr<TimerSerenity> TimerSerenity::create(JS::Heap& heap)
{
return adopt_ref(*new TimerSerenity);
return heap.allocate_without_realm<TimerSerenity>();
}
TimerSerenity::TimerSerenity()

View file

@ -6,15 +6,16 @@
#pragma once
#include <AK/NonnullRefPtr.h>
#include <LibCore/Forward.h>
#include <LibWeb/Platform/Timer.h>
namespace Web::Platform {
class TimerSerenity final : public Timer {
JS_CELL(TimerSerenity, Timer);
public:
static NonnullRefPtr<TimerSerenity> create();
static JS::NonnullGCPtr<TimerSerenity> create(JS::Heap&);
virtual ~TimerSerenity();

View file

@ -876,11 +876,12 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
// 1. Wait until either reqs done flag is set or thiss timeout is not 0 and thiss timeout milliseconds have passed since now.
// 2. If reqs done flag is unset, then set thiss timed out flag and terminate thiss fetch controller.
if (m_timeout != 0) {
auto timer = Platform::Timer::create_single_shot(m_timeout, nullptr);
auto timer = Platform::Timer::create_single_shot(heap(), m_timeout, nullptr);
// NOTE: `timer` is kept alive by copying the NNRP into the lambda, incrementing its ref-count.
// NOTE: `timer` is kept alive by capturing into the lambda for the GC to see
// NOTE: `this` and `request` is kept alive by Platform::Timer using JS::SafeFunction.
timer->on_timeout = [this, request, timer]() {
(void)timer;
if (!request->done()) {
m_timed_out = true;
m_fetch_controller->terminate();
@ -929,10 +930,11 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
bool did_time_out = false;
if (m_timeout != 0) {
auto timer = Platform::Timer::create_single_shot(m_timeout, nullptr);
auto timer = Platform::Timer::create_single_shot(heap(), m_timeout, nullptr);
// NOTE: `timer` is kept alive by copying the NNRP into the lambda, incrementing its ref-count.
// NOTE: `timer` is kept alive by capturing into the lambda for the GC to see
timer->on_timeout = [timer, &did_time_out]() {
(void)timer;
did_time_out = true;
};

View file

@ -53,11 +53,12 @@
namespace WebContent {
ConnectionFromClient::ConnectionFromClient(IPC::Transport transport)
ConnectionFromClient::ConnectionFromClient(JS::Heap& heap, IPC::Transport transport)
: IPC::ConnectionFromClient<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(transport), 1)
, m_heap(heap)
, m_page_host(PageHost::create(*this))
{
m_input_event_queue_timer = Web::Platform::Timer::create_single_shot(0, [this] { process_next_input_event(); });
m_input_event_queue_timer = Web::Platform::Timer::create_single_shot(m_heap, 0, [this] { process_next_input_event(); });
}
ConnectionFromClient::~ConnectionFromClient() = default;

View file

@ -48,7 +48,7 @@ public:
Function<void(IPC::File const&)> on_image_decoder_connection;
private:
explicit ConnectionFromClient(IPC::Transport);
explicit ConnectionFromClient(JS::Heap&, IPC::Transport);
Optional<PageClient&> page(u64 index, SourceLocation = SourceLocation::current());
Optional<PageClient const&> page(u64 index, SourceLocation = SourceLocation::current()) const;
@ -150,6 +150,7 @@ private:
void report_finished_handling_input_event(u64 page_id, Web::EventResult event_was_handled);
JS::Heap& m_heap;
NonnullOwnPtr<PageHost> m_page_host;
HashMap<int, Web::FileRequest> m_requested_files {};
@ -166,7 +167,7 @@ private:
Queue<QueuedInputEvent> m_input_event_queue;
RefPtr<Web::Platform::Timer> m_input_event_queue_timer;
JS::Handle<Web::Platform::Timer> m_input_event_queue_timer;
};
}