Commit Graph

1248 Commits

Author SHA1 Message Date
Andreas Kling
88d715fc68 LibJS: Eliminate HashMap operations in SFID by caching parser data
Cache necessary data during parsing to eliminate HashMap operations
in SharedFunctionInstanceData construction.

Before: 2 HashMap copies + N HashMap insertions with hash computations
After: Direct vector iteration with no hashing

Build FunctionScopeData for function scopes in the parser containing:
- functions_to_initialize: deduplicated var-scoped function decls
- vars_to_initialize: var decls with is_parameter/is_function_name
- var_names: HashTable for AnnexB extension checks
- Pre-computed counts for environment size calculation
- Flags for "arguments" handling

Add ScopeNode::ensure_function_scope_data() to compute the data
on-demand for edge cases that don't go through normal parser flow
(synthetic class constructors, static initializers, module wrappers).

Use this cached data directly in SFID with zero HashMap operations.
2026-01-25 23:08:36 +01:00
Colleirose
bf7fd80140 LibCrypto+AK: Merge LibCrypto/SecureRandom into AK/Random
AK/Random is already the same as SecureRandom. See PR for more details.

ProcessPrng is used on Windows for compatibility w/ sandboxing measures
See e.g. https://crbug.com/40277768
2026-01-23 15:53:27 +01:00
Andreas Kling
4d92c4d71a LibJS: Skip initializing constant slots in ExecutionContext
Every function call allocates an ExecutionContext with a trailing array
of Values for registers, locals, constants, and arguments. Previously,
the constructor would initialize all slots to js_special_empty_value(),
but constant slots were then immediately overwritten by the interpreter
copying in values from the Executable before execution began.

To eliminate this redundant initialization, we rearrange the layout from
[registers | constants | locals] to [registers | locals | constants].
This groups registers and locals together at the front, allowing us to
initialize only those slots while leaving constant slots uninitialized
until they're populated with their actual values.

This reduces the per-call initialization cost from O(registers + locals
+ constants) to O(registers + locals).

Also tightens up the types involved (size_t -> u32) and adds VERIFYs to
guard against overflow when computing the combined slot counts, and to
ensure the total fits within the 29-bit operand index field.
2026-01-19 10:48:12 +01:00
Andreas Kling
f1cf79cac4 LibJS: Make Error stack strings UTF-16 from the get-go
We were creating these as UTF-8 and then converting it to UTF-16 moments
later when someone tried using the string for something.
2026-01-18 19:00:32 +01:00
Andreas Kling
cec0d3eae8 LibJS: Avoid some unnecessary object copies in Error::stack_string() 2026-01-18 19:00:32 +01:00
Andreas Kling
b5fc557709 LibJS: Cache the formatted Error.prototype.stack string
Generating the stack trace string is expensive as it involves
formatting each frame with function names, file paths, and line
numbers. Since the stack trace is immutable after error creation,
we can cache the formatted string on first access.

This matches the caching behavior of V8 and JavaScriptCore, which
also return the same cached string on subsequent accesses to the
stack property.
2026-01-18 19:00:32 +01:00
Andreas Kling
b6b06f691a LibJS: Make PropertyAttributes and default_attributes constexpr
This allows it to be inlined everywhere instead of occurring a fajillion
times in separate BSS locations.
2026-01-18 10:10:04 +01:00
Timothy Flynn
3fb0e69c20 LibJS: Flip validity check to an assertion in CalendarMonthDayFromFields
This is an editorial change in the Temporal proposal. See:
https://github.com/tc39/proposal-temporal/commit/163d589
2026-01-16 14:31:31 +01:00
Timothy Flynn
076bbd4c33 LibJS: Hoist early return in CalendarDateUntil to the top
This is an editorial change in the Temporal proposal. See:
https://github.com/tc39/proposal-temporal/commit/264e4b8
2026-01-16 14:31:31 +01:00
Timothy Flynn
6cd765c19c LibJS: Flip validity check to an assertion in IsValidDuration
This is an editorial change in the Temporal proposal. See:
https://github.com/tc39/proposal-temporal/commit/e65f411
2026-01-16 14:31:31 +01:00
Ali Mohammad Pur
ea65181444 Meta+LibJS: Upgrade simdjson to the latest version
5e0ee26e8b pulls in an old version of
simdjson, this commit upgrades to the latest release.
This commit also pins `dav1d` to the version it was before this change.
2026-01-16 13:11:05 +01:00
Luke Wilde
f77b72040e LibJS/Temporal: Implement finding time zone transitions 2026-01-16 07:00:02 -05:00
Luke Wilde
23659b1130 LibJS: Floor nanoseconds to seconds conversion when finding TZ offsets
Otherwise, for example, -5,000,000,000 and -5,000,000,001 nanoseconds
are indistinguishable when a nanosecond could cross into a new time
zone offset.
2026-01-16 07:00:02 -05:00
Luke Wilde
8395db7e84 LibCrypto+LibJS: Add to_i64 method for SignedBigInteger and use it 2026-01-16 07:00:02 -05:00
Timothy Flynn
b517e5b947 LibJS: Avoid sign negations in Temporal's DifferenceZonedDateTime
This is an editorial change in the Temporal proposal. See:
https://github.com/tc39/proposal-temporal/commit/407fa01
2026-01-13 13:02:22 -05:00
Timothy Flynn
3eabdcf460 LibJS: Replace Temporal's BalanceISODate with AddDaysToISODate
This is an editorial change in the Temporal proposal. See:
https://github.com/tc39/proposal-temporal/commit/b28ef08
2026-01-13 13:02:22 -05:00
Andreas Kling
0710b24f2d LibJS: Optimize JSON.stringify with single StringBuilder
This patch improves JSON.stringify performance through three changes:

1. Use a single StringBuilder for the entire operation instead of
   building up intermediate strings and concatenating them.

2. Format numbers directly into the StringBuilder via a new public
   number_to_string(StringBuilder&, ...) overload, avoiding temporary
   String allocations.

3. Track indentation as a depth counter instead of repeatedly
   concatenating the gap string.
2026-01-12 13:53:28 -05:00
Andreas Kling
5e0ee26e8b LibJS: Use simdjson for JSON.parse
Replace the custom AK JSON parser with simdjson for parsing JSON in
LibJS. This eliminates the intermediate AK::JsonValue object graph,
going directly from JSON text to JS::Value.

simdjson's on-demand API parses at ~4GB/s and only materializes values
as they are accessed, making this both faster and more memory efficient
than the previous approach.

The AK JSON parser is still used elsewhere (WebDriver protocol, config
files, etc.) but LibJS now uses simdjson exclusively for JSON.parse()
and JSON.rawJSON().
2026-01-12 13:53:28 -05:00
Jelle Raaijmakers
ae20ecf857 AK+Everywhere: Add Vector::contains(predicate) and use it
No functional changes.
2026-01-08 15:27:30 +00:00
Shannon Booth
8ea37c4de4 LibJS: Remove unnecessary return in Object::define_native_accessor 2026-01-08 12:57:17 +01:00
Andreas Kling
12e49ad053 LibJS: Visit entire SimpleIndexedProperties packed vector in bulk 2026-01-08 00:26:57 +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
Andreas Kling
7a4e74be96 LibJS: Don't skip indexed property storage switching in Array fast path
If we call put() directly on the underlying indexed property storage
like we were doing here, we skip the checks that switch from flat to
sparse property storage when a huge index is suddenly accessed.

This was caught by folks hitting memory issues when running test-js.
2026-01-07 07:52:03 -05:00
Andreas Kling
4c10f44e3e LibJS: Remove bogus VERIFY_NOT_REACHED() in WeakRef::remove_dead_cells()
It's harmless if the WeakRef is asked to remove dead cells when it has
no dead cells to remove. This can happen if the WeakRef lives longer
due to someone referencing it. Caught by test-js with different GC
frequency.
2026-01-07 07:52:03 -05:00
Andreas Kling
a9cc425cde LibJS+LibWeb: Add missing GC marking visits
This adds visit_edges(Cell::Visitor&) methods to various helper structs
that contain GC pointers, and makes sure they are called from owning
GC-heap-allocated objects as needed.

These were found by our Clang plugin after expanding its capabilities.
The added rules will be enforced by CI going forward.
2026-01-07 12:48:58 +01:00
Jelle Raaijmakers
d00571719f LibGC+LibJS+LibWeb: Add Visitor::visit(Optional<T>)
No functional changes.
2026-01-06 10:55:56 +01:00
InvalidUsernameException
831cecd644 LibJS+LibWeb: Add missing visits for cached cross-origin properties
This was causing GC-related crashes on various websites, most
prominently on any site that contains embedded YouTube videos. The issue
can be reproduced by going to any YouTube video, using the _Share_
button below it and pasting the embed code into an empty HTML file and
loading it through localhost.

This is technically a regression from
89dbdd3411 in that the problem became
visible with that commit. However, there is nothing wrong with the
commit by itself. It just happens that `Origin::is_same_origin_domain()`
prior to that commit was completely bogus and would mistakenly return
true in almost all cases, so the cross-origin code paths were not
exercised.

