Commit graph

75686 commits

Author SHA1 Message Date
Zaggy1024
07d1b222c7 Meta: Simplify GC heap explorer's class list rendering
We don't need to pass the filter and sort to the render function from
all these locations, the callers always use values from the same
inputs. Instead, just use the values directly from cached references
the input elements.

This fixes the class filter not being applied correctly after a refresh
autofills the old value back into it.
2026-03-01 21:50:51 +01:00
Zaggy1024
a3922aa570 LibGC+Meta: Include inline frames in the GC explorer's stack trace 2026-03-01 21:50:51 +01:00
Zaggy1024
03284abee9 LibGC+Meta: Display a frame size in the GC graph explorer's stack trace
This can help us track down overly-large frames that might be
contributing stale roots.
2026-03-01 21:50:51 +01:00
Zaggy1024
1a3e8fdf60 LibGC+Meta: Look up and display stack frames for StackPointer roots
This adds a stack trace to the JSON output from GC graph dumps which
is shown in a default-collapsed tray on the right side of the graph
explorer. When a stack pointer root is selected, the stack frame it
originated from is highlighted in the tray.
2026-03-01 21:50:51 +01:00
Zaggy1024
677a22c63e Meta: Make the GC explorer's source locations' word wrapping prettier
Remove `word-break: break-all` and instead insert word breaks before
each transition from non-word to word characters. As an example, with
breaks represented by vertical bars:

Foo<|Bar>::|baz()

Thus, when wrapping a line, it'll break on whitespace, or on characters
indicating that there is more to follow.
2026-03-01 21:50:51 +01:00
Andreas Kling
fdcb2cdd94 LibJS/Rust: Create for-of loop blocks before evaluating iterable
Match the C++ pipeline's block creation order by creating end_block
and update_block before evaluating the for-of RHS expression. This
ensures loop structure blocks get lower block numbers than blocks
created during RHS evaluation (e.g. from conditional expressions),
producing the same block layout as C++.
2026-03-01 21:20:54 +01:00
Andreas Kling
d88374e119 Tests/LibJS: Add bytecode test for for-of with conditional in RHS
This adds a test case where the for-of iterable is a sequence
expression containing a conditional expression. The C++ pipeline
creates loop blocks before evaluating the iterable, giving them lower
block numbers, while the Rust pipeline evaluates the iterable first.
2026-03-01 21:20:54 +01:00
Andreas Kling
496ca319e4 LibJS/Rust: Skip TDZ check for self-move in emit_set_variable
Move the self-move detection before the TDZ check in
emit_set_variable, matching C++ which returns early for self-moves
without emitting anything. A self-move only happens in compound and
logical assignments where the LHS is a local variable, and the LHS
was already read with a TDZ check, making the write-back's TDZ check
redundant.
2026-03-01 21:20:54 +01:00
Andreas Kling
aadfe0f02a Tests/LibJS: Add test for compound assignment after destructuring
This adds a test case for compound assignment to a variable that was
initialized via a let destructuring pattern. The Rust pipeline emits a
redundant ThrowIfTDZ after the compound assignment because the variable
is not tracked as initialized after destructuring.
2026-03-01 21:20:54 +01:00
Andreas Kling
c379587adf LibJS/Rust: Don't pass preferred_dst for destructuring assignment RHS
When the LHS of an assignment is a destructuring pattern, don't pass
preferred_dst when generating the RHS expression. This matches the C++
pipeline which always allocates a fresh register for the RHS value.

The difference was visible when a destructuring assignment appeared
inside a logical AND expression: the C++ pipeline would allocate the
RHS into a fresh register and then copy it to the AND result register,
while the Rust pipeline would evaluate the RHS directly into the AND
result register, omitting the copy.
2026-03-01 21:20:54 +01:00
Andreas Kling
86191ce229 Tests/LibJS: Add bytecode test for destructuring assignment in &&
This adds a test case for array destructuring assignment inside a
logical AND expression, e.g. `t && ([a, b] = t(e))`. The C++ pipeline
allocates a separate register for the RHS and copies it to the result
register after destructuring, while the Rust pipeline evaluates the
RHS directly into the preferred destination, omitting the copy.
2026-03-01 21:20:54 +01:00
Andreas Kling
7602e030e7 LibJS/Rust: Push LeaveLexicalEnvironment boundary in for-of loops
When a for-of loop creates a per-iteration lexical environment for
let/const declarations, push a LeaveLexicalEnvironment boundary so
that continue/break/return properly restores the lexical environment.
The for-in codegen already did this but for-of was missing it.
2026-03-01 21:20:54 +01:00
Andreas Kling
f0c34d54a1 Tests/LibJS: Add bytecode test for for-of continue with block scope
Test that continue inside a for-of loop body properly restores the
lexical environment when the for-of creates a per-iteration scope
for the loop variable.
2026-03-01 21:20:54 +01:00
Andreas Kling
75e628ce9b LibJS/Rust: Push LeaveLexicalEnvironment boundary in switch statements
When a switch statement creates a lexical environment for block-scoped
declarations (let/const), push a LeaveLexicalEnvironment boundary so
that perform_needed_unwinds correctly emits SetLexicalEnvironment
before Return/Throw instructions inside the switch body.
2026-03-01 21:20:54 +01:00
Andreas Kling
fa9c1a6885 Tests/LibJS: Add bytecode test for return from switch with block scope
Test that returning from inside a switch statement that has a lexical
environment (for const/let declarations) properly emits
SetLexicalEnvironment to restore the parent environment before each
Return instruction.
2026-03-01 21:20:54 +01:00
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
6432754251 Tests/LibJS: Add bytecode test for postfix increment on private member 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
ffa380f15b Tests/LibJS: Add bytecode test for async await in try-catch with scope
Test that the await continuation's throw path properly unwinds the
lexical environment when inside a with statement within a try-catch.
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
dc464ba270 Tests/LibJS: Add bytecode test for var environment capacity
Add a test that exercises CreateVariableEnvironment capacity when a
function has parameter expressions and non-local var bindings.
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
17c8a80afc Tests/LibJS: Add bytecode test for postfix update in logical AND
Add a test that exercises postfix increment/decrement as the RHS of a
logical AND expression, verifying the register allocation matches C++.
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
95fec309cd Tests/LibJS: Add bytecode test for nested try-finally continue
Add a test that exercises break/continue trampolines through nested
try-finally blocks, ensuring exception handler ranges are correct.
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
176a618fce LibJS: Don't emit dead code after Throw for invalid LHS expressions
When the left-hand side of an assignment, update, or for-in loop is
invalid (e.g. `foo() = "bar"`), the bytecode generator emits a Throw
instruction. Previously, it would also create a dead basic block after
the Throw, resulting in unreachable instructions in the output.

Fix this by returning early from the relevant codegen paths after
emitting the Throw, and by guarding for-in/for-of body generation
with an is_current_block_terminated() check.
2026-03-01 21:20:54 +01:00
Andreas Kling
8d51371e22 LibJS: Skip AST dump for ClassFieldInitializerStatement
ClassFieldInitializerStatement is a synthetic AST node that does not
support dump_to_string(). Guard the pipeline comparison code against
this case to avoid a VERIFY failure when comparing class field
initializer functions.
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
Andreas Kling
766567a9d5 LibJS: Compare Rust and C++ bytecode for lazily compiled functions
LIBJS_COMPARE_PIPELINES previously only compared top-level
script/eval/module bytecodes. Function bodies are compiled lazily
via compile_function(), and that path had no comparison at all.

Fix this by pairing each Rust-compiled SharedFunctionInstanceData
with its C++ counterpart during top-level compilation. When a
function is later lazily compiled, compile_function() runs both
pipelines and compares the bytecodes (crashing on mismatch, same
as the top-level comparisons). The pairing is done recursively so
nested functions are also covered.
2026-03-01 21:20:54 +01:00
Shannon Booth
db5f16f042 LibHTTP: Parse token-list headers according to their ABNF
The previous implementation did not fully align with each
headers ABNF, so would not reject some headers as we should
have been doing.

Fixes 6 WPT subtests for

