Commit graph

14 commits

Author SHA1 Message Date
Andreas Kling
93d19b35b6 LibJS/Rust: Handle private member update expressions
Add PrivateIdentifier handling in generate_update_expression so that
postfix/prefix increment/decrement on private members (e.g. this.#c++)
correctly emits GetPrivateById, PostfixIncrement, and PutPrivateById.
Previously this fell through to an empty fallback that returned an
uninitialized register.
2026-03-01 21:20:54 +01:00
Andreas Kling
fa78df7ab7 LibJS/Rust: Call perform_needed_unwinds before Throw instructions
Add missing perform_needed_unwinds() calls before Throw instructions
in four places:
- Await continuation throw path
- Yield* throw_value_block
- Yield* iterator missing throw method
- Invalid left-hand side in assignment helper

This matches the C++ pipeline which calls perform_needed_unwinds<Throw>
before every Throw to restore lexical environments when throwing out of
scopes like with statements.
2026-03-01 21:20:54 +01:00
Andreas Kling
4f503ef243 LibJS/Rust: Use correct capacity for CreateVariableEnvironment
Pass the fully computed var_environment_bindings_count from the SFD
metadata to the codegen, instead of using the raw
non_local_var_count_for_parameter_expressions. The full count includes
additional bindings from Annex B function hoisting and strict-mode
lexical declarations that share the var environment.
2026-03-01 21:20:54 +01:00
Andreas Kling
e88932f75d LibJS/Rust: Always allocate fresh register for postfix update result
Match the C++ pipeline behavior where PostfixIncrement/PostfixDecrement
always writes to a freshly allocated register. The Rust pipeline was
using the caller's preferred_dst, producing one fewer Mov instruction
but causing bytecode mismatches.
2026-03-01 21:20:54 +01:00
Andreas Kling
1c40257c7f LibJS/Rust: Restore unwind handler when trampolining through finally
When break/continue trampolines through nested finally blocks, we need
to restore the unwind handler to the level that was active before each
finally context was pushed. Without this, trampoline blocks created for
inner finally dispatch incorrectly inherited the innermost exception
handler, causing exception handler range mismatches with C++.

Store the current_unwind_handler in each FinallyContext at push time,
and restore it in emit_trampoline_through_finally when popping through.
2026-03-01 21:20:54 +01:00
Andreas Kling
8f38e526e7 LibJS/Rust: Fix several bytecode mismatches with the C++ pipeline
- Don't emit dead code after Throw for UsingDeclaration in for-of
  LHS assignment. Guard loop body generation with
  is_current_block_terminated() in both for-in and for-of.

- Add LeaveLexicalEnvironment boundary tracking to for-loop
  per-iteration environment management, so that perform_needed_unwinds
  correctly emits SetLexicalEnvironment before Throw instructions
  inside the loop body.
2026-03-01 21:20:54 +01:00
Andreas Kling
d0b9905de1 LibJS/Rust: Use GetLengthWithThis for super.length property access
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.
2026-03-01 21:20:54 +01:00
Andreas Kling
c365806041 LibJS/Rust: Fix evaluation order for super in tagged templates
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.
2026-03-01 21:20:54 +01:00
Andreas Kling
56603319b4 LibJS/Rust: Fix evaluation order in delete super[key]
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.
2026-03-01 21:20:54 +01:00
Andreas Kling
543bd7059a LibJS/Rust: Don't emit dead code after Throw for invalid LHS
Match the C++ pipeline behavior by not creating a dead basic block
after emitting a Throw instruction in emit_invalid_lhs_error.
2026-03-01 21:20:54 +01:00
Andreas Kling
18c40a1328 LibJS/Rust: Fix has_parameter_expressions and TDZ checks for arguments
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.
2026-03-01 21:20:54 +01:00
xnacly
bbb6121df4 LibJs/Rust: Migrate to edition 2024 2026-02-24 16:35:51 +01:00
xnacly
e897b77e83 LibJS/Rust: Cargo fmt on all source files 2026-02-24 16:35:51 +01:00
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