Add `ECMAScriptRegex`, LibRegex's C++ facade for ECMAScript regexes.
The facade owns compilation, execution, captures, named groups, and
error translation for the Rust backend, which lets callers stop
depending on the legacy parser and matcher types directly. Use it in the
remaining non-LibJS callers: URLPattern, HTML input pattern handling,
and the places in LibHTTP that only needed token validation.
Where a full regex engine was unnecessary, replace those call sites with
direct character checks. Also update focused LibURL, LibHTTP, and WPT
coverage for the migrated callers and corrected surrogate handling.
With apply_to() now self-contained (carrying its own replacement
DocumentState rather than reading from the live entry), the clone at
the traversal call site is no longer needed.
The clone previously served two purposes:
1. Input snapshot: freeze entry fields before deferred population.
Now solved by changing populate_session_history_entry_document() to
take explicit input parameters, snapshotted before the
deferred_invoke.
2. Output isolation: absorb apply_to() and post-population adjustments
without mutating the live entry during unload. Now solved by storing
the PopulateSessionHistoryEntryDocumentOutput on the continuation
state and deferring all mutations (including the origin-based
classic_history_api_state reset and navigable_target_name clear)
to after_potential_unload.
The post-population adjustments run unconditionally in
after_potential_unload, covering both the population path and the
non-population path (e.g. traversal to an already-populated error
entry).
Previously, populate_session_history_entry_document() took a
SessionHistoryEntry as both input and output — reading URL and
document_state fields while also mutating the entry across a chain of
async functions. This made it very hard to reason about data flow.
Refactor the internal helpers
(create_navigation_params_from_a_srcdoc_resource,
create_navigation_params_by_fetching, NavigationParamsFetchStateHolder,
perform_navigation_params_fetch) to take individual field values instead
of reading from the entry, and accumulate redirect mutations on the
state holder rather than writing them to the entry immediately.
Introduce PopulateSessionHistoryEntryDocumentOutput, a GC cell that
collects all mutations (document, redirect URL, classic history API
state, replacement document state, resource cleared flag, and
finalization data). The completion_steps callback now receives this
output object (or nullptr on cancellation), and callers apply it to the
entry via apply_to().
The replacement DocumentState for the redirect path is built eagerly at
redirect time from values captured on the state holder, making
apply_to() fully self-contained — it never reads from the target entry's
live document_state. This is important for the traversal path where the
entry may be mutated during unload (e.g. window.name writes
navigable_target_name through the active session history entry).
We pump the event loop just before these steps which can cause the
displayed document to be destroyed and lose its navigable. This was a
cause for crashes in the `encoding` WPT tests.
In `::spin_processing_tasks_with_source_until()`, we would first take a
set of tasks based on a filter, and then run them one by one. If there
was more than one task matched and put in that vector, they could
interfere with each other's runnability by making later tasks
permanently unrunnable.
The `::take_tasks_matching()` API is a footgun - remove it in favor of
an API that takes tasks one by one, performing the runnability check
just in time.
`close_top_level_traversable()` checks the `is_closing` flag to prevent
duplicate closes, but it is only set by callers of
`definitely_close_top_level_traversable()`. The flag is a bit in between
specs as things move from browsing contexts to navigables, but its
purpose is clear: without setting it, the check is ineffective and
`definitely_close_top_level_traversable()` runs multiple times for the
same traversable when the page has child navigables. This queues
duplicate session history traversal steps, where the second step
accesses the already-destroyed active document and segfaults.
The `HTMLFormControlsCollection` filter iterates all descendants of the
form's root, which may include non HTMLElement elements such as SVG
elements. The unchecked `as<FormAssociatedElement>` cast would crash on
these elements. Use `as_if` with a null check instead.
This fixes a regression introduced in 9af3e34875.
Other browsers appear to only do this for form submission, not for
all javascript URL navigations. Let's remove the handling in the
general javascript URL navigation handling so that our behaviour
diference to other browsers is limited specifically to form
elements, instead of the general case.
Unfortunately this does (expectedly) cause the test added in
3e0ea4f62 to start timing out, so that test is marked as skipped.
The scroll state collection loop in
record_display_list_and_scroll_state() called paintable() on hosted
documents, which asserts layout is up to date. This crashes when a
nested document has stale layout but a cached display list, e.g. a
render-blocked iframe whose DOM was modified by document.open().
Since scroll offsets are independent of layout freshness, use
unsafe_paintable() to skip the assertion.
Avoid expensive cross-hierarchy dynamic_cast from JS::Object to
UniversalGlobalScopeMixin on every microtask checkpoint.
Since UniversalGlobalScopeMixin is not in the JS::Object
inheritance chain, as<UniversalGlobalScopeMixin>(JS::Object&)
falls through to dynamic_cast, which is very costly. Profiling
showed this taking ~14% of total CPU time.
Add EnvironmentSettingsObject::universal_global_scope() backed
by a pointer cached eagerly during initialization.
On macOS, use Mach port messaging instead of Unix domain sockets for
all IPC transport. This makes the transport capable of carrying Mach
port rights as message attachments, which is a prerequisite for sending
IOSurface handles over the main IPC channel (currently sent via a
separate out-of-band path). It also avoids the need for the FD
acknowledgement protocol that TransportSocket requires, since Mach port
right transfers are atomic in the kernel.
Three connection establishment patterns:
- Spawned helper processes (WebContent, RequestServer, etc.) use the
existing MachPortServer: the child sends its task port with a reply
port, and the parent responds with a pre-created port pair.
- Socket-bootstrapped connections (WebDriver, BrowserProcess) exchange
Mach port names over the socket, then drop the socket.
- Pre-created pairs for IPC tests and in-message transport transfer.
Attachment on macOS now wraps a MachPort instead of a file descriptor,
converting between the two via fileport_makeport()/fileport_makefd().
The LibIPC socket transport tests are disabled on macOS since they are
socket-specific.
entry_realm() was using the topmost execution context, but the spec
defines the entry execution context as the most recently pushed *realm*
execution context — the one owned by the environment settings object.
In a synchronous cross-window call, JS function calls push additional
execution contexts above the entry realm, causing the wrong realm to
be returned. Fix this by walking the stack to find the context that
matches its environment settings object's realm execution context.
The beforeunload, promiserejection, beforetoggle and toggle events were
previously not tagged as trusted. This commit properly tags the event
so that we match the behaviour implemented by other browsers.
The form submit event was previously not tagged as trusted. This commit
properly tags the event so that we match the behaviour implemented by
other browsers and expected by WPT.
In TaskQueue::take_tasks_matching(), we were not discarding tasks for
destroyed documents as we now do in ::take_first_runnable() since commit
c8baa6e179.
This fixes some occurrences of missing browsing contexts / active
documents in TraversableNavigable::destroy_top_level_traversable().
Since we know whether we're buffering from the PlaybackManager state,
let's use that to update the ready state. This ensures that when we set
the ready state to HAVE_CURRENT_DATA, we actually have a frame.
Setting the ready state to HAVE_ENOUGH_DATA should probably still be
further conditioned on the buffer size in IncrementallyPopulatedStream,
but this is still an improvement for now.
This is a normal spec-mandated early return, not an error condition.
The already-started flag exists because prepare_script() is called from
multiple paths (attribute changes, child insertions, DOM connection)
and only the first call should proceed.
Both Chromium and Gecko delay the document's load event for CSS image
resource requests (background-image, mask-image, etc). We now start
fetching CSS image resources as soon as their stylesheet is associated
with a document, rather than deferring until layout. This is done by
collecting ImageStyleValues during stylesheet parsing and initiating
their fetches when the stylesheet is added to the document.
Fixes#3448
Encode transfer-data attachments as raw IPC attachments instead of first
rewrapping them as IPC::File values.
This is preparatory refactoring for the upcoming Mach-port transport
introduction on macOS, where attachments should remain transport-native
rather than being normalized through file descriptors.