Commit graph

95 commits

Author SHA1 Message Date
Linus Groh
d3b7c06712 LibJS: Add Value(GCPtr<T>) and Value(NonnullGCPtr<T>) constructors
Let's avoid reaching for ptr() as much as possible.
2022-10-02 23:02:27 +01:00
Daniel Bertalan
2b69af2dfe AK+LibJS: Handle NaN-boxing pointers on AArch64
JS::Value stores 48 bit pointers to separately allocated objects in its
payload. On x86-64, canonical addresses have their top 16 bits set to
the same value as bit 47, effectively meaning that the value has to be
sign-extended to get the pointer. AArch64, however, expects the topmost
bits to be all zeros.

This commit gates sign extension behind `#if ARCH(X86_64)`, and adds an
`#error` for unsupported architectures, so that we do not forget to
think about pointer handling when porting to a new architecture.

Fixes #15290
Fixes SerenityOS/ladybird#56
2022-09-21 11:55:57 +02:00
davidot
d4736d17ae LibJS: Allow negative pointers in Value
Also ensure that all a nullptr input gives null object and you don't
accidentally dereference a nullptr.
2022-09-10 00:05:32 +01:00
Linus Groh
69415f0608 LibJS: Make string_to_bigint() a standalone function
This now matches the newly added string_to_number().
2022-08-30 10:30:54 +01:00
davidot
a9d2d806b6 LibJS: Use __builtin_isnan in static_assert instead of isnan
For the fuzzer build isnan was not usable in a constexpr context however
__builtin_isnan seems to always be.

Also while we're here add my name to the copyright since I forgot after
the Value rewrite.
2022-08-23 22:30:15 +01:00
Linus Groh
a022e548b8 LibJS: Replace GlobalObject with VM in Value AOs [Part 4/19]
This is where the fun begins. :^)
2022-08-23 13:58:30 +01:00
davidot
e746360b9a LibJS: Use NaN boxing to decrease the memory size of Values
Using the fact that there are 2^52-2 NaN representations we can
"NaN-box" all the Values possible. This means that Value no longer has
an explicit "Type" but that information is now stored in the bits of a
double. This is done by "tagging" the top two bytes of the double.
For a full explanation see the large comment with asserts at the top of
Value.

We can also use the exact representation of the tags to make checking
properties like nullish, or is_cell quicker. But the largest gains are
in the fact that the size of a Value is now halved.

The SunSpider and other benchmarks have been ran to confirm that there
are no regressions in performance compared to the previous
implementation. The tests never performed worse and in some cases
performed better. But the biggest differences can be seen in memory
usage when large arrays are allocated. A simple test which allocates a
1000 arrays of size 100000 has roughly half the memory usage.

There is also space in the representations for future expansions such as
tuples and records.

To ensure that Values on the stack and registers are not lost during
garbage collection we also have to add a check to the Heap to check for
any of the cell tags and extracting the canonical form of the pointer
if it matches.
2022-08-15 17:11:25 +02:00
davidot
8381e7f1e6 LibJS: Specialize Optional<Value>
Values can be "empty" which only has a valid meaning for array holes.
We can however use this state the represent the empty state of an
Optional<Value> which is used in a lot of placed, because of Completion
having one.
This saves 8 bytes for every Optional<Value>.
2022-08-15 17:11:25 +02:00
Linus Groh
1132151f3d LibJS: Use a template for 'Value from integral number' constructors
This also allows constructing from other integral types like u64, which
would have been ambiguous before (at least on i686):

