Commit graph

169 commits

Author SHA1 Message Date
Linus Groh
5db38d7ba1 LibJS: Replace standalone js_bigint() with BigInt::create()
Three standalone Cell creation functions remain in the JS namespace:

- js_bigint()
- js_string()
- js_symbol()

All of them are leftovers from early iterations when LibJS still took
inspiration from JSC, which itself has jsString(). Nowadays, we pretty
much exclusively use static create() functions to construct types
allocated on the JS heap, and there's no reason to not do the same for
these.
Also change the return type from BigInt* to NonnullGCPtr<BigInt> while
we're here.

This is patch 1/3, replacement of js_string() and js_symbol() follow.
2022-12-07 16:43:06 +00:00
Linus Groh
57dc179b1f Everywhere: Rename to_{string => deprecated_string}() where applicable
This will make it easier to support both string types at the same time
while we convert code, and tracking down remaining uses.

One big exception is Value::to_string() in LibJS, where the name is
dictated by the ToString AO.
2022-12-06 08:54:33 +01:00
Linus Groh
6e19ab2bbc AK+Everywhere: Rename String to DeprecatedString
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
2022-12-06 08:54:33 +01:00
Timothy Flynn
9620a092de LibJS: Publicly expose double_to_string and rename it number_to_string
Rename it to match the name used by the spec.

Add an override mode to skip formatting numbers with an exponential sign
(e.g. 1e23). This mode is needed by Number and Intl.NumberFormat, who
don't call out a specific number-to-string method to use (they just say
to make "the String consisting of the digits of n").
2022-11-04 21:12:10 +00:00
Dan Klishch
56aa21a7dc LibJS: Implement precise double_to_string 2022-11-03 20:17:09 -06:00
Moustafa Raafat
54b8a2b094 LibCrypto: Add a way to compare UnsignedBigInteger with double
This patch also make SignedBigInteger::compare_to_double make use
of the new function.
2022-11-02 22:04:34 -06:00
davidot
783b1a479d LibJS: Make string_to_double use the new double parser 2022-10-23 15:48:45 +02:00
Timothy Flynn
e952dca026 LibJS: Expose the StringToNumber AO for public use
This will be needed outside of Value.cpp.
2022-10-15 18:05:02 +02: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
Linus Groh
15e3a99250 LibJS: Trim non-ASCII whitespace as well in StringToBigInt
This was never caught since the original implementation AFAICT, and
isn't being covered by test262 either:
https://github.com/tc39/test262/issues/1354
2022-08-30 10:30:43 +01:00
Linus Groh
c88c33dc22 LibJS: Trim non-ASCII whitespace as well in StringToNumber
This regressed in f4b3bb5.
2022-08-30 10:20:45 +01:00
Slappy826
f4b3bb519f LibJS: Handle non-decimal integer literals in Value::to_number
Implements support for parsing binary and octal literals, and fixes
instances where a hex literal is parsed in ways the spec doesn't
allow.
2022-08-30 01:00:48 +01:00
Linus Groh
50428ea8d2 LibJS: Move intrinsics to the realm
Intrinsics, i.e. mostly constructor and prototype objects, but also
things like empty and new object shape now live on a new heap-allocated
JS::Intrinsics object, thus completing the long journey of taking all
the magic away from the global object.
This represents the Realm's [[Intrinsics]] slot in the spec and matches
its existing [[GlobalObject]] / [[GlobalEnv]] slots in terms of
architecture.

In the majority of cases it should now be possibly to fully allocate a
regular object without the global object existing, and in fact that's
what we do now - the realm is allocated before the global object, and
the intrinsics between both :^)
2022-08-27 11:29:10 +01:00
davidot
e663504df1 LibJS: Fix that leftshift for BigInts did not round down
For negative number this previously rounded towards zero instead of the
intended always rounding down.
2022-08-24 23:27:17 +01:00
davidot
cb49c07fb7 LibJS: Use the new BigInt compare_to_double algorithm :^)
Although this is much more complicated it does not seem to impact
performance that much even when looking only at values in which the
previous casting to i32 was correct.
2022-08-24 23:27:17 +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
25849f8a6d LibJS: Replace GlobalObject with VM in common AOs [Part 18/19] 2022-08-23 13:58:30 +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
Linus Groh
f3117d46dc LibJS: Remove GlobalObject from VM::throw_completion()
This is a continuation of the previous five commits.

A first big step into the direction of no longer having to pass a realm
(or currently, a global object) trough layers upon layers of AOs!
Unlike the create() APIs we can safely assume that this is only ever
called when a running execution context and therefore current realm
exists. If not, you can always manually allocate the Error and put it in
a Completion :^)

In the spec, throw exceptions implicitly use the current realm's
intrinsics as well: https://tc39.es/ecma262/#sec-throw-an-exception
2022-08-23 13:58:30 +01:00
Linus Groh
b99cc7d050 LibJS+LibWeb: Replace GlobalObject with Realm in create() functions
This is a continuation of the previous two commits.

As allocating a JS cell already primarily involves a realm instead of a
global object, and we'll need to pass one to the allocate() function
itself eventually (it's bridged via the global object right now), the
create() functions need to receive a realm as well.
The plan is for this to be the highest-level function that actually
receives a realm and passes it around, AOs on an even higher level will
use the "current realm" concept via VM::current_realm() as that's what
the spec assumes; passing around realms (or global objects, for that
matter) on higher AO levels is pointless and unlike for allocating
individual objects, which may happen outside of regular JS execution, we
don't need control over the specific realm that is being used there.
2022-08-23 13:58:30 +01:00
davidot
0f9434a02c LibJS: Make StringToNumber case sensitive when falling back to strtod
We use strtod to convert a string to number after checking whether the
string is [+-]Infinity, however strtod also checks for either 'inf' or
'infinity' in a case-insensitive.
There are still valid cases for strtod to return infinity like 10e100000
so we just check if the "number" contains 'i' or 'I' in which case
the strtod infinity is not valid.
2022-08-17 23:56:24 +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
Andreas Kling
64b29eb459 LibJS: Implement string concatenation using ropes
Instead of concatenating string data every time you add two strings
together in JavaScript, we now create a new PrimitiveString that points
to the two concatenated strings instead.

This turns concatenated strings into a tree structure that doesn't have
to be serialized until someone wants the characters in the string.

This *dramatically* reduces the peak memory footprint when running
the SunSpider benchmark (from ~6G to ~1G on my machine). It's also
significantly faster (1.39x) :^)
2022-08-06 00:29:15 +02:00
Andreas Kling
f4c68eb0a4 LibJS: Add PrimitiveString::is_empty() and use it
If we're only interested in whether the string is empty, we can skip the
conversion from UTF-16 to UTF-8.
2022-07-19 12:45:50 +02:00
sin-ack
3f3f45580a Everywhere: Add sv suffix to strings relying on StringView(char const*)
Each of these strings would previously rely on StringView's char const*
constructor overload, which would call __builtin_strlen on the string.
Since we now have operator ""sv, we can replace these with much simpler
versions. This opens the door to being able to remove
StringView(char const*).

No functional changes.
2022-07-12 23:11:35 +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
Linus Groh
257375f54c LibJS: Update comments for Annex B changes to IsLooselyEqual
This is an editorial change in the ECMA-262 spec.

See: https://github.com/tc39/ecma262/commit/da3d674
2022-05-03 22:49:31 +02:00
Linus Groh
9f3f3b0864 LibJS: Remove implicit wrapping/unwrapping of completion records
This is an editorial change in the ECMA-262 spec, with similar changes
in some proposals.

See:
- https://github.com/tc39/ecma262/commit/7575f74
- https://github.com/tc39/proposal-array-grouping/commit/df899eb
- https://github.com/tc39/proposal-shadowrealm/commit/9eb5a12
- https://github.com/tc39/proposal-shadowrealm/commit/c81f527
2022-05-03 01:09:29 +02:00
Idan Horowitz
0399239e3f LibJS: Do not negate zero into negative zero in ToIntegerOrInfinity
When the input value was in the range of [-1, 0] we would incorrectly
negate the resulting integer, resulting in -0 instead of the expected 0
2022-04-30 21:35:16 +02:00
Linus Groh
5b48912d35 LibJS: Remove a bunch of gratuitous JS namespace qualifiers 2022-04-03 15:19:33 +01:00
Idan Horowitz
086969277e Everywhere: Run clang-format 2022-04-01 21:24:45 +01:00
Idan Horowitz
60bc5e3b5b LibJS: Trim all types of whitespace characters before parsing numbers 2022-02-19 22:16:30 +00:00
Anonymous
c45922c637 LibJS: Unify exponentiation logic for ** operator and Math.pow
The JS behaviour of exponentiation on two number typed values is
not a simple matter of forwarding to ::pow(double, double). So,
this factors out the Math.pow logic to allow it to be shared with
Value::exp.
2022-02-18 22:31:36 +00:00
Anonymous
1e0facb7ee LibJS: Implement the Number::remainder AO using fmod
The ECMA verbiage for modulus is the mathematical definition implemented
by fmod, so let's just use that rather than trying to reimplement all
the edge cases.
2022-02-16 11:18:41 +00: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
02b7bf34c9 LibJS: Implement BigInt IsLessThan according to the spec 2022-01-31 17:50:54 +00:00
Timothy Flynn
9ad3debf35 LibJS: Implement BigInt loose-equality according to the spec 2022-01-31 17:50:54 +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
mjz19910
1ef633472b Everywhere: Convert VM::call() to JS::call() 2022-01-23 15:24:45 +00:00
Nico Weber
945d962322 LibJS+LibCrypto: Fix SignedBitInteger::bitwise_not and use it in LibJS
Bitwise operators are defined on two's complement, but SignedBitInteger
uses sign-magnitude. Correctly convert between the two.

Let LibJS delegate to SignedBitInteger for bitwise_not, like it does
for all other bitwise_ operations on bigints.

No behavior change (LibJS is now the only client of
SignedBitInteger::bitwise_not()).
2022-01-18 20:04:06 +03:30
Timothy Flynn
444b2d9ec2 LibJS: Implement UTF-16 surrogate pair concatenation without iteration
Performance of string concatenation regressed in a57e2f9. That commit
iterates over the LHS string to find the last code unit, to check if it
is a high surrogate. Instead, first look at the 3rd-to-last byte in the
UTF-8 encoded string to check if it is a 3-byte code point; then decode
just those bytes to check if we have a high surrogate. Similarly, check
the first 3 bytes of the RHS string to check if we have a low surrogate.
2022-01-18 09:46:55 +00:00
Timothy Flynn
a57e2f9a76 LibJS: Combine UTF-16 surrogate pairs when concatenating strings
In the following use case:

    "\ud834" + "\udf06"

We were previously combining these as two individual code points. When
concatenating strings, we must take care to combine the high surrogate
from the left-hand side with the low surrogate from the right-hand side.
2022-01-18 00:49:16 +00:00
Timothy Flynn
d69f5ca128 LibJS: Update spec numbers for Operations on Objects AOs
The error cause proposal was merged, so some spec numbers were bumped.
2021-12-21 14:56:28 +01:00
Linus Groh
905b8bd545 LibJS: Make section URLs more consistent
- Drop index.html
- Include trailing slash before anchor
- Don't use multipage spec URLs
2021-11-24 18:37:57 +00:00
Andreas Kling
72cd31d033 LibJS: Tweak Value::to_property_key() fast path for Int32
Move the check for Int32 *before* we call to_primitive().
2021-10-25 15:37:28 +02:00
Andreas Kling
b63d17e2f8 LibJS: Add fast paths for <, >, <=, and >= with Int32 on both sides
This gives us a ~5% speed-up on Kraken's ai-astar.js
2021-10-25 14:35:23 +02:00
Andreas Kling
b138b4c83f LibJS: Optimize Value::to_property_key() for numeric property names
If the Value is a non-negative Int32, create a numeric PropertyKey
instead of making a string key.

This makes "ai-astar" test from the Kraken benchmark run in 30 seconds,
down from 42 seconds. :^)
2021-10-24 17:18:09 +02: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