Commit graph

1456 commits

Author SHA1 Message Date
Andreas Kling
5ea45da15f LibJS: Store NewObject result directly in preferred dst if possible
This avoids a Mov after every object literal.
2025-03-27 19:50:13 +00:00
Andreas Kling
900f209b34 LibJS: Make Optional<Operand> use less space
Shrink these down from 12 bytes to 8 bytes, which helps make many
bytecode instructions smaller.
2025-03-27 19:50:13 +00:00
Andreas Kling
a29d820f87 LibJS: Make Optional<IdentifierTableIndex> use less space
We can use the index's invalid state to signal an empty optional.
This makes Optional<IdentifierTableIndex> 4 bytes instead of 8,
shrinking every bytecode instruction that uses these.
2025-03-27 19:50:13 +00:00
Andreas Kling
904beef6d2 LibJS: Put newly instantiated functions into locals more efficiently
- Don't allocate a separate register, store directly into the local.
- Mark the local as initialized to avoid emitting TDZ checks.
2025-03-27 19:50:13 +00:00
Andreas Kling
6c70dc5f09 LibJS: Create FunctionParameters earlier in the parser
This avoids making multiple copies of the Vector<FunctionParameter> in
the parser.
2025-03-27 19:50:13 +00:00
Andreas Kling
8af5f25dd0 LibJS: Use a premade shape for normal function object prototypes
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This avoids one shape allocation per function instantiation.
2025-03-27 15:00:43 +00:00
Andreas Kling
dba1798de7 LibJS: Make StringOrSymbol::as_string() return a const reference
No need to copy the FlyString here, we can avoid the ref count churn.
2025-03-27 15:00:43 +00:00
Andreas Kling
7477002e46 LibJS: Keep parsed function parameters in a shared data structure
Instead of making a copy of the Vector<FunctionParameter> from the AST
every time we instantiate an ECMAScriptFunctionObject, we now keep the
parameters in a ref-counted FunctionParameters object.

This reduces memory usage, and also allows us to cache the bytecode
executables for default parameter expressions without recompiling them
for every instantiation. :^)
2025-03-27 15:00:43 +00:00
Lucien Fiorini
6b6e13e28c LibJS: Avoid emptying the return value register in try/finally
This works because at the end of the finally chunk, a
ContinuePendingUnwind is generated which copies the saved return value
register into the return value register. In cases where
ContinuePendingUnwind is not generated such as when there is a break
statement in the finally block, the fonction will return undefined which
is consistent with V8 and SpiderMonkey.
2025-03-27 12:18:30 +00:00
Andreas Kling
c12f8b80dc LibJS: Add fast_is<T> helpers for all the primitive wrapper objects
The JS runtime is full of checks for is<NumberObject> and friends.
They were showing up in a Speedometer profile as ~1% spent in
dynamic_cast, and this basically chops that down to nothing.
2025-03-25 23:57:00 +00:00
Andreas Kling
3cc5b1a6a5 LibJS: Do a bit less stuff in PropertyKey::try_coerce_into_number()
The many out-of-line function calls here stood out in a profile.
2025-03-25 23:57:00 +00:00
Andreas Kling
202cbe7df6 LibJS: Constant-fold unary expressions
!0 and !1 are very common patterns in minified JavaScript, and we should
figure out that they're constants. :^)
2025-03-25 19:14:12 +00:00
Jess
f3a937ee76 LibJS: Fix integer overflow in target_offset of TypedArray.set() 2025-03-25 07:45:42 +00:00
Andreas Kling
f1914893e9 LibJS+LibWeb: Remove more uses of DeprecatedFlyString 2025-03-24 22:27:17 +00: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
Andreas Kling
fc744e3f3f LibJS: Add fast path for strings in Value::to_property_key()
If the Value is already a primitive string, we can skip all the
conversion ceremony and return a PropertyKey right away.
2025-03-24 22:27:17 +00:00
Andreas Kling
53da8893ac LibJS: Replace PropertyKey(char[]) with PropertyKey(FlyString)
...and deal with the fallout.
2025-03-24 22:27:17 +00:00
Andreas Kling
d7908dbff5 LibJS: Change PropertyKey(ByteString) to PropertyKey(String)
...and deal with the fallout.
2025-03-24 22:27:17 +00:00
Andreas Kling
3b5032c4b1 LibJS: Remove unused StringOrSymbol constructors 2025-03-24 22:27:17 +00:00
Andreas Kling
e83a2c2369 LibJS: Prefer Value::to_string() over to_byte_string() in more places
We should always prefer working with String, and Value::to_string() may
even return a cached String if the Value refers to a primitive string,
but no caching occurs for ByteString.
2025-03-24 22:27:17 +00:00
Aliaksandr Kalenik
a8285f255b LibJS: Skip allocation of temp object for primitive types in Value::get
Previously, `String.prototype.split()` caused the construction of a
temporary StringObject when a string primitive was passed as an
argument, solely to perform a Symbol.split lookup. This change allows
skipping that allocation by looking directly into the prototype of
primitive values.

