Commit graph

162 commits

Author SHA1 Message Date
Andreas Kling
6ecfcd3e68 LibWeb+LibJS: Cache decoded JS bytecode sidecars
Add a ref-counted decoded bytecode cache backing so bytecode cache
materialization can create fresh script or module records from a shared
decoded sidecar without passing around one-shot raw blob ownership.

Keep that backing in ExecutableBacking for records materialized from
bytecode cache sidecars, so the immutable decoded data stays alive for
as long as the installed record needs it.

Cover the shared backing path with a bytecode-cache test that
materializes and runs two scripts from one decoded backing.
2026-06-06 09:15:09 +02:00
Andreas Kling
72720bc229 LibWeb: Preserve JS bytecode in memory cache
Store JavaScript bytecode side data in the WebContent HTTP memory
cache and replay it when serving cached responses. Also update an
already-complete memory-cache entry when asynchronous bytecode cache
generation finishes, so the first source-only response does not keep
shadowing the disk-cache sidecar during same-process navigations.

Keep the HTTP memory-cache backfill keyed with the request headers that
populated the memory-cache entry, so Vary responses still receive their
generated bytecode sidecar.

Add LibHTTP coverage for round-tripping bytecode side data through a
memory-cache entry, attaching it after the response body has already
been cached, and matching Vary headers during updates. Add LibWeb
coverage for preserving the memory-cache request headers when cloning
responses.
2026-06-06 09:15:09 +02:00
Andreas Kling
ec421d7fa4 LibWeb+LibJS: Validate bytecode cache blobs off-thread
Warm cache hits used to validate bytecode cache blobs on the main
thread. Route script and module sidecars through a worker step that
decodes and validates the cache blob, then returns the validated blob
for main-thread materialization.

Keep the source bytes mmap-backed and avoid decoding the full source on
cache hits. The main thread still computes the UTF-16 source length so
validation can reject stale blobs before materialization.

Remove the decoded source length getter now that sidecar validation uses
the explicit validation API instead.
2026-06-05 21:55:55 +02:00
Andreas Kling
bf81464904 LibWeb+LibJS: Remove rust_pipeline_available
The Rust pipeline is always available now, so the getter only wrapped
code that always ran. Remove it and make the JavaScript fetch paths use
the off-thread Rust pipeline directly.

This also removes the unreachable synchronous fallback branches from the
classic script and module fetch paths.
2026-06-05 21:55:55 +02:00
Andreas Kling
789d7cba48 LibWeb: Use direct references to main event loops
Post off-thread font, script, and DNS completion work back to direct
Core::EventLoop references. These callbacks target the process main
loop, which is intentionally kept alive for the lifetime of the
process.
2026-06-05 09:18:39 +02:00
Andreas Kling
afb0fa2413 LibJS: Hash encoded source identity in bytecode cache
Switch bytecode cache source identity from decoded UTF-16 source text to
the original encoded response bytes plus the effective source encoding.
Store the decoded source length in the cache blob header so warm loads
can build lazy SourceCode objects without decoding the source before
checking the sidecar.

This removes the main-thread decoded_source_text_info pass from valid
warm-cache script and module loads. The source is only decoded on cache
miss, or when a rejected sidecar falls back to source compilation.
2026-06-03 14:11:23 +02:00
Andreas Kling
55aad9ee38 LibWeb: Install fresh JS bytecode cache blobs locally
After generating a bytecode cache blob, map it as ImmutableBytes and ask
the owning JS record to install it. This lets a cold-cache load move to
mapped cache backing without waiting for a later page load.
2026-05-22 10:54:44 +02:00
Shannon Booth
387cd6e2e2 LibGC: Default-construct RootVector from the global heap
Similar to GC::Root<T>, make GC::RootVector<T> constructible without
explicitly passing a Heap.

This is implemented by having RootVectorBase use GC::Heap::the() for
heap-free construction.
2026-05-20 20:37:55 +02:00
Andreas Kling
3d3e6f4226 LibJS+LibWeb: Keep cached script source text lazy
Avoid decoding warm-cache script responses into full UTF-16 SourceCode
buffers when a bytecode cache sidecar is available. SourceCode now keeps
the original immutable source bytes and source encoding, then decodes
only when full source text or a Function.toString() range is requested.

