Commit Graph

1317 Commits

Author SHA1 Message Date
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
Andreas Kling
7ed7782ece LibJS: Pre-bake the object shape for arrays created by RegExpBuiltinExec
This avoids going through the same exact shape transitions every time.
2025-12-12 11:43:35 -06:00
Andreas Kling
e5c2f2d471 LibJS: Poke into IndexedProperties directly in RegExpPrototype
For numeric property names, we can bypass the CreateDataPropertyOrThrow
machinery and poke directly into IndexedProperties when creating the
various arrays in RegExpPrototype functions.
2025-12-12 11:43:35 -06:00
Andreas Kling
646edbdd65 LibJS: Use more C++ inline caches in RegExpPrototype 2025-12-12 11:43:35 -06:00
Andreas Kling
499f0a59cf LibJS: Add variant of Object::set() that takes PropertyLookupCache
This allows us to use inline caches when setting properties in C++.
2025-12-12 11:43:35 -06: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
9709148512 LibJS: Add Value::is_non_negative_int32()
This helper combines the check for is_int32() and as_i32() >= 0 in a
single mask and compare operation.
2025-12-11 14:34:45 -06:00
Andreas Kling
bad16dc0e0 LibJS: Cache fully-formed PropertyKeys in Executable
Instead of creating PropertyKeys on the fly during interpreter
execution, we now store fully-formed ones in the Executable.

This avoids a whole bunch of busywork in property access instructions
and substantially reduces code size bloat.
2025-12-11 14:34:45 -06:00
Andreas Kling
e6521d8ead LibJS: Mark ArgumentsObject as non-interfering if parameter list empty
If the parameter list is empty, there are no mappings to worry about.
This allows various internal property access optimizations.

1.17x speedup on Octane/raytrace.js
2025-12-10 17:40:57 -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
6dbae3a6dd LibJS: Mark Value::to_numeric_slow_case() COLD
to_numeric() will have already handled the sane case where the value was
some kind of number.
2025-12-09 21:44:13 -06:00
Andreas Kling
cb23d65625 LibJS: Pass JS::Value directly to string formatting functions
We don't need to call .to_string_without_side_effects() when passing
a JS::Value in for string formatting. The Formatter will do it for us.
2025-12-09 21:44:13 -06:00
Andreas Kling
938faff2c6 LibJS: Mark all throw_completion() helpers COLD
Throwing an exception should always be the rare case.
2025-12-09 21:44:13 -06:00
Andreas Kling
5524848b5e LibJS: Mark Value slow path helper functions as COLD
The interpreter fast paths will normally handle these operations, so
it's fine to have rare cases in the cold section.
2025-12-09 21:44:13 -06:00
Andreas Kling
0087c26ab5 LibJS: Remove redundant fast paths from Value helpers
The bytecode interpreter already implements these fast paths, usually
more efficiently as well.

Turns out this stuff was getting inlined into the interpreter, so we
had many fast paths twice(!)
2025-12-09 21:44:13 -06: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
aplefull
e0dd182964 LibJS: Use stored input for RegExp legacy static property views
The m_last_match, m_left_context, and m_right_context views were being
created from a temporary string instead of from the owned m_input.
This caused the views to point to destroyed stack memory when accessing
RegExp.lastMatch after calling String.replace() with a regex.
2025-12-03 13:45:26 +01:00
Timothy Flynn
c7b3a4fcf8 LibJS: Implement Iterator.concat
This proposal reached stage 4 and was merged into ECMA-262. See:
https://github.com/tc39/ecma262/commit/aefd096
2025-12-03 12:08:40 +01:00
Timothy Flynn
7ee415a7c2 LibJS: Directly indicate when the IteratorHelper generator is complete
Our existing implementation was checking if the generator step result
was `undefined` to indicate that the generator is complete. This is
not sufficient for an upcoming implementation of Iterator.concat, where
`undefined` is used as an incomplete iteration result.

Instead, let's have the Iterator prototype return an IterationResult to
explicitly indicate its completeness. As a result, the prototype also
looks more like the spec now.
2025-12-03 12:08:40 +01:00
Timothy Flynn
6976ff389e LibJS: Mark IteratorHelper::create as infallible
This is just allocating an IteratorHelper. There is no way for this to
throw an exception.
2025-12-03 12:08:40 +01:00
Timothy Flynn
e011f8d6b1 LibJS: Replace [[UnderlyingIterator]] with [[UnderlyingIterators]]
This is an editorial change in the EMCA-262 spec. See:
https://github.com/tc39/ecma262/commit/c541680
2025-12-03 12:08:40 +01:00
Timothy Flynn
557805d6ef LibJS: Compute byteIndexInBuffer sooner in Atomic's DoWait
This is a normative change in the ECMA-262 spec. See:
https://github.com/tc39/ecma262/commit/4d2116b

