Commit graph

133 commits

Author SHA1 Message Date
Andreas Kling
879ac36e45 LibJS: Cache stable for-in iteration at bytecode sites
Cache the flattened enumerable key snapshot for each `for..in` site and
reuse a `PropertyNameIterator` when the receiver shape, dictionary
generation, indexed storage kind and length, prototype chain
validity, and magical-length state still match.

Handle packed indexed receivers as well as plain named-property
objects. Teach `ObjectPropertyIteratorNext` in `asmint.asm` to return
cached property values directly and to fall back to the slow iterator
logic when any guard fails.

Treat arrays' hidden non-enumerable `length` property as a visited
name for for-in shadowing, and include the receiver's magical-length
state in the cache key so arrays and plain objects do not share
snapshots.

Add `test-js` and `test-js-bytecode` coverage for mixed numeric and
named keys, packed receiver transitions, re-entry, iterator reuse, GC
retention, array length shadowing, and same-site cache reuse.
2026-04-10 15:12:53 +02:00
Johan Dahlin
c7969858d3 LibJS: Use SharedUtf16String in pattern_bound_names
Replace .to_vec() in parse_variable_declaration with
token_identifier_name(). Destructuring patterns use Rc clones instead
of string copies.

WebsitesParse: -0.1% RSS (-4 MB)
WebsitesRun:   -0.1% RSS (-5 MB)
2026-04-08 16:41:25 +02:00
Johan Dahlin
1fbf2023c8 LibJS: Expand lexer identifier cache to all identifiers
Remove <=8 char and ASCII-only restrictions, use first_code_unit % 128
for indexing.

WebsitesParse: 1.10x faster, -0.4% RSS (-12 MB)
WebsitesRun:   1.06x faster, -0.3% RSS (-11 MB)
2026-04-08 16:41:25 +02:00
Johan Dahlin
36fe4d4af3 LibJS: Avoid alloc in ScopeRecord::variable() on cache hit
contains_key() before entry() skips Utf16String alloc when the variable
name already exists in the scope.
2026-04-08 16:41:25 +02:00
Johan Dahlin
1d5e976fbb LibJS: Use SharedUtf16String keys in identifier_groups
Entry key is now an Rc clone instead of allocating a fresh Utf16String
per register_identifier call.

WebsitesParse: -3.4% RSS (-104 MB)
WebsitesRun:   -3.0% RSS (-97 MB)
2026-04-08 16:41:25 +02:00
Johan Dahlin
d566a81b5c LibJS: Remove redundant name param from register_identifier
Use id.name (SharedUtf16String) directly, eliminating callers .to_vec()
allocations.

WebsitesParse: 1.04x faster
WebsitesRun:   1.05x faster
2026-04-08 16:41:25 +02:00
Johan Dahlin
6e33d36eb5 LibJS: Cache common identifier spellings in the lexer
Add SharedUtf16String (Rc<Utf16String>) for zero-copy sharing. Lexer
caches short ASCII identifiers in a direct-mapped table.

WebsitesParse: 1.03x faster, -5.1% RSS (-164 MB)
WebsitesRun:   1.05x faster, -4.7% RSS (-161 MB)
2026-04-08 16:41:25 +02:00
Andreas Kling
b23aa38546 AK: Adopt mimalloc v2 as main allocator
Use mimalloc for Ladybird-owned allocations without overriding malloc().
Route kmalloc(), kcalloc(), krealloc(), and kfree() through mimalloc,
and put the embedded Rust crates on the same allocator via a shared
shim in AK/kmalloc.cpp.

This also lets us drop kfree_sized(), since it no longer used its size
argument. StringData, Utf16StringData, JS object storage, Rust error
strings, and the CoreAudio playback helpers can all free their AK-backed
storage with plain kfree().

Sanitizer builds still use the system allocator. LeakSanitizer does not
reliably trace references stored in mimalloc-managed AK containers, so
static caches and other long-lived roots can look leaked. Pass the old
size into the Rust realloc shim so aligned fallback reallocations can
move posix_memalign-backed blocks safely.

Static builds still need a little linker help. macOS app binaries need
the Rust allocator entry points forced in from liblagom-ak.a, while
static ELF links can pull in identical allocator shim definitions from
multiple Rust staticlibs. Keep the Apple -u flags and allow those
duplicate shim symbols for LibJS and LibRegex links on Linux and BSD.
2026-04-08 09:57:53 +02:00
Andreas Kling
c167bfd50a Meta: Make Rust FFI headers reproducible
Teach import_rust_crate() to track RustFFI.h as a real build output,
and teach the relevant Rust build scripts to rerun when their FFI
inputs change.

Also keep a copy of RustFFI.h in Cargo's own OUT_DIR and restore the
configured FFI output from that cached copy after cargo rustc runs.
This fixes the case where Ninja knows the header is missing, reruns
the custom command, and Cargo exits without rerunning build.rs
because the crate itself is already up to date.