As a result, we can avoid ~200000 StringObject allocations in a single
test from the Speedometer 2 benchmark.

Co-Authored-By: Andreas Kling <andreas@ladybird.org>
2025-03-24 20:38:11 +01:00
Andreas Kling
5f12b2a05d LibJS: Make IteratorRecord inherit from Cell, not Object
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This shaves its size down from 104 bytes to 48 bytes, cutting GC
pressure caused by this type in more than half.
2025-03-22 16:59:44 -05:00
Andreas Kling
1d88c4529c LibJS: Allow JS::Value to store a non-object Cell
This will allow us to refer to non-object Cells more readily in bytecode
and opens up for some nice optimizations.
2025-03-22 16:59:44 -05:00
Tim Ledbetter
ed62aa6224 Revert "LibJS: Reduce number of proxy traps called during for..in…
…iteration"

This reverts commit 357eeba49c.
2025-03-21 11:44:21 -05:00
Andreas Kling
c528c01745 LibJS: Elide empty variable environment for default parameters
No need to create a separate variable environment if all the parameters
are going into locals anyway.
2025-03-21 00:58:34 +01:00
Andreas Kling
b971e1ece0 LibJS: Mark locals as outside TDZ immediately after initializing
This avoids emitting TDZ checks for multiple bindings declared and
referenced within one variable declaration, i.e:

    var foo = 0, bar = foo;

In the above case, we'd emit an unnecessary TDZ check for the second
reference to `foo`.
2025-03-21 00:58:34 +01:00
Andreas Kling
357eeba49c LibJS: Reduce number of proxy traps called during for..in iteration
Before this change, we would enumerate all the keys with
[[OwnPropertyKeys]], and then do [[GetOwnPropertyDescriptor]] twice for
each key as we went through them.

We now only do one [[GetOwnPropertyDescriptor]] per key, which
drastically reduces the number of proxy traps when those are involved.
The new trap sequence matches what you get with V8, so I don't think
anyone will be unpleasantly surprised here.
2025-03-20 17:50:02 -05:00
Andreas Kling
49d2a8df23 LibJS: Elide empty lexical environments for parameter evaluation
If all the parameter default values end up in locals, the lexical
environment we create to hold them would never be used for anything,
and so we can elide it and avoid the GC work.
2025-03-20 12:51:21 -05:00
Andreas Kling
842a189c2e LibJS: Elide empty lexical environment when direct eval() is present
Direct eval() always creates a new lexical environment, so we don't have
to worry about those here. The var environments still need special care.
2025-03-20 12:51:21 -05:00
Andreas Kling
f6141df589 LibJS: Remove unnecessary check in for..in iterator implementation 2025-03-20 12:51:21 -05:00
Andreas Kling
fb3d1c2754 LibJS: Reuse the internal iterator object across a for..in iteration
Instead of creating a new iterator result Object for every step of
for..in iteration, we can create a single object up front and reuse it
for every step. This avoids generating a bunch of garbage that isn't
observable by author code anyway.

