The C++ pipeline has an optimization that uses the GetLengthWithThis
instruction instead of GetByIdWithThis when accessing the "length"
property. Add the same optimization to the Rust pipeline by
introducing an emit_get_by_id_with_this helper that checks for the
"length" property name and emits the optimized instruction.
Also update emit_get_by_value_with_this to use GetLengthWithThis
when the computed property is a constant "length" string.
Per spec, computed property key expressions should be evaluated
before calling ResolveSuperBase. Fix the Rust codegen for tagged
template literals with super member expressions to match the C++
pipeline's correct evaluation order.
Per spec, the property key expression should be evaluated before
calling ResolveSuperBase. Fix the Rust codegen to match the C++
pipeline's correct evaluation order.
Fix two bugs in the Rust bytecode codegen:
1. has_parameter_expressions incorrectly treated any destructuring
parameter as a "parameter expression", when it should only do so
for patterns that contain expressions (defaults or computed keys).
This caused an unnecessary CreateLexicalEnvironment for simple
destructuring like `function f({a, b}) {}`. The same bug existed
in both codegen.rs and lib.rs (SFD metadata computation).
2. emit_set_variable used is_local_lexically_declared(index) for
argument locals, but that function indexes into the local_variables
array using the argument's index, checking the wrong variable.
This caused spurious ThrowIfTDZ instructions when assigning to
function arguments that happened to share an index with an
uninitialized let/const variable.
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.