Commit graph

85 commits

Author SHA1 Message Date
Andreas Kling
9af5508aef LibJS: Split inline frames from execution context stack
Keep JS-to-JS inline calls out of m_execution_context_stack and walk
the active stack from the running execution context instead. Base
pushes now record the previous running context so duplicate
TemporaryExecutionContext pushes and host re-entry still restore
correctly.

This keeps the fast JS-to-JS path off the vector without losing GC
root collection, stack traces, or helpers that need to inspect the
active execution context chain.
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
Shannon Booth
f27bc38aa7 Everywhere: Remove ShadowRealm support
The proposal has not seemed to progress for a while, and there is
a open issue about module imports which breaks HTML integration.
While we could probably make an AD-HOC change to fix that issue,
it is deep enough in the JS engine that I am not particularly
keen on making that change.

Until other browsers begin to make positive signals about shipping
ShadowRealms, let's remove our implementation for now.

There is still some cleanup that can be done with regard to the
HTML integration, but there are a few more items that need to be
untangled there.
2026-04-05 13:57:58 +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
Andreas Kling
3e1145ef07 LibJS: Synchronous await fast path when microtask queue is empty
When an async function is resumed from a microtask and hits another
await with a non-thenable value (primitive or already-settled native
promise), and the microtask queue is empty, we can resolve the await
synchronously without suspending. No other microtask can observe the
difference in execution order, making this optimization safe.

This avoids the overhead of creating a GC::Function for the microtask
job, enqueuing/dequeuing from the microtask queue, and the execution
context push/pop that comes with it.

A new VM host hook, host_promise_job_queue_is_empty, is added so both
the standalone js binary and LibWeb can provide the appropriate check
for their respective job queue implementations.
2026-03-16 19:15:03 -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
75e7bc1e2a LibJS: Move source range cache from ExecutionContext to Executable
CachedSourceRange was a GC-allocated cell stored on the
ExecutionContext, only needed because ExecutionContext must be
trivially destructible.

Move the source range cache to a HashMap<u32, SourceRange> on the
Executable (keyed by program counter), where it belongs. This
eliminates the GC::Cell subclass entirely and removes the
cached_source_range field from ExecutionContext.

StackTraceElement and TracebackFrame now store Optional<SourceRange>
directly instead of GC::Ptr<CachedSourceRange>.

Shrinks ExecutionContext from 144 to 136 bytes.
2026-03-11 13:33:47 +01:00
Andreas Kling
fe48e27a05 LibJS: Replace GC::Weak with GC::RawPtr in inline cache entries
Property lookup cache entries previously used GC::Weak<T> for shape,
prototype, and prototype_chain_validity pointers. Each GC::Weak
requires a ref-counted WeakImpl allocation and an extra indirection
on every access.

Replace these with GC::RawPtr<T> and make Executable a WeakContainer
so the GC can clear stale pointers during sweep via remove_dead_cells.

For static PropertyLookupCache instances (used throughout the runtime
for well-known property lookups), introduce StaticPropertyLookupCache
which registers itself in a global list that also gets swept.

Now that inline cache entries use GC::RawPtr instead of GC::Weak,
we can compare shape/prototype pointers directly without going
through the WeakImpl indirection. This removes one dependent load
from each IC check in GetById, PutById, GetLength, GetGlobal, and
SetGlobal handlers.
2026-03-08 10:27:13 +01:00
Andreas Kling
f05e326d78 LibJS: Remove vestigial AST.h includes from runtime files 2026-02-11 23:57:41 +01:00
Andreas Kling
4fa4ecf31b LibJS: Inline ExecutionContextRareData fields into ExecutionContext
After removing the unwind context stack, ExecutionContextRareData only
held two GC::Ptr fields — both trivially destructible. The indirection
cost more than it saved: a GC cell allocation per EC, an extra pointer
chase on every source range lookup, and unnecessary complexity.

Replace the rare data cell with two inline fields on ExecutionContext:
cached_source_range and context_owner.
2026-02-09 16:35:39 +01:00
Andreas Kling
8b19992f8c LibGC: Make MarkingVisitor better at bulk-visiting Vector<JS::Value>
When passing a Vector<JS::Value> to the MarkingVisitor, we were
iterating over the vector and visiting one value at a time. This led
to a very inefficient way of building up the GC's work queue.