Compute the bytecode cache source hash while streaming decoded code
points from the response bytes, so cache validation does not force an
intermediate UTF-8 string. Function and class source text metadata now
stores SourceCode ranges instead of views into a materialized buffer.
2026-05-18 09:18:35 +02:00
Andreas Kling
318fb4f2d0 LibWeb: Preserve immutable consumed body bytes
Keep consumed response body bytes in Core::ImmutableBytes instead of
requiring a ByteBuffer. This lets responses that already arrived as
file-backed immutable data keep that representation through body
consumption, while streamed responses can still adopt their
accumulated ByteBuffer without another copy.

Update the body consumers that only inspect bytes to read from
immutable byte views. Font loading still copies at its existing
ownership boundary, where the off-thread preparation path takes a
ByteBuffer.
2026-05-18 01:21:34 +02:00
Shannon Booth
951e2e1986 LibWeb: Avoid unhandled rejection when reporting module script errors
Report module script evaluation failures without replacing the returned
evaluation promise or rethrowing from the reporting reaction. This
avoids surfacing the same failure as both a script error and an
unhandled promise rejection.
2026-05-16 09:52:35 +02:00
Andreas Kling
881c1484fe LibWeb: Avoid widening ASCII source for bytecode cache hashes
Hash ASCII-backed script source as equivalent UTF-16 data in fixed-size
chunks instead of first forcing SourceCode to allocate a full widened
copy. Keep the existing bytecode cache key stable by preserving the same
byte sequence that the previous utf16_data() path hashed.
2026-05-16 09:10:00 +02:00
Andreas Kling
a646f9d0bf LibJS: Borrow mapped bytecode cache executable bytes
Keep executable bytecode payloads decoded from owner-backed bytecode
cache blobs as ranges into the original blob instead of copying them
into Rust Vec allocations. The mapped blob owner is held by decoded
executable records, including lazy nested function executables, so the
borrowed bytecode remains alive until materialization copies it into the
final C++ Executable.

Use the owner-backed decoder for HTTP bytecode cache hits and keep the
plain byte decoder for tests and in-memory callers. Add coverage for
materializing bytecode cache data from an ImmutableBytes mapped file.
2026-05-16 08:13:35 +02:00
Luke Wilde
de35994fc2 LibJS+LibWeb: Use the unified Visitor for Variant-holding members 2026-05-15 08:51:17 +02:00
Andreas Kling
e3841a7392 LibJS: Compact Shape property table to a sorted flat array
Replace the lazy per-shape OrderedHashMap cache for non-dictionary
shapes with a GC-allocated descriptor array. Store descriptors in hash
order for lookup while keeping an enum index so callers can still walk
properties in insertion order.

Keep dictionary shapes on the mutable OrderedHashMap path, and migrate
callers that enumerated Shape::property_table() to the new insertion
order iterator. Cap descriptor arrays to their compact u16 index range
and keep larger dictionary shapes on the mutable table path across
prototype transitions and prototype clones.

Add coverage for setting the prototype of a dictionary object with more
than 65536 named properties.
2026-05-14 19:59:40 +02:00
Andreas Kling
e18d4f7418 LibWeb: Decouple ModuleScript from WebAssemblyModule
Remove the concrete WebAssemblyModule include from ModuleScript.h and
include it only in the .cpp files that need the complete type. This
keeps the module script header from pulling WebAssembly implementation
details into unrelated LibWeb translation units.
2026-05-14 12:19:38 +02:00
Andreas Kling
c32b5a3f73 LibWeb+RequestServer: Send cached bytecode with responses
Attach cached JavaScript bytecode sidecars to HTTP response headers so
WebContent can materialize classic and module scripts directly from a
decoded cache blob on cache hits.

Carry the disk cache vary key with the sidecar and reuse it when storing
fresh bytecode, avoiding mismatches against the augmented network
request headers used to create the cache entry.

Keep CORS-filtered module responses intact for status, MIME, and script
creation checks. Read bytecode sidecar data only from the internal
response, and treat decode or materialization failure as a cache miss
that falls back to normal source compilation.
2026-05-06 08:20:06 +02:00
Andreas Kling
557191decb LibWeb+RequestServer: Cache bytecode after script handoff
Schedule JavaScript bytecode cache generation after downloaded classic
scripts and modules have been handed back to the main thread.

