mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-07 16:49:54 +00:00
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:
parent
e44702f090
commit
ede3c91688
Notes:
github-actions[bot]
2024-10-30 19:57:28 +00:00
Author: https://github.com/shannonbooth
Commit: ede3c91688
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2062
Reviewed-by: https://github.com/kalenikaliaksandr ✅
15 changed files with 52 additions and 38 deletions
|
@ -28,6 +28,14 @@ ImageStyleValue::ImageStyleValue(URL::URL const& url)
|
||||||
|
|
||||||
ImageStyleValue::~ImageStyleValue() = default;
|
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)
|
void ImageStyleValue::load_any_resources(DOM::Document& document)
|
||||||
{
|
{
|
||||||
if (m_resource_request)
|
if (m_resource_request)
|
||||||
|
@ -53,7 +61,7 @@ void ImageStyleValue::load_any_resources(DOM::Document& document)
|
||||||
|
|
||||||
auto image_data = m_resource_request->image_data();
|
auto image_data = m_resource_request->image_data();
|
||||||
if (image_data->is_animated() && image_data->frame_count() > 1) {
|
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->set_interval(image_data->frame_duration(0));
|
||||||
m_timer->on_timeout = [this] { animate(); };
|
m_timer->on_timeout = [this] { animate(); };
|
||||||
m_timer->start();
|
m_timer->start();
|
||||||
|
|
|
@ -28,12 +28,7 @@ public:
|
||||||
}
|
}
|
||||||
virtual ~ImageStyleValue() override;
|
virtual ~ImageStyleValue() override;
|
||||||
|
|
||||||
void visit_edges(JS::Cell::Visitor& visitor) const
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual String to_string() const override;
|
virtual String to_string() const override;
|
||||||
virtual bool equals(CSSStyleValue const& other) 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_current_frame_index { 0 };
|
||||||
size_t m_loops_completed { 0 };
|
size_t m_loops_completed { 0 };
|
||||||
RefPtr<Platform::Timer> m_timer;
|
JS::GCPtr<Platform::Timer> m_timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,13 @@ void EventLoop::visit_edges(Visitor& visitor)
|
||||||
visitor.visit(m_currently_running_task);
|
visitor.visit(m_currently_running_task);
|
||||||
visitor.visit(m_backup_incumbent_settings_object_stack);
|
visitor.visit(m_backup_incumbent_settings_object_stack);
|
||||||
visitor.visit(m_rendering_task_function);
|
visitor.visit(m_rendering_task_function);
|
||||||
|
visitor.visit(m_system_event_loop_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::schedule()
|
void EventLoop::schedule()
|
||||||
{
|
{
|
||||||
if (!m_system_event_loop_timer) {
|
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();
|
process();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ private:
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#last-idle-period-start-time
|
// https://html.spec.whatwg.org/multipage/webappapis.html#last-idle-period-start-time
|
||||||
double m_last_idle_period_start_time { 0 };
|
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
|
// https://html.spec.whatwg.org/#performing-a-microtask-checkpoint
|
||||||
bool m_performing_a_microtask_checkpoint { false };
|
bool m_performing_a_microtask_checkpoint { false };
|
||||||
|
|
|
@ -414,8 +414,9 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout.has_value() && timeout.value() > 0) {
|
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)] {
|
timer->on_timeout = [timer, protocol_request, timeout_callback = move(timeout_callback)] {
|
||||||
|
(void)timer;
|
||||||
protocol_request->stop();
|
protocol_request->stop();
|
||||||
if (timeout_callback)
|
if (timeout_callback)
|
||||||
timeout_callback();
|
timeout_callback();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibJS/SafeFunction.h>
|
#include <LibJS/SafeFunction.h>
|
||||||
#include <LibWeb/Forward.h>
|
#include <LibWeb/Forward.h>
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ public:
|
||||||
|
|
||||||
virtual void spin_until(JS::SafeFunction<bool()> goal_condition) = 0;
|
virtual void spin_until(JS::SafeFunction<bool()> goal_condition) = 0;
|
||||||
virtual void deferred_invoke(ESCAPING JS::SafeFunction<void()>) = 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;
|
virtual void quit() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@ void EventLoopPluginSerenity::deferred_invoke(JS::SafeFunction<void()> function)
|
||||||
Core::deferred_invoke(move(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()
|
void EventLoopPluginSerenity::quit()
|
||||||
|
|
|
@ -17,7 +17,7 @@ public:
|
||||||
|
|
||||||
virtual void spin_until(JS::SafeFunction<bool()> goal_condition) override;
|
virtual void spin_until(JS::SafeFunction<bool()> goal_condition) override;
|
||||||
virtual void deferred_invoke(JS::SafeFunction<void()>) 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;
|
virtual void quit() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/NonnullRefPtr.h>
|
|
||||||
#include <LibWeb/Platform/EventLoopPlugin.h>
|
#include <LibWeb/Platform/EventLoopPlugin.h>
|
||||||
#include <LibWeb/Platform/Timer.h>
|
#include <LibWeb/Platform/Timer.h>
|
||||||
|
|
||||||
|
@ -12,23 +11,23 @@ namespace Web::Platform {
|
||||||
|
|
||||||
Timer::~Timer() = default;
|
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_single_shot(false);
|
||||||
timer->set_interval(interval_ms);
|
timer->set_interval(interval_ms);
|
||||||
timer->on_timeout = move(timeout_handler);
|
timer->on_timeout = move(timeout_handler);
|
||||||
return timer;
|
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_single_shot(true);
|
||||||
timer->set_interval(interval_ms);
|
timer->set_interval(interval_ms);
|
||||||
timer->on_timeout = move(timeout_handler);
|
timer->on_timeout = move(timeout_handler);
|
||||||
|
|
|
@ -7,15 +7,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
|
#include <LibJS/Heap/Cell.h>
|
||||||
#include <LibJS/SafeFunction.h>
|
#include <LibJS/SafeFunction.h>
|
||||||
|
|
||||||
namespace Web::Platform {
|
namespace Web::Platform {
|
||||||
|
|
||||||
class Timer : public RefCounted<Timer> {
|
class Timer : public JS::Cell {
|
||||||
|
JS_CELL(Timer, JS::Cell);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static NonnullRefPtr<Timer> create();
|
static JS::NonnullGCPtr<Timer> create(JS::Heap&);
|
||||||
static NonnullRefPtr<Timer> create_repeating(int interval_ms, JS::SafeFunction<void()>&& timeout_handler);
|
static JS::NonnullGCPtr<Timer> create_repeating(JS::Heap&, 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_single_shot(JS::Heap&, int interval_ms, JS::SafeFunction<void()>&& timeout_handler);
|
||||||
|
|
||||||
virtual ~Timer();
|
virtual ~Timer();
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,13 @@
|
||||||
#include "TimerSerenity.h"
|
#include "TimerSerenity.h"
|
||||||
#include <AK/NonnullRefPtr.h>
|
#include <AK/NonnullRefPtr.h>
|
||||||
#include <LibCore/Timer.h>
|
#include <LibCore/Timer.h>
|
||||||
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
|
||||||
namespace Web::Platform {
|
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()
|
TimerSerenity::TimerSerenity()
|
||||||
|
|
|
@ -6,15 +6,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/NonnullRefPtr.h>
|
|
||||||
#include <LibCore/Forward.h>
|
#include <LibCore/Forward.h>
|
||||||
#include <LibWeb/Platform/Timer.h>
|
#include <LibWeb/Platform/Timer.h>
|
||||||
|
|
||||||
namespace Web::Platform {
|
namespace Web::Platform {
|
||||||
|
|
||||||
class TimerSerenity final : public Timer {
|
class TimerSerenity final : public Timer {
|
||||||
|
JS_CELL(TimerSerenity, Timer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static NonnullRefPtr<TimerSerenity> create();
|
static JS::NonnullGCPtr<TimerSerenity> create(JS::Heap&);
|
||||||
|
|
||||||
virtual ~TimerSerenity();
|
virtual ~TimerSerenity();
|
||||||
|
|
||||||
|
|
|
@ -876,11 +876,12 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
||||||
// 1. Wait until either req’s done flag is set or this’s timeout is not 0 and this’s timeout milliseconds have passed since now.
|
// 1. Wait until either req’s done flag is set or this’s timeout is not 0 and this’s timeout milliseconds have passed since now.
|
||||||
// 2. If req’s done flag is unset, then set this’s timed out flag and terminate this’s fetch controller.
|
// 2. If req’s done flag is unset, then set this’s timed out flag and terminate this’s fetch controller.
|
||||||
if (m_timeout != 0) {
|
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.
|
// NOTE: `this` and `request` is kept alive by Platform::Timer using JS::SafeFunction.
|
||||||
timer->on_timeout = [this, request, timer]() {
|
timer->on_timeout = [this, request, timer]() {
|
||||||
|
(void)timer;
|
||||||
if (!request->done()) {
|
if (!request->done()) {
|
||||||
m_timed_out = true;
|
m_timed_out = true;
|
||||||
m_fetch_controller->terminate();
|
m_fetch_controller->terminate();
|
||||||
|
@ -929,10 +930,11 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
||||||
bool did_time_out = false;
|
bool did_time_out = false;
|
||||||
|
|
||||||
if (m_timeout != 0) {
|
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]() {
|
timer->on_timeout = [timer, &did_time_out]() {
|
||||||
|
(void)timer;
|
||||||
did_time_out = true;
|
did_time_out = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,11 +53,12 @@
|
||||||
|
|
||||||
namespace WebContent {
|
namespace WebContent {
|
||||||
|
|
||||||
ConnectionFromClient::ConnectionFromClient(IPC::Transport transport)
|
ConnectionFromClient::ConnectionFromClient(JS::Heap& heap, IPC::Transport transport)
|
||||||
: IPC::ConnectionFromClient<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(transport), 1)
|
: IPC::ConnectionFromClient<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(transport), 1)
|
||||||
|
, m_heap(heap)
|
||||||
, m_page_host(PageHost::create(*this))
|
, 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;
|
ConnectionFromClient::~ConnectionFromClient() = default;
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
Function<void(IPC::File const&)> on_image_decoder_connection;
|
Function<void(IPC::File const&)> on_image_decoder_connection;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ConnectionFromClient(IPC::Transport);
|
explicit ConnectionFromClient(JS::Heap&, IPC::Transport);
|
||||||
|
|
||||||
Optional<PageClient&> page(u64 index, SourceLocation = SourceLocation::current());
|
Optional<PageClient&> page(u64 index, SourceLocation = SourceLocation::current());
|
||||||
Optional<PageClient const&> page(u64 index, SourceLocation = SourceLocation::current()) const;
|
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);
|
void report_finished_handling_input_event(u64 page_id, Web::EventResult event_was_handled);
|
||||||
|
|
||||||
|
JS::Heap& m_heap;
|
||||||
NonnullOwnPtr<PageHost> m_page_host;
|
NonnullOwnPtr<PageHost> m_page_host;
|
||||||
|
|
||||||
HashMap<int, Web::FileRequest> m_requested_files {};
|
HashMap<int, Web::FileRequest> m_requested_files {};
|
||||||
|
@ -166,7 +167,7 @@ private:
|
||||||
|
|
||||||
Queue<QueuedInputEvent> m_input_event_queue;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue