This removes another Match member that required destruction. The "API"
for accessing the strings is definitely a bit awkward. We'll think of
something nicer eventually.
Our engine already keeps track of the home realm for all objects.
This is stored in Shape::realm(). We can use that instead of having
a dedicated member in ESFO for the same pointer.
Since there's always a home realm these days, we can also remove some
outdated fallback code from the days when having a realm was not
guaranteed due to LibWeb shenanigans.
If we have two PrimitiveString objects that are both backed by UTF-16
data, we don't have to convert them to UTF-8 for equality checking.
Just compare the underlying UTF-16 data. :^)
This allows us to remove the BoundFunction::m_name field, which we
were initializing with a formatted FlyString on every function binding,
despite never using it for anything.
FJCVTZS (Floating-point Javascript Convert to Signed fixed-point,
rounding toward Zero) does exactly what we need for ToInt32 in the
JavaScript specification.
This isn't world-changing, but it does give a ~2% boost on compute-
heavy benchmarks like JetStream, so we should obviously use it.
The fast path of to_i32() can be neatly inlined everywhere, and we still
have to_i32_slow_case() for non-trivial conversions.
For to_u32(), it really can just be implemented as a static cast to i32!
~2% of the Speedometer 2.1 profile was just repeatedly performing the
shape transitions to add these two properties. We can avoid all that
work by caching a premade shape.
We can use the placeholder syntax to specify the precision dynamically.
Note that `fraction_digits` is a double, which we do not support as a
precision argument. It's safe to cast to an integer here because we
guaranteed above that the value is in the range [0, 100], and is not
fractional.
It's generally considered a security issue to use non-format string
literals. We would likely just crash in practice, but let's avoid the
issue altogether.
We don't need the [[Fields]] and [[PrivateMethods]] slots for most ESFO
instances, so let's reduce their impact on class size!
This shrinks ESFO from 200 bytes to 160 bytes, allowing more allocations
before we have to collect garbage.
We were doing way too much computation every time an ESFO was
instantiated. This was particularly sad, since the results of these
computations were identical every time!
This patch adds a new SharedFunctionInstanceData object that gets
shared between all instances of an ESFO instantiated from some kind of
AST FunctionNode.
~5% speedup on Speedometer 2.1 :^)
This is an editorial change in the ECMA-402 spec. See:
a2beb66
We implement this change by introducing a virtual interface that all
Intl "service" objects must implement. A future patch will make use of
the virtualized RelevantExtensionKeys and ResolutionOptionDescriptors
accessors, and we will need to be able to use those slots from a generic
instance type.
This is an editorial change in the ECMA-402 spec. See:
e3f7260
Note the other changes in this commit do not apply to our implementation
as we defer to ICU for the affected steps.
There's a bit of a UTF-8 assumption with this change. But nearly every
caller of these methods were immediately creating a String from the
resulting ByteString anyways.
We cached the length identifier for GetLength, but not
GetLengthWithThis. This caused an `has_value()` verification failure
when accessing super.length. Found by Fuzzilli.
This is a slightly mystified attempt to recover the performance
regression seen on our JS benchmark runner after 3c2a2bb39f
and c7bba505ea.
With this change, c7bba505ea is effectively reverted from the
perspective of x86_64.
It seems both aarch64 and x86_64 are extremely sensitive to the use of
bitfields here. Unfortunately, aarch64 gains a huge speedup from them
while x86_64 sees a very noticeable slowdown.
Since we're talking about 5%+ swings in both directions here, let's go
for the best of both worlds and use ifdefs in the Operand memory layout.
We know that the payload is always 0 for these three Value types, and so
we can implement checking for them as full 64-bit compares against
constant values instead of checking just the tag.
This avoids shifting the tag 48 bits to the right before comparing it.
Since these are used all over the place, it actually leads to a nice
code size reduction.
Before this change, we were inlining this function after every
handler for instructions that could throw.
Forcing it out-of-line shrinks the main bytecode interpreter by 15%
and yields a decent 2.5% speedup on JetStream/gcc-loops.cpp.js
This packs the bytecode much better and gives us a decent performance
boost on throughput-focused benchmarks.
Measured on my M3 MacBook Pro:
- 4.7% speedup on Kraken
- 2.3% speedup on Octane
- 2.7% speedup on JetStream1
We can use the index's invalid state to signal an empty optional.
This makes Optional<StringTableIndex> 4 bytes instead of 8,
shrinking every bytecode instruction that uses these.
By specializing this template and using the special empty JS::Value as a
marker for the `void` state, we shrink this very common class from 16
bytes to 8 bytes.
This allows bytecode instruction handlers to return their result in a
single 64-bit register, allowing tighter code generation.