We can also reuse the existing premade shape for these objects.
2025-03-20 12:51:21 -05:00
Andreas Kling
37bf083536 LibJS: Do a single pass to prune non-enumerable keys for iteration
Instead of pruning as-we-go, which means a ton of hash lookups,
we now only do a single pass to prune all non-enumerable keys when
setting up for for..in iteration.
2025-03-20 12:51:21 -05:00
Andreas Kling
660d533b50 LibJS: Don't assume [[GetOwnPropertyDescriptor]] always succeeds
It can fail if we're talking to a badly-behaved proxy when enumerating
object properties for iteration.
2025-03-20 12:51:21 -05:00
Andreas Kling
37c7eb14fe LibJS: Let GetGlobal cache module environment lookups when possible 2025-03-20 12:51:21 -05:00
Andreas Kling
8fcff2fa18 LibJS: Store Module::environment() as ModuleEnvironment
Let's use a more specific type here to allow for devirtualization.
2025-03-20 12:51:21 -05:00
Jess
12cbefbee7 LibJS+LibCrypto: Use a bitwise approach for BigInt's as*IntN methods
This speeds up expressions such as `BigInt.asIntN(0x4000000000000, 1n)`
(#3615). And those involving very large bigints.
2025-03-20 09:44:12 +01:00
Jess
92d0cd3c7c LibJS: Make InvalidIndex detail the full range of allowed values 2025-03-20 09:44:12 +01:00
Jess
f5a6704219 LibJS: Fix UAF in ECMAScriptFunctionObject::internal_construct
Currently, we create `this_argument` with
`ordinary_create_from_constructor`, then we use `arguments_list` to
build the callee_context.

The issue is we don't properly model the side-effects of
`ordinary_create_from_constructor`, if `new_target` is a proxy object
then when we `get` the prototype, arbitrary javascript can run.

This javascript could perform a function call with enough arguments to
reallocate the interpreters m_argument_values_buffer vector. This is
dangerous and leads to a use-after-free, as our stack frame maintains a
pointer to m_argument_values_buffer (`arguments_list`).
2025-03-19 10:31:00 +01:00
Timothy Flynn
780de1395b LibJS: Merge Intl.DurationFormat style and display fields into a struct
This is an editorial change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/d56d624
2025-03-18 11:47:23 -04:00
Timothy Flynn
00d00b84d3 LibJS: Ensure relevant extension keys are included in ICU locale data
This is a normative change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/7508197

In our implementation, we don't have the affected AOs directly, as we
delegate to ICU. So instead, we must ensure we provide ICU a locale with
the relevant extension keys present.
2025-03-18 11:47:23 -04:00
Timothy Flynn
37b8ba96f1 LibJS: Use currency digits for NumberFormat only for standard notation
This is a normative change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/9140da2
2025-03-18 11:47:23 -04:00
Timothy Flynn
96c059bf67 LibJS: Use correct enum casing in some Intl constructors 2025-03-18 11:47:23 -04:00
Timothy Flynn
ea10470071 LibJS: Correctly print labels for some Intl objects
For example, printing an Intl.Collator object would previously display:

    [Intl.Collator]  numeric:
    "en"  locale:
    "sort"  usage:
    "variant"  sensitivity:
    "upper"  caseFirst:
    "default"  collation:
    false  ignorePunctuation:
    false

We now print:

    [Intl.Collator]
      locale: "en"
      usage: "sort"
      sensitivity: "variant"
      caseFirst: "upper"
      collation: "default"
      ignorePunctuation: false
      numeric: false
2025-03-18 11:47:23 -04:00
Sam Atkins
9b7fb0850d LibJS+LibWebView: Treat trivia tokens as comments
Trivia is whatever whitespace and comments appear before a token.
Previously this was always given a TokenCategory of Invalid, so it
would be displayed as an error in the view-source page, with red wiggly
underlines. Instead, treat it as what it actually is: whitespace and
comments!
2025-03-04 15:54:03 -05:00
Timothy Flynn
532f156f4a LibJS: Remove some single-use Intl.DurationFormat variables
This is an editorial change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/4c139f1
https://github.com/tc39/ecma402/commit/da498c2
https://github.com/tc39/ecma402/commit/ed5c716
2025-03-04 07:36:10 -05:00
Timothy Flynn
1e462daa9b LibJS: Simplify the Intl.DurationFormat GetDurationUnitOptions AO
This is an editorial change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/d097048
2025-03-04 07:36:10 -05:00
Timothy Flynn
2f023c2d9c LibJS: Simplify Intl.DurationFormat.prototype.resolvedOptions
This is an editorial change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/e3d3406
2025-03-04 07:36:10 -05:00
Timothy Flynn
56a6daee4d LibJS: Standardize the spec-order of Intl.DurationFormat definitions
This is an editorial change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/54ca35d
https://github.com/tc39/ecma402/commit/6cdcab3
https://github.com/tc39/ecma402/commit/e4cbfba
2025-03-04 07:36:10 -05:00
Timothy Flynn
aa61307392 LibJS: Re-arrange and rename a few Intl properties
This is an editorial change in the ECMA-402 spec. See:
https://github.com/tc39/ecma402/commit/a46e37d
https://github.com/tc39/ecma402/commit/e102741
https://github.com/tc39/ecma402/commit/67a8417
https://github.com/tc39/ecma402/commit/ecb086c
2025-03-04 07:36:10 -05:00
aplefull
80b2c11c81 LibJS: Implement Math.sumPrecise 2025-03-03 21:46:22 +01:00