Commit Graph

4 Commits

Author SHA1 Message Date
Andreas Kling
029708b2cf Tests: Rebaseline bytecode tests after handler/finalizer collapse
The exception handler dump format changed from showing both handler
and finalizer offsets to showing only a single handler offset.
2026-02-09 16:35:39 +01:00
Andreas Kling
7f89158d20 LibJS: Replace implicit environment stack with explicit registers
Replace the saved_lexical_environments stack in ExecutionContextRareData
with explicit register-based environment tracking. Environments are now
stored in registers and restored via SetLexicalEnvironment, making the
environment flow visible in bytecode.

Key changes:
- Add GetLexicalEnvironment and SetLexicalEnvironment opcodes
- CreateLexicalEnvironment takes explicit parent and dst operands
- EnterObjectEnvironment stores new environment in a dst register
- NewClass takes an explicit class_environment operand
- Remove LeaveLexicalEnvironment opcode (instead: SetLexicalEnvironment)
- Remove saved_lexical_environments from ExecutionContextRareData
- Use a reserved register for the saved lexical environment to avoid
  dominance issues with lazily-emitted GetLexicalEnvironment
2026-02-09 16:35:39 +01:00
Andreas Kling
a439dc8490 LibJS: Use explicit completion records for try/finally dispatch
Each finally scope gets two registers (completion_type and
completion_value) that form an explicit completion record. Every path
into the finally body sets these before jumping, and a dispatch chain
after the finally body routes to the correct continuation.

This replaces the old implicit protocol that relied on the exception
register, a saved_return_value register, and a scheduled_jump field
on ExecutionContext, allowing us to remove:

- 5 opcodes (ContinuePendingUnwind, ScheduleJump, LeaveFinally,
  RestoreScheduledJump, PrepareYield)
- 1 reserved register (saved_return_value)
- 2 ExecutionContext fields (scheduled_jump, previously_scheduled_jumps)
2026-02-09 08:51:12 +01:00
Andreas Kling
871d93355b LibJS: Stop propagating is_inside_scope_with_eval across functions
Previously, when a nested function contained eval(), the parser would
mark all identifiers in parent functions as "inside scope with eval".
This prevented those identifiers from being marked as global, forcing
them to use GetBinding instead of GetGlobal.

However, eval() can only inject variables into its containing function's
scope, not into parent function scopes. So a parent function's reference
to a global like `Number` should still be able to use GetGlobal even if
a nested function contains eval().

This change adds a new flag `m_eval_in_current_function` that propagates
through block scopes within the same function but stops at function
boundaries. This flag is used for marking identifiers, while the
existing `m_screwed_by_eval_in_scope_chain` continues to propagate
across functions for local variable deoptimization (since eval can
access closure variables).

Before: `new Number(42)` in outer() with eval in inner() -> GetBinding
After:  `new Number(42)` in outer() with eval in inner() -> GetGlobal
2026-01-27 10:58:39 +01:00