mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-18 18:00:31 +00:00
LibJS: Add alternative source-to-bytecode pipeline in Rust
Implement a complete Rust reimplementation of the LibJS frontend: lexer, parser, AST, scope collector, and bytecode code generator. The Rust pipeline is built via Corrosion (CMake-Cargo bridge) and linked into LibJS as a static library. It is gated behind a build flag (ENABLE_RUST, on by default except on Windows) and two runtime environment variables: - LIBJS_CPP: Use the C++ pipeline instead of Rust - LIBJS_COMPARE_PIPELINES=1: Run both pipelines in lockstep, aborting on any difference in AST or bytecode generated. The C++ side communicates with Rust through a C FFI layer (RustIntegration.cpp/h) that passes source text to Rust and receives a populated Executable back via a BytecodeFactory interface.
This commit is contained in:
parent
8bf1d749a1
commit
6cdfbd01a6
Notes:
github-actions[bot]
2026-02-24 08:41:00 +00:00
Author: https://github.com/awesomekling
Commit: 6cdfbd01a6
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8104
43 changed files with 28402 additions and 148 deletions
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/AsyncFunctionDriverWrapper.h>
|
||||
|
|
@ -15,6 +16,9 @@
|
|||
#include <LibJS/Runtime/ModuleEnvironment.h>
|
||||
#include <LibJS/Runtime/PromiseCapability.h>
|
||||
#include <LibJS/Runtime/SharedFunctionInstanceData.h>
|
||||
#include <LibJS/RustIntegration.h>
|
||||
#include <LibJS/Script.h>
|
||||
#include <LibJS/SourceCode.h>
|
||||
#include <LibJS/SourceTextModule.h>
|
||||
|
||||
namespace JS {
|
||||
|
|
@ -164,6 +168,29 @@ SourceTextModule::SourceTextModule(Realm& realm, StringView filename, Script::Ho
|
|||
}
|
||||
}
|
||||
|
||||
SourceTextModule::SourceTextModule(Realm& realm, StringView filename, Script::HostDefined* host_defined, bool has_top_level_await,
|
||||
Vector<ModuleRequest> requested_modules, Vector<ImportEntry> import_entries,
|
||||
Vector<ExportEntry> local_export_entries, Vector<ExportEntry> indirect_export_entries,
|
||||
Vector<ExportEntry> star_export_entries, Optional<Utf16FlyString> default_export_binding_name,
|
||||
Vector<Utf16FlyString> var_declared_names, Vector<LexicalBinding> lexical_bindings,
|
||||
Vector<FunctionToInitialize> functions_to_initialize,
|
||||
GC::Ptr<Bytecode::Executable> executable,
|
||||
GC::Ptr<SharedFunctionInstanceData> tla_shared_data)
|
||||
: CyclicModule(realm, filename, has_top_level_await, move(requested_modules), host_defined)
|
||||
, m_execution_context(ExecutionContext::create(0, 0, 0))
|
||||
, m_import_entries(move(import_entries))
|
||||
, m_local_export_entries(move(local_export_entries))
|
||||
, m_indirect_export_entries(move(indirect_export_entries))
|
||||
, m_star_export_entries(move(star_export_entries))
|
||||
, m_var_declared_names(move(var_declared_names))
|
||||
, m_lexical_bindings(move(lexical_bindings))
|
||||
, m_functions_to_initialize(move(functions_to_initialize))
|
||||
, m_default_export_binding_name(move(default_export_binding_name))
|
||||
, m_executable(executable)
|
||||
, m_tla_shared_data(tla_shared_data)
|
||||
{
|
||||
}
|
||||
|
||||
SourceTextModule::~SourceTextModule() = default;
|
||||
|
||||
void SourceTextModule::visit_edges(Cell::Visitor& visitor)
|
||||
|
|
@ -180,6 +207,25 @@ void SourceTextModule::visit_edges(Cell::Visitor& visitor)
|
|||
// 16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
|
||||
Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename, Script::HostDefined* host_defined)
|
||||
{
|
||||
auto rust_result = RustIntegration::compile_module(source_text, realm, filename);
|
||||
if (rust_result.has_value()) {
|
||||
if (rust_result->is_error())
|
||||
return rust_result->release_error();
|
||||
auto& module_result = rust_result->value();
|
||||
Vector<FunctionToInitialize> functions_to_initialize;
|
||||
functions_to_initialize.ensure_capacity(module_result.functions_to_initialize.size());
|
||||
for (auto& f : module_result.functions_to_initialize)
|
||||
functions_to_initialize.append({ *f.shared_data, move(f.name) });
|
||||
return realm.heap().allocate<SourceTextModule>(
|
||||
realm, filename, host_defined, module_result.has_top_level_await,
|
||||
move(module_result.requested_modules), move(module_result.import_entries),
|
||||
move(module_result.local_export_entries), move(module_result.indirect_export_entries),
|
||||
move(module_result.star_export_entries), move(module_result.default_export_binding_name),
|
||||
move(module_result.var_declared_names), move(module_result.lexical_bindings),
|
||||
move(functions_to_initialize),
|
||||
module_result.executable.ptr(), module_result.tla_shared_data.ptr());
|
||||
}
|
||||
|
||||
// 1. Let body be ParseText(sourceText, Module).
|
||||
auto parser = Parser(Lexer(SourceCode::create(String::from_utf8(filename).release_value_but_fixme_should_propagate_errors(), Utf16String::from_utf8(source_text))), Program::Type::Module);
|
||||
auto body = parser.parse_program();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue