Commit graph

77858 commits

Author SHA1 Message Date
Andreas Kling
1859ecbb24 AK: Add lower_bound_index to binary search helpers
Add a helper for finding the first position in a sorted container where
needle can be inserted while preserving sort order. This gives callers a
lower-bound insertion point.

Cover empty inputs, duplicate values, custom comparators, and constexpr
use in TestBinarySearch.
2026-05-11 11:01:46 +02:00
Andreas Kling
2dab9f53d2 LibWasm: Use mmap to read shm fd on macOS in cranelift-compiler
macOS POSIX shared memory objects returned by shm_open() only support
mmap() and ftruncate(). Calls to read(), write(), pread() or pwrite()
all fail with ESPIPE. The cranelift-compiler child was using pread/
pwrite via File::read_exact_at/write_all_at, which works fine on
Linux where the parent uses memfd_create(), but fails on macOS where
the parent uses shm_open().

Add a macOS-specific path that mmaps the inherited shm fd with
MAP_SHARED, mirroring the Windows MapViewOfFile path. Writes through
the mapping are automatically visible to the parent, so the explicit
write-back step at the end is also skipped on macOS.
2026-05-11 09:57:33 +02:00
Andreas Kling
c9e135cdff LibWasm: Clear FD_CLOEXEC on shm fd before spawning Cranelift child
On macOS, the cranelift JIT compilation step works by creating an
anonymous shared memory segment via shm_open() in the parent process
and passing the fd as an argument to the spawned cranelift-compiler
child. POSIX requires shm_open() to set FD_CLOEXEC on the returned
fd, which caused the child to immediately fail with EBADF when it
tried to read from the inherited fd number.

Clear FD_CLOEXEC after shm_open() so the fd actually survives the
spawn. The Linux memfd_create() path is unaffected since we call it
with flags=0 (no MFD_CLOEXEC), and Windows passes an inheritable
HANDLE instead of an fd.
2026-05-11 09:57:33 +02:00
Timothy Flynn
fc401bd830 Meta: Treat Rust warnings as errors
We do the same in C++ files.
2026-05-10 20:50:20 +02:00
Timothy Flynn
0914e00c78 Meta: Extract common Rust compilation functionality to a helper
Lots of shared setup code between these functions. This will let us add
compilation flags in a single location in an upcoming commit.
2026-05-10 20:50:20 +02:00
Timothy Flynn
7ffbf5a8c0 LibJS: Remove unused Rust function
This became unused after 87493f056d, and
we now see a warning during the build.
2026-05-10 20:50:20 +02:00
Luke Wilde
b279fbc40d LibWeb/Painting: Skip positioned descendants earlier in traversal
paint_descendants already skipped positioned descendants at stack level
zero so they're only painted by paint_internal's pass, but the SVG-root
and grid-item branches returned before reaching the skip, making them
be painted twice.

Move the skip above them to make it apply to all deferred positioned
descendants uniformly.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9277
2026-05-10 20:31:00 +02:00
Tim Ledbetter
013ede7214 LibWeb: Use targeted invalidation when adopting a stylesheet
Previously, adding or removing a constructed `CSSStyleSheet` via
`document.adoptedStyleSheets` invalidated style for the entire document
or shadow root. We now route this through the same style invalidation
machinery that's used when we add or remove `<style>` elements,
resulting in fewer full invalidations.
2026-05-10 20:19:32 +02:00
Tim Ledbetter
ca43780bba LibWeb: Move stylesheet add/remove invalidation into shared helper
No behavior change.
2026-05-10 20:19:32 +02:00
Shannon Booth
4b9f6450bd LibWeb: Treat support IDLs like normal bindings inputs
Allow the WebIDL parser to accept files without a top-level interface,
and have the exposed-interface generator skip those modules.

With that in place, register support IDLs through
libweb_js_bindings() as well, including generated CSS IDLs from the
build directory, and remove the separate support-idl plumbing.

This is enabled now that the IDL generator rules have been simplified
so that every IDL file produces a corresponding header and cpp file.
2026-05-10 20:11:46 +02:00
Aliaksandr Kalenik
9d605f1237 LibGfx: Hide Skia types behind pImpl in DecodedImageFrameSkiaImageCache
Move the cache's Skia-dependent members (sk_sp<SkImage>, the
DecodedImageFrame-keyed HashMap, and the SkColorSpace-based key traits)
into a private Impl struct defined in the .cpp file. The header now only
needs forward declarations for SkImage and sk_sp, so including the cache
no longer drags in Skia headers into translation units that just want to
hold a pointer to the cache.
2026-05-10 19:49:29 +02:00
Aliaksandr Kalenik
688849947c LibWeb: Make display list inline data payload-relative
DisplayListDataSpan offsets used to point into the owning DisplayList's
command byte buffer. That made copied command sequences
position-dependent: whenever commands were captured, replayed, or
appended elsewhere, every inline data span inside command payloads had
to be decoded, adjusted, and written back.

Store those spans relative to the containing command payload instead.
CommandPayloadBuilder still computes padding from the final byte-stream
layout so inline data keeps the alignment expected by typed readers, but
the recorded offset is now local to the payload. This makes command
sequences self-contained byte ranges that can be copied without
rewriting their embedded spans.

Move inline data lookup to DisplayListPlayer by tracking the current
command payload while dispatching a command. The Skia player now
resolves glyph runs, gradient stops, path data, dash arrays, and nested
display list command bytes from that current payload instead of from the
active display list's global byte buffer.

With spans no longer absolute, remove the offset-adjustment helpers from
DisplayList.cpp and simplify append_command_sequence() and
copy_command_sequence_from() to copy command bytes directly. Add small
display-list object byte helpers and tighten the command/header
byte-stream contract to require trivially copyable payload structs.
2026-05-10 19:49:29 +02:00
Aliaksandr Kalenik
ec1cdea7db LibWeb: Inline paint styles in display list commands
Paint styles were stored as display list resources, which kept path
painting tied to in-process C++ objects. Move the gradient and pattern
payload into FillPath and StrokePath instead, with gradient stops
serialized as parallel color and position spans.

This is prep work for making display lists serializable across the IPC
boundary without needing to marshal SVG paint style objects separately.
2026-05-10 19:49:29 +02:00
Shannon Booth
21caf3fc7b Tests: Resync idlharness.js with WPT and fix worker IDL loading
Sync our local copy of `idlharness.js` with upstream WPT changes.

This also fixes worker IDL harness tests by replacing the local
`window.location` based URL handling in `fetch_spec()`. Worker globals
do not expose `window`, so worker IDL tests could fail during setup
before any interface checks ran.

The local `window.location` logic was originally needed for `file://`
execution, but this is no longer needed as our IDL tests are now
served over HTTP.
2026-05-10 17:36:57 +02:00
kunlinglio
87493f056d LibJS: Remove unused rust_compile_program function 2026-05-10 10:45:21 -04:00
Shehab Ahmed
f6a009e757 UI/Qt: Add a tooltip for the close tab button 2026-05-10 10:45:11 -04:00
Ali Mohammad Pur
9bda97a11b LibWasm: Avoid huge switches in all handlers' log functions
This explodes the debug info size, making the CI runner OOM when
building this file :)
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
a36f6abedb LibWasm+LibWeb: Properly track module lifetime with function refs 2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
a33e148339 LibWasm+Meta: Add Cranelift AOT compilation backend
Add an optional Cranelift-based AOT compiler for WebAssembly functions,
enabled via -DENABLE_CRANELIFT_JIT=ON.
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
96c3a5ed73 LibWasm: Add a regression test for cross-module memory access
This is not well-covered in neither the spectests nor our own tests.
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
5ab2eaed8c LibWasm: Fix some signedness bugs
- memory.grow page count
- memory.copy offsets and underflow in copy op
- table_{set,get} index exec
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
65a4af3ab0 LibWeb: Use UnownedExternalBuffer for WebAssembly.Memory backing store 2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
f181d24dc0 LibWasm: Prepare for VM and direct function calls
Introduce MemoryBuffer, a memory backing store that uses mmap to reserve
the full wasm32 address space (4 GiB + guard pages) upfront, growing
without a copy and falling back to a ByteBuffer when mmap fails.
Also let Frame know how to handle non-owned locals (to e.g. allow
allocating them on the native stack.)
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
0bb987e809 LibJS+LibWeb: Allow instantiating DataBlock with an external buffer
This requires the minimal API exposed by ByteBuffer, allowing external
users to implement them as needed instead of being forced to use a
ByteBuffer.
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
0a7bef349d LibCore: Add functions to reserve and commit non-backed address space 2026-05-10 16:41:42 +02:00
Daniel Gołębiewski
26b18f192e LibWeb: Basic support for scrollIntoView on boxes 2026-05-10 11:32:02 +02:00
Daniel Gołębiewski
ff6bfd495b Tests: Import scrollIntoView tests 2026-05-10 11:32:02 +02:00
Andreas Kling
949889f124 LibGC: Clear functions during finalization
A finalized GC::Function should no longer be callable. Clear the
underlying AK::Function during finalization so stale references fail as
empty callbacks instead of calling through finalized capture storage.
2026-05-10 10:58:11 +02:00
Andreas Kling
5cf90c0d0d LibWeb: Avoid stale delayed resource callbacks
Delayed preload and image animation callbacks can outlive the objects
they notify. Incremental sweeping makes this easier to hit because stale
callback state may be reclaimed before the delayed work runs.

Use a weak link element when firing preload load and error events, and
use a weak image style value from animated image timers instead of a raw
pointer.
2026-05-10 10:58:11 +02:00
Andreas Kling
37117b1cb4 LibJS: Check live blocks before pruning executable caches
Executable caches can retain weak pointers to shapes and prototypes
across collections. With incremental sweeping, a previous sweep may have
already freed the block behind one of those pointers by the time pruning
runs for weak containers.

Use the live HeapBlock registry before reading cached cells. This
matches the other weak containers updated for incremental sweeping.
2026-05-10 10:58:11 +02:00
Andreas Kling
4dfed815cc LibWeb: Make SharedResourceRequest finalization safe
SharedResourceRequest can be finalized while fetch work is pending.
Use weak fetch callbacks so late work no-ops once the request is gone.

Finalization now only drops local references and callbacks. It does not
stop fetch, since that allocates new algorithms during collection.
2026-05-10 10:58:11 +02:00
Andreas Kling
7930a6bd25 LibWeb: Cancel media controls when finalizing the host media element
Tear down the MediaControls (and its Core::Timer-driven hover handler)
during HTMLMediaElement finalization. Otherwise, between weak-clearing
and incremental sweep destroying the element, a queued hover timer
event can still fire and trip a VERIFY against an already-cleared
GC::Weak reference to a shadow tree node.
2026-05-10 10:58:11 +02:00
Andreas Kling
1f30af9f5a LibGC: Restructure GC report phases for incremental sweep
The phase breakdown was authored when sweep_dead_cells was the
single STW sweep phase, with sweep_callbacks and weak-container
work nested under it. After incremental sweep landed, that nesting
no longer matches reality: sweep_callbacks runs at STW every
collection, the weak-container prune is its own STW step, and
sweep_dead_cells only runs for CollectEverything.

Promote prune_weak_containers and sweep_callbacks to top-level
phases so they show up correctly in the report, and gate the
sweep_dead_cells subsection on a non-zero time so normal
collections no longer print a wall of zero rows.

The prune-weak-containers loop was previously untimed, leaving an
unaccounted gap in the per-GC totals. Wire it through the existing
ScopedPhaseTimer mechanism. The PhaseTimings field for it is
renamed from sweep_weak_containers_us to prune_weak_containers_us
to disambiguate from sweep_weak_blocks_us, which times a different
piece of work.
2026-05-10 10:58:11 +02:00
Andreas Kling
b95b3ecd6d LibWeb: Unregister image observers when finalizing layout nodes
Clear NodeWithStyle image observers during finalization so pending image
loads cannot call back into observers owned by unreachable layout nodes.
Incremental sweep leaves finalized cells allocated until their block is
swept, so waiting for the C++ destructor is too late.
2026-05-10 10:58:11 +02:00
Andreas Kling
d51d849943 LibWeb: Keep active platform timers alive during GC
Treat active Platform::Timer objects as event-loop roots so their GC
callbacks stay marked while the underlying Core::Timer can still fire.
Finalize unreachable timers by stopping the Core timer and dropping the
callback, preventing incremental sweep from leaving a timer with a raw
pointer to a swept GC::Function.
2026-05-10 10:58:11 +02:00
Andreas Kling
a4945a651f LibGC: Report incremental sweep batches
Record incremental sweep batch timing while LIBGC_LOG_LEVEL enables GC
reporting. Print the batch summary once the incremental sweep fully
finishes, so normal collection reports include the delayed sweep work
instead of leaving the sweep section empty for incremental collections.
2026-05-10 10:58:11 +02:00
Andreas Kling
d4aff987ab LibGC: Use live HeapBlock registry during GC instead of rebuilding it
Now that Heap maintains a persistent set of live heap blocks, use it
in the marking and conservative root scanning phases instead of
rebuilding a local copy on every collection cycle.
2026-05-10 10:58:11 +02:00
Andreas Kling
b9ec043b5a LibGC: Add live HeapBlock registry to fix weak container UAF
Maintain a HashTable<HeapBlock*> of live heap blocks in the Heap,
updated on block creation and destruction.

Weak containers (WeakMap, WeakSet, WeakRef, FinalizationRegistry)
now check block liveness before accessing cell memory in their
remove_dead_cells() methods. This prevents use-after-free when
blocks have been freed during incremental sweeping.
2026-05-10 10:58:11 +02:00
Andreas Kling
245b7d74a7 LibGC: Prune weak containers in stop-the-world phase of GC
Move weak container cleanup (remove_dead_cells) out of both
sweep_dead_cells() and start_incremental_sweep() to the place
where it is actually safe to inspect cell state: collect_garbage().

Previously, remove_dead_cells could access cells that had already
been swept and poisoned by ASAN, causing use-after-poison crashes
when a new GC triggered while an incremental sweep was in progress.
2026-05-10 10:58:11 +02:00
Andreas Kling
fb4095ae50 LibGC: Implement incremental sweeping for reduced GC pause times
Instead of sweeping all heap blocks in one go after marking, sweep
incrementally, one block at a time, interleaved with program execution.
This significantly reduces worst-case GC pause times by spreading
sweep work across multiple smaller time slices.

Sweep is driven by two complementary mechanisms:

1. Timer-based sweeping: A 16ms repeating timer drives background
   sweep work, processing blocks for up to 5ms per timer fire.

2. Allocation-directed sweeping: Each allocator sweeps its own
   pending blocks before creating new ones, ensuring forward
   progress even without timer events.

Each allocator maintains its own list of blocks pending sweep,
and allocators with pending work are tracked in a separate list
for efficient timer-driven sweeping.

Key implementation details:

- Newly allocated cells during sweep are marked immediately to
  prevent premature collection.

- Mark bits are cleared incrementally as each block is swept,
  rather than in a separate pass over the entire heap.

- Finalization and weak reference processing remain stop-the-world
  since they must complete atomically before any sweeping occurs.
2026-05-10 10:58:11 +02:00
Andreas Kling
e23ec1f841 LibWeb: Convert Document's cursor blink timer to GC::Timer
Use GC::Timer instead of Core::Timer for the cursor blink timer so
that capturing [this] in the callback properly protects the Document
from garbage collection.
2026-05-10 10:58:11 +02:00
Andreas Kling
4ba14759dc LibGC: Move Web::WebDriver::HeapTimer to GC::Timer
Move HeapTimer out of LibWeb and into LibGC as GC::Timer, inheriting
from GC::Cell instead of JS::Cell. Add a finalize() override that
stops the timer, ensuring it is cleaned up during GC finalization.
2026-05-10 10:58:11 +02:00
Andreas Kling
3b9c55bd5c LibGC: Gate per-GC report on LIBGC_LOG_LEVEL environment variable
Reading LIBGC_LOG_LEVEL once at startup picks the verbosity for the
collection reports:

  0/default: silent.
  1:         per-GC report with totals and detailed per-phase timings.
  2+:        everything in level 1, plus the full block allocator dump.

The existing collect_garbage(..., print_report=true) entry point still
works and behaves like a per-call floor of level 1, so the DevTools
"collect-garbage" inspector request keeps emitting a report regardless
of the env var. The allocator dump is now off by default at level 1
since most reports do not need it.

Right-aligned the percentage column in the breakdown so the numbers
line up cleanly.
2026-05-10 10:58:11 +02:00
Andreas Kling
895def2bd5 LibGC: Add detailed per-phase timing breakdown to GC report
The per-collection report now includes microsecond timings (with
percentage of total) for each phase and major subphase:

  gather_roots
    must-survive scan / embedder roots / explicit roots
    conservative roots
      register scan / stack scan / conservative-vector / cell lookup
  mark_live_cells
    initial visit / BFS marking / clear uprooted
  finalize_unmarked_cells
  sweep_weak_blocks
  sweep_dead_cells
    block iteration / weak containers / sweep callbacks
    block reclassify / update threshold

Timings are recorded via a small RAII helper into a file-scope struct,
keeping all the plumbing inside Heap.cpp so the public Heap.h surface
stays untouched. Sweep stats now travel back to collect_garbage() the
same way, which lets the report move out of sweep_dead_cells() into a
single print_gc_report() helper run after every phase has completed.
2026-05-10 10:58:11 +02:00
Andreas Kling
93c2175fc7 LibGC: Report GC times in microseconds with human-readable byte counts
Switch the per-GC report to a precise timer and microsecond output, and
format all byte counts via human_readable_size so they read naturally
(e.g. "12.3 MiB" instead of "12923847 bytes").
2026-05-10 10:58:11 +02:00
Andreas Kling
c78a50c4c3 LibGC: Use mmap for HeapBlock chunks
Use a direct anonymous mapping for POSIX BlockAllocator chunks and trim
any temporary padding needed to make the live 2 MiB chunk HeapBlock-
aligned.

The GC only needs each 16 KiB HeapBlock slot aligned so from_cell() can
recover the block base by masking low bits. Request that alignment from
mach_vm_map() as well, rather than aligning whole chunks to 2 MiB.
2026-05-10 10:58:11 +02:00
Shannon Booth
c3812d54e1 LibWeb: Push an execution context for WebDriver screenshots
WPT reftests capture screenshots through
WebDriver::draw_bounding_box_from_the_framebuffer(), which creates a
scratch 2D canvas outside normal script execution.

This regressed when CanvasRenderingContext2DSettings started using the
generated bindings conversion path. That path now looks at the current
realm even for this codepath, whereas the previous handwritten
conversion did not, so WebDriver screenshot capture could hit a missing
running execution context and crash.

Push a TemporaryExecutionContext while creating the scratch canvas so
the generated conversion has the realm it expects and WPT reftests no
longer crash.
2026-05-10 10:21:19 +02:00
Kevin Bortis
ba26f8eee7 AK: Reset UTF-16 StringBuilder ascii flag on clear()
StringBuilder::clear() did not reset m_utf16_builder_is_ascii. When a
UTF-16 mode builder processed a non-ASCII character then was cleared
and reused, subsequent ASCII content was stored as char16_t. The
to_utf16_string() path then corrupted the first code unit to null via
placement-new overlap in Utf16StringData::from_string_builder().

This caused the HTML parser's shared m_character_insertion_builder to
produce corrupted script text nodes when a non-ASCII character (e.g.
&times;) appeared in an earlier element, breaking inline script
execution with "Unexpected token Invalid" at line 1 column 1.
2026-05-09 09:49:02 -04:00
Andreas Kling
0dd6b32a1b LibWeb/Bindings: Share more interface constructors
Split the generator decision for shared prototype and constructor
objects. Interfaces with custom prototype behavior can still use the
shared InterfaceConstructor when the constructor object itself has no
custom GC cell state.

Teach Intrinsics how to register a shared constructor for an existing
custom prototype object, and keep LegacyFactoryFunction aliases wired up
when the primary interface objects are shared.
2026-05-09 15:33:00 +02:00
kunlinglio
8a259c1cde LibGC: Remove size-based allocator support 2026-05-09 15:07:24 +02:00