The cache job reparses and fully compiles on the thread pool,
serializes the bytecode blob, and stores it as HTTP cache sidecar data.
RequestServer finalizes the disk cache entry before notifying
WebContent, so the script fetcher can attach the sidecar immediately.
2026-05-06 08:20:06 +02:00
Andreas Kling
b265694f0d LibJS: Match bytecode cache blobs to their source
Store a SHA-256 fingerprint of the decoded source text in each bytecode
cache blob, and require callers to provide the expected fingerprint when
validating or decoding a blob.

This rejects sidecars for stale HTTP cache entries whose URL and request
headers still match but whose source body has been replaced. Bytecode
cache tests cover the mismatched-source rejection path.
2026-05-06 08:20:06 +02:00
Andreas Kling
54fbf3ff30 LibWeb: Compile remaining script functions in background
After off-thread script or module compilation hands top-level bytecode
back to the main thread, clone the remaining lazy function payloads and
compile them on the thread pool.

Install completed bytecode only when the function is still lazy. If the
main thread compiled it first, discard the stale result and schedule
another pass over that executable so nested lazy payloads still move to
bytecode.
2026-05-06 08:20:06 +02:00
Aliaksandr Kalenik
737691c43a LibWeb: Keep worker startup reachable until script load completes
Fixes flakiness in worker tests that create a Worker or SharedWorker
with a missing script URL and only attach an error handler to it.
Once the test callback returns, nothing keeps the worker rooted from
JavaScript. If GC ran before the WebWorker process reported the
script fetch failure, the Worker/WorkerAgentParent cycle could be
collected and the error event never delivered, leaving the test hung
until timeout.

Hold startup-pending WorkerAgentParents from the outside
EnvironmentSettingsObject and release that edge once the script load
succeeds, fails, or the worker closes. The worker now survives long
enough to deliver its first script-load result.
2026-04-27 18:02:49 +02:00
Andreas Kling
4a7dc45b3f LibWeb+LibJS: Compile fetched top-level JS off-thread
Split Rust program compilation so code generation and assembly finish
before the main thread materializes GC-backed executable objects. The
new CompiledProgram handle owns the parsed program, generator state, and
bytecode until C++ consumes it on the main thread.

Wire WebContent script fetching through that handle for classic scripts
and modules. Syntax-error paths still return ParsedProgram, so existing
error reporting stays in place. Successful fetches now do top-level
codegen on the thread pool before deferred_invoke hands control back to
the main thread.

Executable creation, SharedFunctionInstanceData materialization, module
metadata extraction, and declaration data extraction still run on the
main thread where VM and GC access is valid.
2026-04-26 21:51:52 +02:00
Andreas Kling
88d4d1b1a6 LibWeb: Use VM helpers for execution context access
Inline JS-to-JS frames no longer live in the raw execution context
vector, so LibWeb callers that need to inspect or pop contexts now go
through VM helpers instead of peeking into that storage directly.

