Commit graph

1758 commits

Author SHA1 Message Date
Andreas Kling
9312a9f86f LibJS: Move InstantiateOrdinaryFunctionExpression into interpreter
This is execution time stuff and doesn't belong in the AST.
2025-10-27 21:14:33 +01:00
Andreas Kling
44fa9566a8 LibJS: Generate bytecode for the BlockDeclarationInstantiation AO
This necessitated adding some new instructions for creating mutable and
immutable bindings.
2025-10-27 21:14:33 +01:00
Andreas Kling
892c7d980e LibJS: Let JS::Script remember whether its code is strict mode
We don't want to rely on having the AST node just to answer the question
"is this script strict mode?"
2025-10-27 21:14:33 +01:00
Andreas Kling
b712caf855 LibJS: Move bytecode executable cache to SharedFunctionInstanceData
This shrinks every Statement and ECMAScriptFunctionObject by one
pointer, and puts the bytecode cache in the only place that actually
makes use of it anyway: functions.
2025-10-27 21:14:33 +01:00
Andreas Kling
3a38040c82 LibJS: Make SharedFunctionInstanceData GC-allocated 2025-10-27 21:14:33 +01:00
aplefull
5632a52531 LibRegex: Properly track code units in u-v modes
Previously, both string_position and view_index used code unit offsets
regardless of mode. Now in unicode mode, these variables track code
point positions while string_position_in_code_units is properly
updated to reflect code unit offsets.
2025-10-24 21:23:06 +02:00
aplefull
cd4ac4f30f LibJS: Escape line terminators in regex source 2025-10-24 13:24:55 -04:00
aplefull
7ce4abe330 LibRegex+LibUnicode: Add unicode string properties 2025-10-24 13:24:55 -04:00
Luke Wilde
d4deafe5fe LibJS: Track current shape dictionary generation in PropertyLookupCache
When an object becomes too big (currently 64 properties or more), we
change its shape to a dictionary and don't do any further transitions.

However, this means the Shape of the object no longer changes, so the
cache invalidation check of `current_shape != cache.shape` is no longer
a valid check.

This fixes that by keeping track of a generation number for the Shape
both on the Shape object and in the cache, allowing that to be checked
instead of the Shape identity. The generation is incremented whenever
the dictionary is mutated.

Fixes stale cache lookups on Gmail preventing emails from being
displayed.

I was not able to produce a reproduction for this, plus the generation
count was over the 20k mark on Gmail.
2025-10-24 15:35:04 +02:00
Luke Wilde
a21d247b0e LibJS: Actually mark uncacheable dictionary shapes as uncacheable 2025-10-24 15:35:04 +02:00
caztanj
e93f44112d LibJS: Do not verify cycle root's status is linked in CyclicModule
This VERIFY is both incorrect and redundant. The VERIFY at step 2
verifies the status when evaluate is called on m_cycle_root.
2025-10-22 11:54:56 +02:00
Feng Yu
61c36e2865 LibJS: Sync additional Import Attributes spec changes
Some steps were not updated with tc39/ecma262#3057. This patch
syncs the remaining changes.
2025-10-22 10:58:19 +02:00
Andreas Kling
7ee8645b9c LibJS: Avoid redundant GC::Weak checks in hot inline cache code paths
By copying out pointees to a temporary, we can avoid some redundant
pointer chasing inside GC::Weak when hitting our inline caches.
2025-10-17 17:22:16 +02:00
Andreas Kling
dfa796a4e4 LibJS+LibWeb: Use GC::Weak instead of AK::WeakPtr for GC-allocated types
This makes some common types like JS::Object smaller (by 8 bytes) and
yields a minor speed improvement on many benchmarks.
2025-10-17 17:22:16 +02:00
aplefull
4b989b8efd LibRegex: Add support for forward references to named capture groups
This commit implements support for forward references to named capture
groups. We now allow patterns like \k<name>(?<name>x) and
self-references like (?<name>\k<name>x).
2025-10-16 16:37:54 +02:00
aplefull
25a47ceb1b LibRegex+LibJS: Include all named capture groups in source order
Previously, named capture groups in RegExp results did not always follow
their source order, and unmatched groups were omitted. According to the
spec, all named capture groups must appear in the result object in the
order they are defined, even if they did not participate in the match.
This commit makes sure we follow this requirement.
2025-10-16 16:37:54 +02:00
Andreas Kling
c23ed104e5 LibJS: Micro-optimize ECMAScriptFunctionObject::internal_construct()
- Add FLATTEN (same as we do for internal_call()).
- Demote nice-to-have VERIFYs to ASSERTs.
- Pass already-known Realm to ordinary_create_from_constructor

1.03x speedup on Octane/earley-boyer.js
2025-10-16 10:47:10 +02:00
Andreas Kling
d065171791 LibJS: Use property lookup caches for some of our hot C++ gets
We can use caching in a million more places. This is just me running JS
benchmarks and looking at which get() call sites were hot and putting
caches there.