Note this does not yet affect us as we do not implement the remainder of
this AO.
2025-12-03 12:08:40 +01:00
Andreas Kling
99bef81d09 LibJS: Fast path for TypedArray.slice()
We now try to do a bulk memcpy() when possible. This is significantly
faster than going byte-at-a-time.
2025-12-01 15:12:52 +01:00
Andreas Kling
4d7d8aa827 LibJS: Allow fast conversions between Uint8Array and Uint8ClampedArray
These two typed array kinds have the same exact underlying data type and
differ only in how assignment works.

We can allow them to take the fast paths for same-type conversions.
2025-12-01 15:12:52 +01:00
Callum Law
1f7fe97ac3 LibJS/AK: Move XorShift128PlusRNG to AK
This will be useful for CSS random functions so it should be in a
reusable place.

This does require us to use `AK::get_random` instead of
`Crypto::get_secure_random`, but this is fine since the latter is in the
process of being removed (see #6564).
2025-12-01 11:00:33 +00:00
Rocco Corsi
11dc254d27 LibJS: Add missing internal object string printing for debugging
When testing with JS_BYTECODE_DEBUG macro defined or using the All_Debug
profile, internal objects were not known in Value class to the function
Value::to_string_without_side_effects leading to a VERIFICATION FAILED
when running the test-js or test-web programs.

Internal objects are known in the Value class as cells, and do not have
a dedicated tag to identify them. Internal objects are detected using
is_cell function call, but only after all other types have been
checked as other types of non-internal objects can also be cells.

Both the String and Utf16String version of the function were updated.
2025-11-30 19:22:46 +01:00
Luke Wilde
0eceee0a05 LibJS: Replace Array.fromAsync with a native JavaScript implementation
This allows us to use the bytecode implementation of await, which
correctly suspends execution contexts and handles completion
injections.

This gains us 4 test262 tests around mutating Array.fromAsync's
iterable whilst it's suspended as well.

This is also one step towards removing spin_until, which the
non-bytecode implementation of await uses.

```
Duration:
     -5.98s

Summary:
    Diff Tests:
        +4     -4 

Diff Tests:
    [...]/Array/fromAsync/asyncitems-array-add-to-singleton.js  -> 
    [...]/Array/fromAsync/asyncitems-array-add.js               -> 
    [...]/Array/fromAsync/asyncitems-array-mutate.js            -> 
    [...]/Array/fromAsync/asyncitems-array-remove.js            -> 
```
2025-11-30 11:54:54 +01:00
Luke Wilde
a63b0cfaba LibJS: Introduce NativeJavaScriptBackedFunction
This hosts the ability to compile and run JavaScript to implement
native functions. This is particularly useful for any native function
that is not a normal function, for example async functions such as
Array.fromAsync, which require yielding.

These functions are not allowed to observe anything from outside their
environment. Any global identifiers will instead be assumed to be a
reference to an abstract operation or a constant. The generator will
inject the appropriate bytecode if the name of the global identifier
matches a known name. Anything else will cause a code generation error.
2025-11-30 11:54:54 +01:00
Luke Wilde
899c6ebffc LibJS: Make stored realm in NativeFunction non-null
We now always have a realm for NativeFunction, which allows removing an
old hack in internal_call and internal_construct.
2025-11-30 11:54:54 +01:00
Luke Wilde
354888640d LibJS/Bytecode: Make compilation use SharedFunctionInstanceData instead
All the data we need for compilation is in SharedFunctionInstanceData,
so we shouldn't depend on ECMAScriptFunctionObject.

Allows NativeJavaScriptBackedFunction to compile bytecode.
2025-11-30 11:54:54 +01:00
Luke Wilde
2d15326f5d LibJS: Moved SharedFunctionInstanceData into separate files
This will allow it to be reused by NativeJavaScriptBackedFunction.
2025-11-30 11:54:54 +01:00
Tim Ledbetter
166c8b116f LibJS: Avoid cast to out-of-range value in MathObject::abs() fast path 2025-11-30 11:54:02 +01:00