This keeps the execution context bookkeeping encapsulated while
preserving existing microtask and realm-entry checks.
2026-04-13 18:29:43 +02:00
Andreas Kling
2ca7dfa649 LibJS: Move bytecode interpreter state to VM
The bytecode interpreter only needed the running execution context,
but still threaded a separate Interpreter object through both the C++
and asm entry points. Move that state and the bytecode execution
helpers onto VM instead, and teach the asm generator and slow paths to
use VM directly.
2026-04-13 18:29:43 +02:00
Timothy Flynn
2f3199adbf LibURL+LibWeb: Add a helper to check if a URL is a WebUI URL
Let's not have to know off-hand that we need to update Environments.cpp
when adding a new WebUI. It's more obvious just below where we define
the URLs.
2026-04-09 10:08:06 -04:00
Shannon Booth
57130908b3 LibJS+LibWeb: Make DOMException hold an [[ErrorData]] slot
Split JS::ErrorData out of JS::Error so that it can be used both
by JS::Error and WebIDL::DOMException. This adds support for
Error.isError to DOMException, also letting us report DOMException
stack information to the console.
2026-04-08 20:33:53 +02:00
Shannon Booth
bb0f244667 LibWeb: Remove ShadowRealm HTML integration 2026-04-05 13:57:58 +02:00
Shannon Booth
91e7218c22 LibWeb/HTML: Enforce CORS-mode fetch when fetching Worker script
At some point, the FIXME mentioned has been fixed.
2026-04-05 09:52:25 +02:00
Glenn Skrzypczak
e5dab9e1c7 LibWeb: Support WASM modules
This adds support for importing WASM modules in JavaScript and vice
versa.
2026-04-03 21:21:09 +02:00
Glenn Skrzypczak
7392d2a2f4 LibWeb: Support JSON modules
This adds support for importing JSON objects from JSON files in
javascript.
2026-04-03 21:21:09 +02:00
Glenn Skrzypczak
f1d3244b22 LibWeb: Support CSS modules
This adds support for importing CSS stylesheets from CSS files in
javascript.
2026-04-03 21:21:09 +02:00
Glenn Skrzypczak
8053c2a0f1 LibWeb: Update fetch single module script steps
This updates the steps for fetching single module scripts and related
functions.
2026-04-03 21:21:09 +02:00
InvalidUsernameException
7002c47ce1 LibJS+LibWeb: Pass constants into execution context constructor
The additional data being passed will be used in an upcoming commit.
Allows splitting the churn of modified function signatures from the
logically meaningful code change.

No behavior change.
2026-03-29 13:44:06 +02:00
Sam Atkins
ed6a5f25a0 LibWeb: Implement scoped custom element registries 2026-03-27 19:49:55 +00:00
Andreas Kling
b5babda288 LibWeb: Cache UniversalGlobalScopeMixin pointer on ESO
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.
2026-03-24 08:28:47 +01:00
Shannon Booth
9d7b18f517 LibWeb: Fix entry_realm() to correctly find the realm execution context
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.
2026-03-23 09:00:39 +01:00
Jelle Raaijmakers
c8baa6e179 LibWeb: Remove tasks for destroyed documents instead of running them
Previously, destroyed-document tasks were forced to be runnable to
prevent them from leaking in the task queue. Instead, discard them
during task selection so their callbacks never run with stale state.

This used to cause issues with a couple of `spin_until()`s in the past,
but since we've removed some of them that had to do with the document
lifecycle, let's see if we can stick closer to the spec now.
2026-03-19 15:24:46 -05:00
Andrew Kaster
92e4c20ad5 LibJS: Generate FFI header using cbindgen instead of hand-rolling
Replace the BytecodeFactory header with cbindgen.

This will help ensure that types and enums and constants are kept in
sync between the C++ and Rust code. It's also a step in exporting more
Rust enums directly rather than relying on magic constants for
switch statements.

The FFI functions are now all placed in the JS::FFI namespace, which
is the cause for all the churn in the scripting parts of LibJS and
LibWeb.
2026-03-17 20:49:50 -05:00
Tim Ledbetter
36f74ba96c Revert "LibJS: Shrink ExecutionContext by replacing ScriptOrModule …"
… with Cell*.

This reverts commit d3495c62a7.
2026-03-11 23:13:18 +00:00
Andreas Kling
d3495c62a7 LibJS: Shrink ExecutionContext by replacing ScriptOrModule with Cell*
Replace the 16-byte Variant<Empty, GC::Ref<Script>, GC::Ref<Module>>
with a simple 8-byte GC::Ptr<Cell> that points to either a Script or
Module (or is null for Empty).

A helper function script_or_module_from_cell() converts back to the
full ScriptOrModule variant when needed (e.g. in
VM::get_active_script_or_module).
2026-03-11 13:33:47 +01:00
Andreas Kling
f02b67a700 LibJS: Remove context_owner from ExecutionContext
This field was only used by LibWeb to prevent GC collection of the
EnvironmentSettingsObject while its execution context is on the stack.

This is unnecessary because the ESO is already reachable through the
realm's host_defined pointer: EC -> realm -> host_defined ->
PrincipalHostDefined -> environment_settings_object.