Lots of nice speedups all over the place, some examples:

1.19x speedup on Octane/raytrace.js
1.13x speedup on Octane/earley-boyer.js
1.12x speedup on Kraken/ai-astar.js
1.10x speedup on Octane/box2d.js
1.08x speedup on Octane/gbemu.js
1.05x speedup on Octane/regexp.js
2025-10-14 15:47:38 +02:00
Andreas Kling
0fb9ba1e3a LibJS: Add Value::get() and Object::get() overloads with lookup cache
To speed up property access, callers of get() can now provide a lookup
cache like so:

    static Bytecode::PropertyLookupCache cache;
    auto value = TRY(object.get(property, cache));

Note that the cache has to be `static` or it won't make sense!

This basically brings the inline caches from our bytecode VM straight
into C++ land, allowing us to gain serious performance improvements.
The implementation shares code with the GetById bytecode instruction.
2025-10-14 15:47:38 +02:00
Andreas Kling
26c1dea22a LibJS: Move GetById logic to a separate header to prepare for reuse
We also make the code a bit more generic by making callers provide
(templated) callbacks that produce the property name and base expression
string if any.
2025-10-14 15:47:38 +02:00
Andreas Kling
0e4450f4b3 LibJS: Avoid function call if @@hasInstance is default implementation
This makes the instanceof operator signficantly faster by avoiding a
generic function call to @@hasInstance unless it has been overridden.

1.15x speed-up on Octane/earley-boyer.js
2025-10-13 17:15:44 +02:00
Andreas Kling
5a7b0a07cb LibJS: Mark global function declarations as globals
This allows us to use the GetGlobal and SetGlobal bytecode instructions
for them, enabling cached accesses.

2.62x speed-up on this Fibonacci program:

    function fib(n) {
        return n < 2 ? n : fib(n - 1) + fib(n - 2);
    }
    for (let i = 0; i < 50_000; ++i)
        fib(10);
2025-10-13 17:15:44 +02:00
Rocco Corsi
44d2a74eeb LibJS: Increase the stack limit when ASAN enabled
Linux, x86_64, Sanitizer, GNU runners on GitHub Action fail randomly
with a stack overflow on recursive test called:
Libraries/LibJS/Tests/runtime-error-call-stack-size.js
2025-10-13 09:07:39 -04:00
Andreas Kling
a76f420207 LibJS: Add fast path for division of two numbers
We already had fast paths for Add, Sub and Mul. Might as well do Div.

1.18x speed-up on this micro-benchmark:

    (() => {
        let a = 1234;
        for (let i = 0; i < 100_000_000; ++i)
            a / a;
    })()
2025-10-11 20:08:58 +02:00
Andreas Kling
755c8d8cd6 LibJS: Sprinkle [[likely]] on the fast paths in ValueInlines.h
1.04x speed-up on JetStream/quicksort.c.js
2025-10-11 20:08:58 +02:00
Andreas Kling
7462c10ee2 LibJS: Sprinkle [[unlikely]] on the PutBy* cache miss code paths
These caches are gonna be hitting most of the time, so let's give the
compiler a hint about this.

1.01x speed-up on MicroBench/pic-add-own.js
2025-10-11 20:08:58 +02:00
Andreas Kling
b47f8f94fe LibJS: Split PutBy* instructions into specialized per-kind variants
This allows the compiler to fold away lots of unused code for each kind.

1.10x speed-up on MicroBench/pic-add-own.js :^)
2025-10-11 20:08:58 +02:00
Andreas Kling
d13b4f3e39 LibJS: Remove unused member PutPrivateById::m_kind
Private property puts never have a PutKind.
2025-10-11 20:08:58 +02:00
Andreas Kling
e7a3c4dbad LibJS: Rename Bytecode::Op::PropertyKind => Bytecode::PutKind
This is only used to specify how a property is being added to an object
by Put* instructions, so let's call it PutKind.

Also add an enumeration X macro for it to prepare for upcoming
specializations.
2025-10-11 20:08:58 +02:00
Adam Patterson
120bba597d LibJS: Remove using-declaration.js from .prettierignore
This is the second and final commit to remove using-declaration from
.prettierignore. While there is standard formatting changes here, there
is also scoping changes for the 'using' declarations due to the
following error:

Libraries/LibJS/Tests/using-declaration.js: SyntaxError:
Using declaration cannot appear in the top level when source
type is `script` or in the bare case statement.
2025-10-09 15:49:49 -04:00
Adam Patterson
052013f8e6 LibJS: Partially format using-declaration.js with prettier
This contains prettier formatting fixes for using-declaration.js. The
file isn't fully formatted at this state. There is a minor scoping code
change that must happen in the next commit to be able to remove this
file from .prettierignore, but I wanted to separate the code change from
the formatting change to improve the review process.