By adding a new visit_impl() virtual to Cell::Visitor, we can now
grow the work queue capacity once, and then add without incrementally
growing the storage.
2026-01-07 20:51:17 +01:00
CountBleck
d44b239621 LibJS: Crudely implement growable SharedArrayBuffers
We treat any mention of [[ArrayBufferByteLengthData]] and related
atomic operations as FIXMEs to be fixed at a later date. We also add the
HostGrowSharedArrayBuffer abstract operation, which will be overridden
by LibWeb to grow shared WebAssembly memories.
2026-01-04 07:47:55 +01:00
Andreas Kling
72886c4999 LibJS: Don't iterate finalization registry cleanup jobs in silly way
Pop jobs from the end of the vector instead of from the front. This
avoids shifting all the memory around. Also use GC::Ref instead of Ptr.
2025-12-25 20:21:37 +01:00
Andreas Kling
ba6e7083bb LibJS: Make VM::the() be ALWAYS_INLINE
This was already getting optimized properly in distribution builds
but release builds (on macOS at least) failed to inline it unless we
do this.
2025-12-11 14:34:45 -06:00
Andreas Kling
87ecd3f558 LibJS: Enforce "only one JS::VM" but allow destroying+recreating VMs
test262-runner needs to make a clean slate VM for each test, so let's
relax the enforcement here a little bit. As long as there is only one
JS::VM instantiated, we're good.
2025-12-10 09:41:21 -05:00
Andreas Kling
8289b24a7e LibJS: Introduce VM::the() and use it instead of caching VM pointer
In our process architecture, there's only ever one JS::VM per process.
This allows us to have a VM::the() singleton getter that optimizes
down to a single global access everywhere.

Seeing 1-2% speed-up on all JS benchmarks from this.
2025-12-09 11:58:39 -06:00
Andreas Kling
2d76e21cfd LibJS: Don't use GC::Root unnecessarily in Error stack traces
This was causing a fair bit of root registration churn on pages that
throw lots of errors.

Since there's no need for these pointers to float around freely, we can
just visit them during the mark phase as usual.
2025-11-30 11:53:56 +01:00
Tim Ledbetter
ab00a4dc1f LibJS: Skip null entries in numeric string cache when gathering roots
This caused a crash when dumping the GC graph.
2025-11-04 10:34:43 +01:00
Andreas Kling
5b9469786e LibJS: Move ExecutionContext::cached_source_range to rare data 2025-11-01 08:40:32 +01:00
Andreas Kling
9ded35f98f LibJS: Make CachedSourceRange GC-allocated
This gets rid of a RefPtr in ExecutionContext, bringing us one step
closer to destructor-less ExecutionContext.
2025-11-01 08:40:32 +01:00
Andreas Kling
4c7ffc0552 LibJS: Remove ExecutionContext::function_name field
Instead of having ExecutionContext track function names separately,
we give FunctionObject a virtual function that returns an appropriate
name string for use in call stacks.
2025-10-29 21:20:10 +01:00
Andreas Kling
fb05063dde LibJS: Let bytecode instructions know whether they are in strict mode
This commits puts the strict mode flag in the header of every bytecode
instruction. This allows us to check for strict mode without looking at
the currently running execution context.
2025-10-29 21:20:10 +01:00
Andreas Kling
b691f4c7af LibJS: Add number-to-string cache for numbers < 1000
We are often forced to convert numbers to strings inside LibJS, e.g when
iterating over the property names of an array, but it's also just a very
common operation in general.

This patch adds a 1000-entry string cache for the numbers 0-999 since
those appear to be by far the most common ones we convert.
2025-10-05 21:44:06 +02:00
Andreas Kling
24934ba479 LibJS: Make single-character ASCII string cache strings be Utf16String
Just another little step towards all strings being Utf16String.
2025-10-05 16:39:14 +02:00
Timothy Flynn
70db474cf0 LibJS+LibWeb: Port interned bytecode strings to UTF-16
This was almost a no-op, except we intern JS exception messages. So the
bulk of this patch is porting exception messages to UTF-16.
2025-08-14 10:27:08 +02:00
Timothy Flynn
b955c9b2a9 LibJS: Port the Identifier AST (and related) nodes to UTF-16
This eliminates quite a lot of UTF-8 / UTF-16 churn.
2025-08-13 09:56:13 -04:00
Timothy Flynn
0efa98a57a LibJS+LibWeb+WebContent: Port JS::PropertyKey to UTF-16
This has quite a lot of fall out. But the majority of it is just type or
UDL substitution, where the changes just fall through to other function
calls.

By changing property key storage to UTF-16, the main affected areas are:
* NativeFunction names must now be UTF-16
* Bytecode identifiers must now be UTF-16
* Module/binding names must now be UTF-16
2025-08-05 07:07:15 -04:00
Luke Wilde
3d43462ccd LibJS: Implement the Dynamic Code Brand Checks stage 3 proposal
This is an active proposal at stage 3 of the TC39 proposal process.
See: https://tc39.es/proposal-dynamic-code-brand-checks/
See: https://github.com/tc39/proposal-dynamic-code-brand-checks

This proposal essentially adds support for the TrustedScript type from
the Trusted Types specification to eval and Function. This in turn
pipes support for the type into the CSP hook to check if the CSP allows
dynamic code compilation.

However, it currently doesn't support ShadowRealms, so the
implementation here is a close approximation, using PerformEval as the
basis.
See: https://github.com/tc39/proposal-dynamic-code-brand-checks/issues/19

