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:
Andreas Kling
2026-02-23 11:50:46 +01:00
committed by Andreas Kling
parent 8bf1d749a1
commit 6cdfbd01a6
Notes: github-actions[bot] 2026-02-24 08:41:00 +00:00
43 changed files with 28402 additions and 148 deletions

View File

@@ -9,6 +9,7 @@
#include <AK/Debug.h>
#include <AK/Function.h>
#include <LibGC/DeferGC.h>
#include <LibJS/AST.h>
#include <LibJS/Bytecode/BasicBlock.h>
#include <LibJS/Bytecode/Generator.h>
@@ -29,6 +30,7 @@
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/RustIntegration.h>
namespace JS {
@@ -217,7 +219,13 @@ void ECMAScriptFunctionObject::get_stack_frame_size(size_t& registers_and_locals
{
auto& executable = shared_data().m_executable;
if (!executable) {
if (is_module_wrapper()) {
auto rust_executable = RustIntegration::compile_function(vm(), *m_shared_data, false);
if (rust_executable) {
executable = rust_executable;
executable->name = m_shared_data->m_name;
if (Bytecode::g_dump_bytecode)
executable->dump();
} else if (is_module_wrapper()) {
executable = Bytecode::compile(vm(), ecmascript_code(), kind(), name());
} else {
executable = Bytecode::compile(vm(), shared_data(), Bytecode::BuiltinAbstractOperationsEnabled::No);