This contains formatting and changing single quotes to double quotes.
2025-10-09 15:49:49 -04:00
Adam Patterson
0eac4cc6ad LibJS: Remove files from .prettierignore
.prettierignore had files listed for an issue with 'using' declarations,
this is no longer an issue for prettier (tested on 3.6.2).
2025-10-09 15:49:49 -04:00
Andreas Kling
695f02e8e5 LibJS: Give Interpreter a direct pointer to the identifier table
This gets rid of a lot of pointer chasing from interpreter to executable
to identifier table to the actual identifier.

1.05x speed-up on Kraken/ai-astar.js
2025-10-07 23:50:51 +02:00
Andreas Kling
d0df7c8c62 LibJS: Use [[likely]] annotations for cached environment lookups
These will generally be cached the vast majority of the time except on
first encounter, and sprinkling [[likely]] gives us a nice boost.

1.10x speed-up on this micro-benchmark:

    (() => {
        var a = 3;
        for (let i = 0; i < 100_000_000; ++i) { a; }
        eval("");
    })();
2025-10-07 23:50:51 +02:00
Andreas Kling
38e224cd9f LibJS: Make overflowing arithmetic on 2x Int32 values faster
Instead of converting them to doubles and doing double math, just do the
arithmetic operation in i64 space instead.

This gives us a ~1.25x speed-up on this kind of micro-benchmark:

    (() => {
        let a = -2124299999;
        for (let i = 0; i < 100_000_000; ++i) {
            a + a;
        }
    })()

Same idea for Add, Sub, and Mul.

There's a fair bit of overflowing Int32 arithmetic in some of the
JetStream benchmarks, and this seems like an obvious improvement.
2025-10-07 18:28:26 +02:00
Andreas Kling
4d99f9f5d1 LibJS: Try to avoid a [[GetOwnProperty]] when setting Object property
The [[Set]] operation on objects will normally end up doing
[[GetOwnProperty]] twice, but if the object and the receiver are one on
the same, we can avoid the double work.

AFAIK this is not observable via proxies or other mechanisms.

1.10x speed-up on MicroBench/object-set-with-rope-strings.js
2025-10-07 11:34:19 +02:00
Andreas Kling
7a2fe53c65 Revert "LibJS: Use HashMap::ensure() in VM string cache helpers"
This reverts commit 5810ddf339.

Appears to have introduced flakiness on WPT.
2025-10-06 12:15:34 +02:00
Andreas Kling
46c6176235 LibJS: Cache bytecode constant strings with their Utf16String as key 2025-10-05 21:44:06 +02:00
Andreas Kling
5810ddf339 LibJS: Use HashMap::ensure() in VM string cache helpers
This cuts the number of hash lookups on cache hit from 2 to 1.
2025-10-05 21:44:06 +02: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
0c3f113e05 LibJS: Avoid some heap allocations in JSRopeString::resolve()
- Give piece vectors some inline capacity (for the common case of a+b)
- Pre-calculate the sum of UTF-16 code unit lengths for StringBuilder
2025-10-05 21:44:06 +02:00
Andreas Kling
15eb80cb5a LibJS: Prefer UTF-16 sources when resolving rope string to UTF-16 2025-10-05 16:39:14 +02:00
Andreas Kling
cc560a6feb LibJS: Avoid string ref-count churn in PrimitiveString::*_string_view() 2025-10-05 16:39:14 +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
Andreas Kling
792913e9f7 LibJS: Make PrimitiveString::create() take String/Utf16String by const&
This avoids unnecessary ref-count churn in the case where a string is
already in the VM's string cache.
2025-10-05 16:39:14 +02:00
Andreas Kling
0675c6e3cc LibJS: Make Value::to_utf16_string() avoid UTF-8 roundtrip if possible
To do this, it's not enough for to_utf16_string() to just be a wrapper
around to_string(), we have to duplicate some of the logic.
2025-10-05 16:39:14 +02:00
Timothy Flynn
400300945f LibJS: Fill all available space when TA.copyWithin shrinks the array
This is a normative change in the ECMA-262 spec. See:
d228070p
2025-10-03 09:03:40 +02:00
Timothy Flynn
a7e55f3024 LibJS: Explicitly prevent out-of-bounds access in String.lastIndexOf
This is a normative change in the ECMA-262 spec. See:
541b2f6

Note we already handled this case well, but let's update our impl to
match the latest spec text.
2025-10-03 09:03:40 +02:00
Timothy Flynn
a4991143e0 LibJS: Update spec links and steps for the U8Array base64/hex proposal
This proposal reached stage 4 and was merged into ECMA-262. See:
3dfa316
2025-10-03 09:03:40 +02:00
Timothy Flynn
a7e5fa2256 LibJS: Update spec links and steps for the Math.sumPrecise proposal
This proposal reached stage 4 and was merged into ECMA-262. See:
27172c8
2025-10-03 09:03:40 +02:00