https://wpt.live/cors/access-control-expose-headers-parsing.window.html
2026-03-01 18:16:16 +00:00
Tim Ledbetter
65b08e7d9f LibWeb: Use correct point type in to_top_level_position()
This occurred because 90a211b changed the return type of
`transform_rect_to_viewport()` but 7fc945d didn't take this into
account.
2026-03-01 09:54:59 +00:00
Tim Ledbetter
7fc945d524 LibWeb: Account for scroll and transforms in to_top_level_position()
This change means the right click context menu is displayed in the right
place when clicking inside an iframe on a scrolled page, including when
the iframe has CSS transforms applied to it.
2026-03-01 08:31:41 +00:00
Zaggy1024
e77167f2f4 UI/AppKit: Make CPU painting work again
We were incorrectly calling presentMetalFrame while force-cpu-painting
was enabled, so updateLayer never had any chance to be called.

However, in addition to that, it turned out that there's a subclass of
CALayer that is used by NSView by default which cannot be created in a
makeBackingLayer override, so updateLayer was never going to be called
anyway. In order to update the layer at the requisite time, a new
LadybirdWebViewContentLayer had to be added to simply call the delegate
on our view.

Setting the contentsRect on the layer was also incorrect, and caused
the contents to shift and stretch until WebContent's backing stores
shrank to fit the new view size.
2026-03-01 08:32:36 +01:00
Shannon Booth
e188de89f9 LibWeb/PermissionsPolicy: Allow autoplay of file:// media from file://
As file:// URLs are considered opaque origins by default, we need
to special case them in the allowlist as any opaque origin will
not be matched in the allow list.
2026-03-01 01:04:10 +01:00
Shannon Booth
336d95ebdc Tests/LibWeb: Run test-web tests with opaque origin file:// URLs
I intended to do this in: 1be69479a

However at that time I was switching back and forward between the
two settings, and must have accidentally left in that option.

The change in test expectation here is an exception being thrown
from a different point.
2026-03-01 01:04:10 +01:00
Shannon Booth
8c8b8338b7 Tests/LibWeb: Load tests relying on tuple file origins from HTTP server
These tests do not work when run from an opaque origin file:// URL.
2026-03-01 01:04:10 +01:00
Shannon Booth
9e198ff523 Tests/LibWeb: Run less Origin testcases from web server
Only the two remaining tests are making assumptions about the
origin of the initial document's global being a tuple origin.
2026-03-01 01:04:10 +01:00
Shannon Booth
8d04c7b738 Tests/LibWeb: Remove bogus file:// URL testcase
This was also removed in upstream WPT as it was testing something
which is implementation defined.
2026-03-01 01:04:10 +01:00
Shannon Booth
ec0231c788 LibWeb/SecureContexts: Make use of Origin::is_opaque_file_origin 2026-03-01 01:04:10 +01:00
Shannon Booth
8124a5028c LibURL: Move some Origin helpers out of line
There have been a few times I have wanted to add a debug log in
one of these functions, but currently that causes a massive rebuild.
Let's just move these out of line.
2026-03-01 01:04:10 +01:00
Shannon Booth
b6e5b960fd LibURL: Add a Origin::is_opaque_file_origin helper
We will likely have some of these dotted around the place AD-HOC,
so let's make this a bit more readable when used.
2026-03-01 01:04:10 +01:00
Undefine
23e2408a0e Meta: Disable --no-undefined on all BSD systems
It turns out the problem present on FreeBSD is also present on OpenBSD.
2026-02-28 10:26:26 -07:00
Undefine
ed26c06836 Meta: Do not use CMAKE_LINKER_TYPE on all BSD systems
The bug doesn't only affect FreeBSD but the others too.
2026-02-28 10:26:26 -07:00
Zaggy1024
d77a0a2daf test-web: Convert ANSI control codes to HTML styling in dumped output
Instead of stripping all the control codes, let's use them to make our
test dumps more readable. :^)
2026-02-28 11:19:19 -06:00
Shannon Booth
46cd47753f LibWeb: Make more use of Value::{as,as_if,is} in LibWeb 2026-02-28 10:24:37 -05:00