This is required to support the new function signature for the CSP
hook, and will allow us to slot in Trusted Types support in the future.
2025-07-09 15:52:54 -06:00
Shannon Booth
7d44640c0f LibJS: Assume is_strict_mode called with running execution context
This should always be invoked when there is an execution context
on the stack.
2025-05-23 03:25:55 +02:00
Timothy Flynn
2401764697 LibJS: Update spec steps / links for the JSON modules proposal
This proposal has reached stage 4 and been merged into the main ECMA-262
spec. See:

3feb1ba
2025-04-29 07:33:08 -04:00
Timothy Flynn
3867a192a1 LibJS: Update spec steps / links for the import-assertions proposal
This proposal has reached stage 4 and been merged into the main ECMA-262
spec. See:

4e3450e
2025-04-29 07:33:08 -04:00
Andreas Kling
58925887ce LibJS: Inline VM::bytecode_interpreter() 2025-04-29 02:09:35 +02:00
Andreas Kling
4d17707b26 LibJS: Store bytecode VM program counter in ExecutionContext
This way it's always automatically correct, and we don't have to
manually flush it in push_execution_context().

~7% speedup on the MicroBench/call* tests :^)
2025-04-28 21:12:48 +02:00
Andreas Kling
233097c250 LibJS: Inline part of VM::run_queued_promise_jobs()
Most of the time there are no queued promise jobs to run after exiting
a stack frame. By moving the check inline, leaving a function call gets
a measurable speedup in the common case.
2025-04-28 10:39:42 -04:00
Shannon Booth
7dd7e5b438 LibJS+LibWeb: Defer initialization of the Agent after VM constructor
This helps unwind a niggly depedency where the VM owns and constructs
the Heap and the Agent. But the agent wants to have customized
construction that depends on the heap. Solve this by defering
the initialization of the Agent to after we have constructed the
VM and the heap.
2025-04-25 14:07:51 +02:00
Shannon Booth
8263a9863f LibJS+LibWeb: Do not return error from VM::create
This never returns an error to propogate, also allowing ErrorOr
to be removed from creating the main thread VM.
2025-04-25 14:07:51 +02:00
Shannon Booth
e124ef52ee LibJS+LibWeb: Set [[CanBlock]] false to Agent for window agent
similar-origin window agents have the [[CanBlock]] flag set to false.
Achieve this by hooking up JS's concept with an agent to HTML::Agent.
For now, this is only hooked up to the similar-origin window agent
case but should be extended to the other agent types in the future.
2025-04-22 11:50:35 -04:00
Andreas Kling
81d4ed27d8 LibJS: Add cache for the string "[object Object]"
This is very frequently returned by Object.prototype.toString(),
so we benefit from caching it instead of recreating it every time.

Takes Speedometer2.1/EmberJS-Debug-TodoMVC from ~4000ms to ~3700ms
on my M3 MacBook Pro.
2025-04-15 13:08:27 +02:00
Andreas Kling
e4941a36b0 LibJS: Remove unused struct NativeStackFrame 2025-04-12 11:07:48 +02:00
Kenneth Myhra
82a2ae99c8 Everywhere: Remove DeprecatedFlyString + any remaining references to it
This reverts commit 7c32d1e8a5.
2025-04-02 11:43:13 +02:00
Andreas Kling
7c32d1e8a5 Revert "Everywhere: Remove DeprecatedFlyString + any remaining references to it"
This reverts commit 3131e6369f.

Greatly regressed JavaScript benchmark performance.
2025-04-01 15:40:27 +02:00
Kenneth Myhra
3131e6369f Everywhere: Remove DeprecatedFlyString + any remaining references to it 2025-04-01 12:50:00 +02:00
Andreas Kling
c71772126f LibJS: Remove ByteString internals from PrimitiveString
PrimitiveString is now internally either UTF-8, UTF-16, or both.
We no longer convert them to/from ByteString anywhere, nor does VM have
a ByteString cache.
2025-03-28 12:31:40 -04:00
Andreas Kling
46a5710238 LibJS: Use FlyString in PropertyKey instead of DeprecatedFlyString
This required dealing with *substantial* fallout.
2025-03-24 22:27:17 +00:00
Timothy Flynn
85b424464a AK+Everywhere: Rename verify_cast to as
Follow-up to fc20e61e72.
2025-01-21 11:34:06 -05:00
Timothy Flynn
049109452e LibJS: Do not attempt to link modules which have failed to load
Linking a module has assertions about the module's state, namely that
the state is not "new". The state remains "new" if loading the module
has failed. See: https://tc39.es/ecma262/#figure-module-graph-missing

    In any case, this exception causes a loading failure, which results
    in A's [[Status]] remaining new.

So we must propagate that failure, instead of blindly moving on to the
linking steps.
2025-01-21 14:58:32 +01:00
Timothy Flynn
f2c19f96f8 LibJS: Implement Temporal.Now 2024-11-25 13:32:58 +01:00
Shannon Booth
fd0c63b338 LibJS: Align spec comments for ShadowRealm for HostInitializeShadowRealm
The proposed changes have been merged into the proposal with:

https://github.com/tc39/proposal-shadowrealm/commit/f20d02
2024-11-17 22:15:22 +01:00