I am uncertain how to make a automatic test case for this problem, given
the nature of it being GC- and cross-origin-related. So there is no
regression test included in this commit.
2026-01-06 00:01:01 +01:00
Ali Mohammad Pur
3f35d84785 LibRegex+LibJS: Flatten the bytecode buffer before regex execution
This makes it so we don't have to unnecessarily check for having a
flattened buffer; significant performance increase.
2026-01-05 18:22:11 +01:00
CountBleck
b42402514e LibJS: Don't crash on enormous maxByteLengths for SharedArrayBuffer
I mistakenly used ensure_capacity upon first implementing this, leading
to a crash when the requested memory couldn't be allocated. Instead,
we now pass the maxByteLength to create_shared_byte_data_block (which
throws the RangeError for us) and shrink the data block back down to the
proper size.
2026-01-05 06:38:55 -05: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
Shannon Booth
5eac5a94cf LibJS: Implement an as_if<T> helper for JS::Value
This is to make it much easier when trying to pull out an object
of a specific type from a JS::Value, instead of needing to do the
repetitive checking that it is an object, getting that object,
checking that object is of a specific type, then casting to that
type.
2025-12-30 12:40:27 +01:00
Andreas Kling
ce0a16d11c LibJS: Simplify how we know which builtin a FunctionObject represents
Instead of storing a list of builtin function objects with the realm,
just move the builtin field from NativeFunction up to FunctionObject.

Now you can ask any FunctionObject for its builtin(), and we no longer
need the get_builtin_value() API.

Fixes 10 test262 tests that were querying the realm builtins at a
bad time.

Regressed in 54b755126c.
2025-12-25 23:59:21 +01:00
Andreas Kling
df88938b61 LibJS: Propagate function length etc to new Function objects
Fixes 12 test262 tests.

Regressed in 63eccc5640.
2025-12-25 23:59:21 +01:00
Andreas Kling
b6bd38c55d AK+LibJS: Make SinglyLinkedList::remove() return a new iterator
This fixes an issue where the iterator could be in a bad state after
removing something from the list.

The behavior is also more idiomatic in general.
2025-12-25 20:21:37 +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
0504fffe6b LibJS: Don't unregister WeakRef during finalization phase
This "optimization" was not safe as it caused the ongoing iteration
of GC::Heap's weak container list to end immediately.
2025-12-25 20:21:37 +01:00
Andreas Kling
1a687cf0c6 LibJS: Rearrange members to shrink Promise by 8 bytes 2025-12-21 12:08:41 -06:00
Andreas Kling
a143733e69 LibJS: Specialize Optional<PropertyKey>
This shrinks Shape by another 8 bytes.
2025-12-21 12:08:41 -06:00
Andreas Kling
0f937c70f7 LibJS: Rearrange members of Shape to shrink it by 8 bytes 2025-12-21 12:08:41 -06:00
Andreas Kling
5214e30182 LibJS: Shrink FunctionEnvironment by reordering members a bit 2025-12-21 12:08:41 -06:00
Andreas Kling
72b95d79d2 LibJS: Shrink DeclarativeEnvironment by shrinking DisposeCapability 2025-12-21 12:08:41 -06:00
Andreas Kling
f09695ab3f LibJS: Shrink JS::Object by 8 bytes
Turn some boolean flags into a bitfield to save space and slim down
JS::Object (as well as everything that inherits from it).
2025-12-21 12:08:41 -06:00
Andreas Kling
63eccc5640 LibJS: Don't make extra copies of every JS function's source code
Instead, let functions have a view into the AST's SourceCode object's
underlying string data. The source string is kept alive by the AST, so
it's fine to have views into it as long as the AST exists.

Reduces memory footprint on my x.com home feed by 65 MiB.
2025-12-21 10:06:04 -06:00
Andreas Kling
737d9727c2 LibJS+LibWeb: Add various fast_is<T>() helpers for common things 2025-12-20 09:13:19 -06:00
Andreas Kling
9f4a96de67 LibJS: Add fast_is<T>() for all typed array classes 2025-12-20 09:13:19 -06:00
Andreas Kling
959afc21f8 LibJS: Add fast_is<T>() for ArrayBuffer 2025-12-20 09:13:19 -06:00
Andreas Kling
9290939200 LibJS: Remove FunctionObject::fast_is<T>() deletion
This broke fast is<ECMAScriptFunctionObject> and is<NativeFunction>.
By moving them up to Object, we get fast checks for these types again.

Regressed in aec20e032b.
2025-12-20 09:13:19 -06:00
Andreas Kling
cbe75f8251 LibJS: Lazily instantiate "prototype" field on ECMAScriptFunctionObject
This field is rarely accessed but we were creating it for every single
script function instantiated.

It's a little awkward but the same optimization can be found in other
engines, so it's nothing crazy.

This avoids creating roughly 80,000 objects on my x.com home feed.
2025-12-17 12:50:17 -06:00
Andreas Kling
eb04076d2d LibJS: Only do regexp_builtin_exec() fast calls for real RegExpObject
The static_cast should have been a clue that this wasn't entirely safe.

Fixes one test262 crash:

    test/staging/sm/RegExp/prototype.js 💥️ -> 

Regressed in 54b755126c.
2025-12-15 14:10:57 -06:00
Andreas Kling
54b755126c LibJS: Skip generic call when using regexp builtins in StringPrototype
For StringPrototype functions that defer to RegExpPrototype builtins,
we can skip the generic call stuff (eliding the execution context etc)
and just call the builtin directly.

1.03x speedup on Octane/regexp.js
2025-12-13 13:51:12 -06:00