mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 03:55:24 +00:00
LibWeb: Add a simple internals
objects only available during testing
This object is available as `window.internals` (or just `internals`) and is only accessible while running in "test mode". This first version only has one API: gc(), which triggers a garbage collection immediately. In the future, we can add more APIs here to help us test parts of the engine that are hard or impossible to reach via public web APIs.
This commit is contained in:
parent
ba236e3f21
commit
ec24d7555a
Notes:
sideshowbarker
2024-07-18 00:34:07 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/ec24d7555a Pull-request: https://github.com/SerenityOS/serenity/pull/20394
14 changed files with 109 additions and 5 deletions
|
@ -23,6 +23,7 @@
|
|||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibMain/Main.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
#include <LibWeb/Loader/FrameLoader.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
|
@ -89,6 +90,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
Web::WebSockets::WebSocketClientManager::initialize(Ladybird::WebSocketClientManagerQt::create());
|
||||
}
|
||||
|
||||
Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode);
|
||||
|
||||
JS::Bytecode::Interpreter::set_enabled(use_javascript_bytecode);
|
||||
|
||||
VERIFY(webcontent_fd_passing_socket >= 0);
|
||||
|
|
|
@ -3126,6 +3126,7 @@ using namespace Web::FileAPI;
|
|||
using namespace Web::Geometry;
|
||||
using namespace Web::HighResolutionTime;
|
||||
using namespace Web::HTML;
|
||||
using namespace Web::Internals;
|
||||
using namespace Web::IntersectionObserver;
|
||||
using namespace Web::RequestIdleCallback;
|
||||
using namespace Web::ResizeObserver;
|
||||
|
@ -3342,6 +3343,7 @@ using namespace Web::FileAPI;
|
|||
using namespace Web::Geometry;
|
||||
using namespace Web::HighResolutionTime;
|
||||
using namespace Web::HTML;
|
||||
using namespace Web::Internals;
|
||||
using namespace Web::IntersectionObserver;
|
||||
using namespace Web::PerformanceTimeline;
|
||||
using namespace Web::RequestIdleCallback;
|
||||
|
@ -3723,6 +3725,7 @@ using namespace Web::FileAPI;
|
|||
using namespace Web::Geometry;
|
||||
using namespace Web::HighResolutionTime;
|
||||
using namespace Web::HTML;
|
||||
using namespace Web::Internals;
|
||||
using namespace Web::IntersectionObserver;
|
||||
using namespace Web::NavigationTiming;
|
||||
using namespace Web::PerformanceTimeline;
|
||||
|
@ -3858,6 +3861,7 @@ using namespace Web::FileAPI;
|
|||
using namespace Web::Geometry;
|
||||
using namespace Web::HighResolutionTime;
|
||||
using namespace Web::HTML;
|
||||
using namespace Web::Internals;
|
||||
using namespace Web::IntersectionObserver;
|
||||
using namespace Web::NavigationTiming;
|
||||
using namespace Web::PerformanceTimeline;
|
||||
|
@ -3990,6 +3994,7 @@ using namespace Web::FileAPI;
|
|||
using namespace Web::Geometry;
|
||||
using namespace Web::HighResolutionTime;
|
||||
using namespace Web::HTML;
|
||||
using namespace Web::Internals;
|
||||
using namespace Web::IntersectionObserver;
|
||||
using namespace Web::NavigationTiming;
|
||||
using namespace Web::PerformanceTimeline;
|
||||
|
|
|
@ -23,6 +23,7 @@ static constexpr Array libweb_interface_namespaces = {
|
|||
"Geometry"sv,
|
||||
"HTML"sv,
|
||||
"HighResolutionTime"sv,
|
||||
"Internals"sv,
|
||||
"IntersectionObserver"sv,
|
||||
"NavigationTiming"sv,
|
||||
"RequestIdleCallback"sv,
|
||||
|
|
|
@ -178,7 +178,7 @@ void Intrinsics::create_web_namespace<@namespace_class@>(JS::Realm& realm)
|
|||
)~~~");
|
||||
};
|
||||
|
||||
auto add_interface = [&](SourceGenerator& gen, StringView name, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor) {
|
||||
auto add_interface = [](SourceGenerator& gen, StringView name, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor) {
|
||||
gen.set("interface_name", name);
|
||||
gen.set("prototype_class", prototype_class);
|
||||
gen.set("constructor_class", constructor_class);
|
||||
|
@ -434,6 +434,8 @@ static ErrorOr<ExposedTo> parse_exposure_set(IDL::Interface& interface)
|
|||
auto exposed = maybe_exposed.value().trim_whitespace();
|
||||
if (exposed == "*"sv)
|
||||
return ExposedTo::All;
|
||||
if (exposed == "Nobody"sv)
|
||||
return ExposedTo::Nobody;
|
||||
if (exposed == "Window"sv)
|
||||
return ExposedTo::Window;
|
||||
if (exposed == "Worker"sv)
|
||||
|
@ -477,10 +479,8 @@ ErrorOr<void> add_to_interface_sets(IDL::Interface& interface, Vector<IDL::Inter
|
|||
{
|
||||
// TODO: Add service worker exposed and audio worklet exposed
|
||||
auto whom = TRY(parse_exposure_set(interface));
|
||||
VERIFY(whom != ExposedTo::Nobody);
|
||||
|
||||
if ((whom & ExposedTo::Window) || (whom & ExposedTo::DedicatedWorker) || (whom & ExposedTo::SharedWorker))
|
||||
intrinsics.append(interface);
|
||||
intrinsics.append(interface);
|
||||
|
||||
if (whom & ExposedTo::Window)
|
||||
window_exposed.append(interface);
|
||||
|
|
3
Tests/LibWeb/Text/expected/internals.txt
Normal file
3
Tests/LibWeb/Text/expected/internals.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
[object Internals]
|
||||
function gc() { [native code] }
|
||||
OK
|
9
Tests/LibWeb/Text/input/internals.html
Normal file
9
Tests/LibWeb/Text/input/internals.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<script src="include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
println(window.internals);
|
||||
println(internals.gc);
|
||||
internals.gc();
|
||||
println("OK");
|
||||
});
|
||||
</script>
|
|
@ -397,6 +397,7 @@ set(SOURCES
|
|||
Infra/ByteSequences.cpp
|
||||
Infra/JSON.cpp
|
||||
Infra/Strings.cpp
|
||||
Internals/Internals.cpp
|
||||
IntersectionObserver/IntersectionObserver.cpp
|
||||
IntersectionObserver/IntersectionObserverEntry.cpp
|
||||
Layout/AudioBox.cpp
|
||||
|
|
|
@ -454,6 +454,10 @@ namespace Web::HighResolutionTime {
|
|||
class Performance;
|
||||
}
|
||||
|
||||
namespace Web::Internals {
|
||||
class Internals;
|
||||
}
|
||||
|
||||
namespace Web::IntersectionObserver {
|
||||
class IntersectionObserver;
|
||||
class IntersectionObserverEntry;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020-2023, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
|
@ -51,6 +51,7 @@
|
|||
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
|
||||
#include <LibWeb/Infra/Base64.h>
|
||||
#include <LibWeb/Infra/CharacterTypes.h>
|
||||
#include <LibWeb/Internals/Internals.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/RequestIdleCallback/IdleDeadline.h>
|
||||
|
@ -805,6 +806,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::CallbackType>> Window::byte_length_
|
|||
return JS::NonnullGCPtr { *m_byte_length_queuing_strategy_size_function };
|
||||
}
|
||||
|
||||
static bool s_internals_object_exposed = false;
|
||||
|
||||
void Window::set_internals_object_exposed(bool exposed)
|
||||
{
|
||||
s_internals_object_exposed = exposed;
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> Window::initialize_web_interfaces(Badge<WindowEnvironmentSettingsObject>)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
@ -815,6 +823,9 @@ WebIDL::ExceptionOr<void> Window::initialize_web_interfaces(Badge<WindowEnvironm
|
|||
MUST_OR_THROW_OOM(Bindings::WindowGlobalMixin::initialize(realm, *this));
|
||||
MUST_OR_THROW_OOM(WindowOrWorkerGlobalScopeMixin::initialize(realm));
|
||||
|
||||
if (s_internals_object_exposed)
|
||||
define_direct_property("internals", MUST_OR_THROW_OOM(heap().allocate<Internals::Internals>(realm, realm)), JS::default_attributes);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,8 @@ public:
|
|||
HighResolutionTime::DOMHighResTimeStamp get_last_activation_timestamp() const { return m_last_activation_timestamp; }
|
||||
void set_last_activation_timestamp(HighResolutionTime::DOMHighResTimeStamp timestamp) { m_last_activation_timestamp = timestamp; }
|
||||
|
||||
static void set_internals_object_exposed(bool);
|
||||
|
||||
private:
|
||||
explicit Window(JS::Realm&);
|
||||
|
||||
|
|
33
Userland/Libraries/LibWeb/Internals/Internals.cpp
Normal file
33
Userland/Libraries/LibWeb/Internals/Internals.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/Bindings/InternalsPrototype.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Internals/Internals.h>
|
||||
|
||||
namespace Web::Internals {
|
||||
|
||||
Internals::Internals(JS::Realm& realm)
|
||||
: Bindings::PlatformObject(realm)
|
||||
{
|
||||
}
|
||||
|
||||
Internals::~Internals() = default;
|
||||
|
||||
JS::ThrowCompletionOr<void> Internals::initialize(JS::Realm& realm)
|
||||
{
|
||||
TRY(Base::initialize(realm));
|
||||
Object::set_prototype(&Bindings::ensure_web_prototype<Bindings::InternalsPrototype>(realm, "Internals"));
|
||||
return {};
|
||||
}
|
||||
|
||||
void Internals::gc()
|
||||
{
|
||||
vm().heap().collect_garbage();
|
||||
}
|
||||
|
||||
}
|
26
Userland/Libraries/LibWeb/Internals/Internals.h
Normal file
26
Userland/Libraries/LibWeb/Internals/Internals.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
|
||||
namespace Web::Internals {
|
||||
|
||||
class Internals final : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(Internals, Bindings::PlatformObject);
|
||||
|
||||
public:
|
||||
virtual ~Internals() override;
|
||||
|
||||
void gc();
|
||||
|
||||
private:
|
||||
explicit Internals(JS::Realm&);
|
||||
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
||||
};
|
||||
|
||||
}
|
5
Userland/Libraries/LibWeb/Internals/Internals.idl
Normal file
5
Userland/Libraries/LibWeb/Internals/Internals.idl
Normal file
|
@ -0,0 +1,5 @@
|
|||
[Exposed=Nobody] interface Internals {
|
||||
|
||||
undefined gc();
|
||||
|
||||
};
|
|
@ -183,6 +183,7 @@ libweb_js_bindings(HTML/WorkerGlobalScope)
|
|||
libweb_js_bindings(HTML/WorkerLocation)
|
||||
libweb_js_bindings(HTML/WorkerNavigator)
|
||||
libweb_js_bindings(HighResolutionTime/Performance)
|
||||
libweb_js_bindings(Internals/Internals)
|
||||
libweb_js_bindings(IntersectionObserver/IntersectionObserver)
|
||||
libweb_js_bindings(IntersectionObserver/IntersectionObserverEntry)
|
||||
libweb_js_bindings(NavigationTiming/PerformanceTiming)
|
||||
|
|
Loading…
Add table
Reference in a new issue