1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 17:47:36 +00:00

Ladybird+LibJS: Add CLI option to run browser with LibJS bytecode VM

This required quite a bit of plumbing, but now you can run

    ladybird --use-bytecode
This commit is contained in:
Andreas Kling 2023-06-17 13:16:35 +02:00
parent 7ec7015750
commit 9c568282dc
20 changed files with 91 additions and 38 deletions

View file

@ -8,9 +8,11 @@
#include <AK/TemporaryChange.h>
#include <LibJS/AST.h>
#include <LibJS/Bytecode/BasicBlock.h>
#include <LibJS/Bytecode/Generator.h>
#include <LibJS/Bytecode/Instruction.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/Bytecode/PassManager.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/GlobalEnvironment.h>
#include <LibJS/Runtime/GlobalObject.h>
@ -18,6 +20,18 @@
namespace JS::Bytecode {
static bool s_bytecode_interpreter_enabled = false;
bool Interpreter::enabled()
{
return s_bytecode_interpreter_enabled;
}
void Interpreter::set_enabled(bool enabled)
{
s_bytecode_interpreter_enabled = enabled;
}
static Interpreter* s_current;
bool g_dump_bytecode = false;
@ -425,4 +439,14 @@ Bytecode::PassManager& Interpreter::optimization_pipeline(Interpreter::Optimizat
return passes;
}
size_t Interpreter::pc() const
{
return m_pc ? m_pc->offset() : 0;
}
DeprecatedString Interpreter::debug_position() const
{
return DeprecatedString::formatted("{}:{:2}:{:4x}", m_current_executable->name, m_current_block->name(), pc());
}
}

View file

@ -6,8 +6,6 @@
#pragma once
#include "Generator.h"
#include "PassManager.h"
#include <LibJS/Bytecode/Label.h>
#include <LibJS/Bytecode/Register.h>
#include <LibJS/Forward.h>
@ -18,6 +16,9 @@
namespace JS::Bytecode {
class InstructionStreamIterator;
class PassManager;
struct RegisterWindow {
MarkedVector<Value> registers;
MarkedVector<GCPtr<Environment>> saved_lexical_environments;
@ -27,6 +28,9 @@ struct RegisterWindow {
class Interpreter {
public:
[[nodiscard]] static bool enabled();
static void set_enabled(bool);
explicit Interpreter(Realm&);
~Interpreter();
@ -82,11 +86,8 @@ public:
Executable const& current_executable() { return *m_current_executable; }
BasicBlock const& current_block() const { return *m_current_block; }
size_t pc() const { return m_pc ? m_pc->offset() : 0; }
DeprecatedString debug_position()
{
return DeprecatedString::formatted("{}:{:2}:{:4x}", m_current_executable->name, m_current_block->name(), pc());
}
size_t pc() const;
DeprecatedString debug_position() const;
enum class OptimizationLevel {
None,

View file

@ -12,6 +12,7 @@
#include <LibJS/Bytecode/BasicBlock.h>
#include <LibJS/Bytecode/Generator.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibJS/Bytecode/PassManager.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Array.h>

View file

@ -1,11 +1,12 @@
/*
* Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2023, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Debug.h>
#include <LibCore/ElapsedTimer.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibJS/Interpreter.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/HTML/Scripting/ClassicScript.h>
@ -94,9 +95,13 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors, JS::GCPtr<JS::En
auto timer = Core::ElapsedTimer::start_new();
// 6. Otherwise, set evaluationStatus to ScriptEvaluation(script's record).
auto interpreter = JS::Interpreter::create_with_existing_realm(m_script_record->realm());
evaluation_status = interpreter->run(*m_script_record, lexical_environment_override);
if (JS::Bytecode::Interpreter::enabled()) {
auto interpreter = JS::Bytecode::Interpreter(m_script_record->realm());
evaluation_status = interpreter.run(*m_script_record, lexical_environment_override);
} else {
auto interpreter = JS::Interpreter::create_with_existing_realm(m_script_record->realm());
evaluation_status = interpreter->run(*m_script_record, lexical_environment_override);
}
// FIXME: If ScriptEvaluation does not complete because the user agent has aborted the running script, leave evaluationStatus as null.

View file

@ -35,7 +35,7 @@ OutOfProcessWebView::OutOfProcessWebView()
OutOfProcessWebView::~OutOfProcessWebView() = default;
void OutOfProcessWebView::create_client(EnableCallgrindProfiling)
void OutOfProcessWebView::create_client(EnableCallgrindProfiling, UseJavaScriptBytecode)
{
m_client_state = {};

View file

@ -78,7 +78,7 @@ private:
virtual void did_scroll() override;
// ^WebView::ViewImplementation
virtual void create_client(EnableCallgrindProfiling = EnableCallgrindProfiling::No) override;
virtual void create_client(EnableCallgrindProfiling = EnableCallgrindProfiling::No, UseJavaScriptBytecode = UseJavaScriptBytecode::No) override;
virtual void update_zoom() override;
virtual void notify_server_did_layout(Badge<WebContentClient>, Gfx::IntSize content_size) override;
virtual void notify_server_did_paint(Badge<WebContentClient>, i32 bitmap_id, Gfx::IntSize) override;

View file

@ -179,7 +179,7 @@ void ViewImplementation::handle_resize()
#if !defined(AK_OS_SERENITY)
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths, EnableCallgrindProfiling enable_callgrind_profiling, IsLayoutTestMode is_layout_test_mode)
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths, EnableCallgrindProfiling enable_callgrind_profiling, IsLayoutTestMode is_layout_test_mode, UseJavaScriptBytecode use_javascript_bytecode)
{
int socket_fds[2] {};
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
@ -221,6 +221,8 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ViewImplementation::launch_web
arguments.remove(0, callgrind_prefix_length);
if (is_layout_test_mode == IsLayoutTestMode::Yes)
arguments.append("--layout-test-mode"sv);
if (use_javascript_bytecode == UseJavaScriptBytecode::Yes)
arguments.append("--use-bytecode"sv);
result = Core::System::exec(arguments[0], arguments.span(), Core::System::SearchInPath::Yes);
if (!result.is_error())

View file

@ -30,6 +30,11 @@ enum class IsLayoutTestMode {
Yes
};
enum class UseJavaScriptBytecode {
No,
Yes
};
class ViewImplementation {
public:
virtual ~ViewImplementation() { }
@ -167,10 +172,10 @@ protected:
void request_repaint();
void handle_resize();
virtual void create_client(EnableCallgrindProfiling = EnableCallgrindProfiling::No) {};
virtual void create_client(EnableCallgrindProfiling = EnableCallgrindProfiling::No, UseJavaScriptBytecode = UseJavaScriptBytecode::No) { }
#if !defined(AK_OS_SERENITY)
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths, EnableCallgrindProfiling = EnableCallgrindProfiling::No, IsLayoutTestMode = IsLayoutTestMode::No);
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(ReadonlySpan<String> candidate_web_content_paths, EnableCallgrindProfiling = EnableCallgrindProfiling::No, IsLayoutTestMode = IsLayoutTestMode::No, UseJavaScriptBytecode = UseJavaScriptBytecode::No);
#endif
void handle_web_content_process_crash();