```
error: call of overloaded 'Value(u64&)' is ambiguous
note: candidate: 'JS::Value::Value(i32)'
  175 |     explicit Value(i32 value)
      |              ^~~~~
note: candidate: 'JS::Value::Value(unsigned int)'
  164 |     explicit Value(unsigned value)
      |              ^~~~~
note: candidate: 'JS::Value::Value(long unsigned int)'
  153 |     explicit Value(unsigned long value)
      |              ^~~~~
note: candidate: 'JS::Value::Value(double)'
  141 |     explicit Value(double value)
      |              ^~~~~
```
2022-07-04 10:10:11 +02:00
Obinna Ikeh
3d99e83a86 LibJS: Update order of parameters in our is_less_than implementation
This change updates the parameter order of the is_less_than function
signature and calls to match accordingly with the spec
(https://tc39.es/ecma262/#sec-islessthan)
2022-06-13 17:37:11 -07:00
Linus Groh
b9b3d01bea LibJS: Add variant of to_integer_or_infinity() for plain doubles
In many cases we already know a certain value is a number, or don't have
JS values at all and would need to wrap doubles in a value. To optimize
these cases and avoid having to pass a global object into functions that
won't ever allocate or throw, add a standalone implementation of this
function that takes and returns doubles directly.
2022-05-06 22:32:47 +02:00
Idan Horowitz
086969277e Everywhere: Run clang-format 2022-04-01 21:24:45 +01:00
Andreas Kling
4b412e8fee Revert "LibJS: Get rid of unnecessary work from canonical_numeric_index_string"
This reverts commit 3a184f7841.

This broke a number of test262 tests under "TypedArrayConstructors".
The issue is that the CanonicalNumericIndexString AO should not fail
for inputs like "1.1", despite them not being integral indices.
2022-02-13 16:01:32 +01:00
Anonymous
d1cc67bbe1 LibJS: Avoid unnecessary ToObject conversion when resolving references
When performing GetValue on a primitive type we do not need to perform
the ToObject conversion as it will resolve to a property on the
prototype object.

To avoid this we skip the initial ToObject conversion on the base value
as it only serves to get the primitive's boxed prototype. We further
specialize on PrimitiveString in order to get efficient behaviour
behaviour for the direct properties.

Depending on the tests anywhere from 20 to 60%, with significant loop
overhead.
2022-02-13 14:44:36 +01:00
Anonymous
3a184f7841 LibJS: Get rid of unnecessary work from canonical_numeric_index_string
The spec version of canonical_numeric_index_string is absurdly complex,
and ends up converting from a string to a number, and then back again
which is both slow and also requires a few allocations and a string
compare.

Instead lets use the logic we already have as that is much more
efficient.

This improves performance of all non-numeric property names.
2022-02-13 14:44:36 +01:00
Linus Groh
bc183dbbcb LibJS: Replace uses of MarkedValueList with MarkedVector<Value>
This is effectively a drop-in replacement.
2022-02-09 12:25:27 +00:00
Linus Groh
6f20f49b21 Everywhere: Rename JS::PropertyKey variables from property_{name => key}
PropertyKey used to be called PropertyName, but got renamed. Let's
update all the variables of this type as well.
2022-02-06 22:02:45 +00:00
Timothy Flynn
281b0411f2 LibJS: Implement conversion of strings to BigInts according to the spec
The spec defines a StringToBigInt AO which allows for converting binary,
octal, decimal, and hexadecimal strings to a BigInt. Our conversion was
only allowing for decimal strings.
2022-01-31 17:50:54 +00:00
Timothy Flynn
236025df19 LibJS: Prevent implicit pointer-to-bool conversion in Value constructor
For example, say you try to create a Value from an Array and forgot to
include LibJS/Runtime/Array.h. This would cause the boolean constructor
to be used instead of a compile error.
2022-01-27 16:27:00 +00:00
Andreas Kling
216e21a1fa AK: Convert AK::Format formatting helpers to returning ErrorOr<void>
This isn't a complete conversion to ErrorOr<void>, but a good chunk.
The end goal here is to propagate buffer allocation failures to the
caller, and allow the use of TRY() with formatting functions.
2021-11-17 00:21:13 +01:00
Andreas Kling
65a7296b8f LibJS: Make Value::to_property_key() return a JS::PropertyKey
Instead of returning JS::StringOrSymbol, which is a space-optimized type
used in Shape property tables, this now returns JS::PropertyKey which is
*not* space-optimized, but has other niceties like optimized storage of
numeric ("indexed") properties.
2021-10-24 17:18:09 +02:00
Andreas Kling
398c181c79 LibJS: Rename PropertyName to PropertyKey
Let's use the same name as the spec. :^)
2021-10-24 17:18:07 +02:00
Idan Horowitz
545d403f6b LibJS: Convert Value operator AOs to ThrowCompletionOr 2021-10-18 23:06:11 +01:00
Idan Horowitz
48ac15758e LibJS: Convert is_loosely_equal() to ThrowCompletionOr 2021-10-18 23:06:11 +01:00
Idan Horowitz
b5e28410c5 LibJS: Convert is_less_than() to ThrowCompletionOr 2021-10-18 23:06:11 +01:00
Idan Horowitz
c15a3b0576 LibJS: Convert Value::get() to ThrowCompletionOr 2021-10-18 23:06:11 +01:00
Linus Groh
be28a6142b LibJS: Convert to_integer_or_infinity() to ThrowCompletionOr 2021-10-18 21:24:30 +01:00
Idan Horowitz
85a28a6555 LibJS: Convert to_index() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
aad12b050b LibJS: Convert to_length() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
750da61c0f LibJS: Convert to_u8_clamp() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
99287afc99 LibJS: Convert to_u8() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
1b7dbb6b3b LibJS: Convert to_i8() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
7bbb92dfe9 LibJS: Convert to_u16() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
627b1205ce LibJS: Convert to_i16() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
cc94bba5c0 LibJS: Convert to_u32() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
f6a5ff7b00 LibJS: Convert to_i32() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
20d990563c LibJS: Convert to_number() to ThrowCompletionOr 2021-10-18 08:01:38 +03:00
Idan Horowitz
c488f5a59d LibJS: Convert to_property_key() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Idan Horowitz
1639ed7e0a LibJS: Convert to_double() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Idan Horowitz
51c33b3b35 LibJS: Convert to_bigint_uint64() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Idan Horowitz
df181809fd LibJS: Convert to_bigint_int64() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Idan Horowitz
e87cea8248 LibJS: Convert to_bigint() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Idan Horowitz
b8f101888b LibJS: Convert to_numeric() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Linus Groh
52976bfac6 LibJS: Convert to_object() to ThrowCompletionOr 2021-10-13 09:55:10 +01:00
Linus Groh
9eb065a1f6 LibJS: Convert to_primitive() to ThrowCompletionOr 2021-10-13 09:55:10 +01:00
Linus Groh
96ab116f0d LibJS: Convert to_primitive_string() to ThrowCompletionOr 2021-10-13 09:55:10 +01:00
Linus Groh
da59c77fe3 LibJS: Convert to_utf16_string() to ThrowCompletionOr 2021-10-13 09:55:10 +01:00
Linus Groh
4d8912a92b LibJS: Convert to_string() to ThrowCompletionOr
Also update get_function_name() to use ThrowCompletionOr, but this is
not a standard AO and should be refactored out of existence eventually.
2021-10-13 09:55:10 +01:00
Linus Groh
44e70d1bc0 LibJS+LibWeb: Let WrapperGenerator deal with legacy_null_to_empty_string
This concept is not present in ECMAScript, and it bothers me every time
I see it.
It's only used by WrapperGenerator, and even there only relevant in two
places, so let's fully remove it from LibJS and use a simple ternary
expression instead:

    cpp_name = js_name.is_null() && legacy_null_to_empty_string
        ? String::empty()
        : js_name.to_string(global_object);
2021-10-11 23:36:03 +01:00
Andreas Kling
e67155638c LibJS: Take advantage of Value::Type::Int32 in a bunch of functions
If a JS::Value has type Int32, we know it's a finite, 32-bit integer.
Use this information to avoid converting it to a double if possible.
2021-10-07 19:27:30 +02:00