Shrinks ExecutionContext from 152 to 144 bytes.
2026-03-11 13:33:47 +01:00
Andreas Kling
69bab13718 LibWeb: Drain microtasks after background parse completion
When parse_off_thread() completes, the result callback runs inside a
deferred_invoke, which executes outside the HTML event loop's task
model. This meant that any microtasks queued by the callback (e.g.
promise reactions from react_to_promise during module linking) were
never drained, since HTML::EventLoop::process() only performs
microtask checkpoints after executing an HTML task.

Fix this by performing an explicit microtask checkpoint after the
parse result callback. This ensures that promise reactions queued
during module linking are drained immediately.

This fixes module worker scripts timing out because their loading
promise chains would stall indefinitely.
2026-03-09 09:38:29 +01:00
Andreas Kling
4c1e2aeb54 LibJS+LibWeb: Parse modules off the main thread
Use the parse_off_thread() helper to submit
parse_program(ProgramType::Module) to the ThreadPool for parsing
on a worker thread. Bounce back to the main thread to compile and
deliver the result via deferred_invoke.

Falls back to synchronous parsing when the Rust pipeline is
unavailable (LIBJS_CPP=1 or LIBJS_COMPARE_PIPELINES=1).
2026-03-06 13:06:05 +01:00
Andreas Kling
3f4d3d6108 LibJS+LibWeb: Add C++ compile_parsed_module wrapper
Add compile_parsed_module() to RustIntegration, which takes a
RustParsedProgram and a SourceCode (from parse_program with
ProgramType::Module) and compiles it on the main thread with GC
interaction.

Rewrite compile_module() to use the new split functions internally.

Add SourceTextModule::parse_from_pre_parsed() and
JavaScriptModuleScript::create_from_pre_parsed() to allow creating
module scripts from a pre-parsed RustParsedProgram.

This prepares the infrastructure for off-thread module parsing.
2026-03-06 13:06:05 +01:00
Andreas Kling
d8921646f5 LibJS+LibWeb: Parse classic scripts off the main thread
Create a SourceCode on the main thread (performing UTF-8 to UTF-16
conversion), then submit parse_program() to the ThreadPool for
Rust parsing on a worker thread. This unblocks the WebContent event
loop during external script loading.

Add Script::create_from_parsed() and
ClassicScript::create_from_pre_parsed() factory methods that take a
pre-parsed RustParsedProgram and a SourceCode, performing only the
GC-allocating compile step on the main thread.

Falls back to synchronous parsing when the Rust pipeline is
unavailable (LIBJS_CPP=1 or LIBJS_COMPARE_PIPELINES=1).
2026-03-06 13:06:05 +01:00
Andreas Kling
4e0e16e510 LibJS+LibWeb: Use InterpreterStack for all execution context allocation
Replace alloca-based execution context allocation with InterpreterStack
bump allocation across all call sites: bytecode call instructions,
AbstractOperations call/construct, script evaluation, module evaluation,
and LibWeb module script evaluation.

Also replace the native stack space check with an InterpreterStack
exhaustion check, and remove the now-unused alloca macros from
ExecutionContext.h.
2026-03-04 18:53:12 +01:00
Shannon Booth
8d099b9cec LibWeb: Add non const global object getter to EnvironmentSettingsObject
And sneak in a as_if tidyup too.
2026-02-26 07:22:50 +01:00
Shannon Booth
9e7aa878bc LibWeb: Properly determine if running in SecureContext for Workers
Fixes the included imported test. Note that this required a minor
edit of the WPT import to work with our test harness setup to
try and create a non secure context setup as both file:// and
localhost are considered secure contexts.
2026-02-26 07:22:50 +01:00
Shannon Booth
025ddd385b LibWeb/HTML: Track secure context as part of Serialized{Document,Worker}
This is somewhat awkward as the spec refers to 'is secure context'
with respect to these objects 'relevant settings object'. A natural
way of implementing this could be storing a pointer to the relevant
settings object like the JS representations of these objects do
(and then changing is_secure_context to accept this representation
too), but for now it seems much simpler to just store a boolean for
this purpose and sidestep both problems above.
2026-02-26 07:22:50 +01:00
Shannon Booth
665654a1c4 LibWeb: Begin serializing global object as part of serialized ESO
Instead of passing through window's associated document's URL as
an extra argument to starting up a worker. This will allow for
improving the representation of 'outside settings' when setting
up a Worker.
2026-02-23 11:42:20 +01:00