When Cargo leaves multiple hashed build-script outputs behind, pick
the newest root-output before restoring RustFFI.h so we do not copy a
stale header after Rust-side API changes.

Finally, track the remaining Rust-side inputs that could leave build
artifacts stale: LibUnicode and LibJS now rerun build.rs when src/
changes, and the asmintgen rule now depends on Cargo.lock, the
BytecodeDef path dependency, and newly added Rust source files.
2026-03-31 15:59:04 +02:00
Johan Dahlin
b542617e09 LibJS: Box StatementKind::ClassFieldInitializer variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
057725c731 LibJS: Box StatementKind::FunctionDeclaration variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
247b9a0a87 LibJS: Box StatementKind::UsingDeclaration variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
0167c83b35 LibJS: Box StatementKind::VariableDeclaration variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
938ec6ca18 LibJS: Box StatementKind::Labelled variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
345dbab49a LibJS: Box StatementKind::With variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
a36d7e5d88 LibJS: Box StatementKind::ForInOf variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
64ea365379 LibJS: Box StatementKind::For variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
31ae13eec6 LibJS: Box StatementKind::DoWhile variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
f29b7ab579 LibJS: Box StatementKind::While variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
3496379d09 LibJS: Box StatementKind::If variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
5ab51b173d LibJS: Box ExpressionKind::Yield variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
c62b7f2f87 LibJS: Box ExpressionKind::ImportCall variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
15097fa8e0 LibJS: Box ExpressionKind::TaggedTemplateLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
9d0d8129f4 LibJS: Box ExpressionKind::OptionalChain variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
7262ab5880 LibJS: Box ExpressionKind::Member variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
07e187ae6d LibJS: Box ExpressionKind::Conditional variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
333ae7cc6d LibJS: Box ExpressionKind::Assignment variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
0cae77b94a LibJS: Box ExpressionKind::Update variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
4d5df1f10b LibJS: Box ExpressionKind::Logical variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
5a02479704 LibJS: Box ExpressionKind::Binary variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
2c210df618 LibJS: Box ExpressionKind::Object variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
badad22006 LibJS: Box ExpressionKind::Array variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
f3c68d516b LibJS: Box ExpressionKind::Sequence variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
9981b2eaf5 LibJS: Box ExpressionKind::PrivateIdentifier variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
9f0265f953 LibJS: Box ExpressionKind::BigIntLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
5da800bff2 LibJS: Box ExpressionKind::StringLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
8dda68e642 LibJS: Box StatementKind::Program variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
3d0aaf41a9 LibJS: Box ExpressionKind::RegExpLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
780605f986 LibJS: Box ExpressionKind::TemplateLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
bb44d3bb38 LibJS: Box StatementKind::Export variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
9d29703962 LibJS: Box StatementKind::Import variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
b922b4a31b LibJS: Box StatementKind::Try variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
ff047383e4 LibJS: Box StatementKind::Switch variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
102c73a072 LibJS: Box ExpressionKind::SuperCall variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
0a1bf8079c LibJS: Box ExpressionKind::New variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
d2a5c1260d LibJS: Box ExpressionKind::Call variant 2026-03-28 11:55:41 +01:00
Andreas Kling
c8a0a960b5 LibJS: Validate regex literals during parsing
Now that LibRegex is safe to use (for parsing) off the main thread,
we can validate regex literals directly while parsing JavaScript.

This allows us to remove the deferred regex compilation pass that we
previously ran on the main thread after parsing JS in the background.
2026-03-27 17:32:19 +01:00
InvalidUsernameException
61e6dbe4e7 LibJS: Copy object of member expression to preserve evaluation order
Noticed this pattern when reading some minified JS while debugging a
seemingly unrelated problem and immediately got suspicious because of my
earlier, similar fixes.
2026-03-22 15:40:38 +01:00
InvalidUsernameException
a94d8a1f78 LibJS: Remove some dead code
Looks like the combined parse and compile code path wasn't used
(anymore).
2026-03-22 15:40:38 +01:00
Andreas Kling
cf7576728d LibJS: Collect hoisted var declarations when checking module exports
The check_undeclared_exports() function only looked at top-level
VariableDeclaration nodes when collecting declared names. This missed
var declarations nested inside for loops, if/else blocks, try/catch,
switch statements, etc. Since var declarations are hoisted to the
enclosing module scope, they are valid export targets.

This caused legitimate modules (like the claude.ai JS bundle) to fail
with "'name' in export is not declared" errors when a var was declared
inside a for loop and later exported.

Fix this by recursively walking nested statements to collect var
declarations, while correctly not crossing function boundaries (since
var does not hoist out of functions) and not collecting block-scoped
let/const declarations.
2026-03-22 09:24:44 -05:00