Commit graph

12 commits

Author SHA1 Message Date
Andreas Kling
6cdfbd01a6 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.
2026-02-24 09:39:42 +01:00
Andreas Kling
e308e73120 LibJS: Move SharedFunctionInstanceData creation out of FunctionNode
Add static factory methods create_for_function_node() on
SharedFunctionInstanceData and update all callers to use them instead
of FunctionNode::ensure_shared_data().

This removes the GC::Root<SharedFunctionInstanceData> cache from
FunctionNode, eliminating the coupling between the RefCounted AST
and GC-managed runtime objects. The cache was effectively dead code:
hoisted declarations use m_functions_to_initialize directly, and
function expressions always create fresh instances during codegen.
2026-02-11 23:57:41 +01:00
Andreas Kling
6d0b54dd0b LibJS: Drop AST after first compilation on Script
After compiling the bytecode executable on first run, null out the
AST (m_parse_node) and clear AnnexB candidates since they are no
longer needed. This frees the memory held by the entire AST for the
script's lifetime.

The parse_node() accessor now returns a nullable pointer. Callers
(js.cpp for AST dumping, Interpreter for first compilation) access
the AST before it is dropped.
2026-02-11 23:57:41 +01:00
Andreas Kling
f87429a9e7 LibJS: Rewrite global declaration instantiation using metadata
Add Script::global_declaration_instantiation() that performs the GDI
algorithm using pre-computed name lists and shared function data
instead of walking the AST.

Runtime checks (has_lexical_declaration, can_declare_global_function,
etc.) remain since they depend on global environment state. AnnexB
iterates pre-collected candidates and calls
set_should_do_additional_annexB_steps() on stored refs.

The Interpreter::run(Script&) now calls the Script method instead of
the Program method.
2026-02-11 23:57:41 +01:00
Andreas Kling
1c68bc7533 LibJS: Pre-compute global declaration instantiation data on Script
Extract all data that Program::global_declaration_instantiation()
needs from the AST into value-type metadata stored on the Script
object, computed once during construction. This includes lexical
names, var names, functions to initialize, var scoped names, AnnexB
candidates, and lexical bindings.

This prepares for rewriting GDI to use the pre-computed metadata
instead of walking the AST.
2026-02-11 23:57:41 +01:00
Andreas Kling
d72ade6fa2 LibJS: Cache compiled executable on Script
Instead of recompiling from AST on every run, cache the compiled
bytecode executable after first compilation and reuse it on
subsequent runs.
2026-02-11 23:57:41 +01:00
Andreas Kling
0dacc94edd LibJS: Have JS::Lexer take a JS::SourceCode as input
This moves the responsibility of setting up a SourceCode object to the
users of JS::Lexer.

This means Lexer and Parser are free to use string views into the
SourceCode internally while working.

It also means Lexer no longer has to think about anything other than
UTF-16 (or ASCII) inputs. So the unit test for parsing various invalid
UTF-8 sequences is deleted here.
2025-11-09 12:14:03 +01:00
Andreas Kling
fdb85a330e LibJS: Stop tracking whether execution context is strict mode or not
This was only used for basic testing, and forced us to plumb this flag
flag in a bunch of places.
2025-10-29 21:20:10 +01:00
Andreas Kling
892c7d980e LibJS: Let JS::Script remember whether its code is strict mode
We don't want to rely on having the AST node just to answer the question
"is this script strict mode?"
2025-10-27 21:14:33 +01:00
Shannon Booth
f87041bf3a LibGC+Everywhere: Factor out a LibGC from LibJS
Resulting in a massive rename across almost everywhere! Alongside the
namespace change, we now have the following names:

 * JS::NonnullGCPtr -> GC::Ref
 * JS::GCPtr -> GC::Ptr
 * JS::HeapFunction -> GC::Function
 * JS::CellImpl -> GC::Cell
 * JS::Handle -> GC::Root
2024-11-15 14:49:20 +01:00
Shannon Booth
1e54003cb1 LibJS+LibWeb: Rename Heap::allocate_without_realm to Heap::allocate
Now that the heap has no knowledge about a JavaScript realm and is
purely for managing the memory of the heap, it does not make sense
to name this function to say that it is a non-realm variant.
2024-11-13 16:51:44 -05:00
Timothy Flynn
93712b24bf Everywhere: Hoist the Libraries folder to the top-level 2024-11-10 12:50:45 +01:00
Renamed from Userland/Libraries/LibJS/Script.cpp (Browse further)