Previously, in LibGFX's `Point` class, calculated distances were passed
to the integer `abs` function, even if the stored type was a float. This
caused the value to unexpectedly be truncated. Luckily, this API was not
used with floating point types, but that can change in the future, so
why not fix it now :^)
Since we are in C++, we can use function overloading to make things
easy, and to automatically use the right version.
This is even better than the LibC/LibM functions, as using a bit of
hackery, they are able to be constant-evaluated. They use compiler
intrinsics, so they do not depend on external code and the compiler can
emit the most optimized code by default.
Since we aren't using the C++ standard library's trick of importing
everything into the `AK` namespace, this `abs` function cannot be
exported to the global namespace, as the names would clash.
This is supposed to be its own AO, but since it was only used in one
place, we inlined it. Now that it's also being used in the Temporal
proposal (Date.prototype.toTemporalInstant() specifically), it makes
sense to have it as a standalone function.
A small difference is that we now construct the SignedBigInteger without
casting to i32 but instead take the (known to be integral) double and
cast it to i64. Not perfect, but slightly better.
Also clean up the BigInt constructor a bit while we're here and sprinkle
some spec comments.
Several test262 tests rely on creating phony RegExp objects that do not
have the internal slots used to test for a valid RegExp object. To allow
these tests to run (and because the spec doesn't require real RegExp
objects in these methods), do not attempt to downcast where it isn't
needed.
This was previously used as a wrapper for Regex::match when that method
was invoked by multiple RegExp.prototype implementations. But now all
implementations go through the RegExpExec abstraction, so this helper
is not needed. Remove it to discourage its usage.
Also update a comment about using dynamic properties for lastIndex; this
is no longer a FIXME.
The RegExp specification dictates that the internal implementation of
RegExp.prototype.exec must go through the RegExpBuiltinExec abstraction.
Note there is currently no functional difference in this commit. However
this now allows other RegExp.prototype methods to use RegExpExec rather
than calling RegExp.prototype.exec. Then, if JavaScript in the wild has
overwritten exec, RegExpExec has some protections to defer to
RegExpBuiltinExec.
These were an ad-hoc way to implement special behaviour when reading or
writing to specific object properties. Because these were effectively
replaced by the abillity to override the internal methods of Object,
they are no longer needed.
This is not a functional change, the exposed (incorrect) behaviour is
the same as it was before, this simply removes the last user of
NativeProperties, allowing us to remove them completely from LibJS.
This is often needed in ArrayPrototype when getting items with indices
above 2**32-1 is possible since length is at most 2**53-1.
This also fixes a number of these cases in ArrayPrototype where the type
was not big enough to hold the potential values.
Unfortunately this fast path leads to problems if Array.prototype is
changed. We probably need to find out some way to optimize these methods
by detecting changes to the prototype or other mechanisms.
Just like the initial Temporal.TimeZone commit, this patch adds the
Instant object itself, its constructor and prototype (currently empty),
and two required abstract operations.
Here we got our first Temporal object :^)
This patch adds the TimeZone object itself, its constructor and
prototype (currently empty), and a bunch of required abstract operations
Add a JS_ENUMERATE_TEMPORAL_OBJECTS macro and use it to generate:
- Forward declarations
- CommonPropertyNames class name members
- Constructor and prototype GlobalObject members, getters, visitors,
and initialize_constructor() calls
This will be home to various functions:
- Temporal.now.timeZone()
- Temporal.now.instant()
- Temporal.now.plainDateTime()
- Temporal.now.plainDateTimeISO()
- Temporal.now.zonedDateTime()
- Temporal.now.zonedDateTimeISO()
- Temporal.now.plainDate()
- Temporal.now.plainDateISO()
- Temporal.now.plainTimeISO()
Currently empty, but we gotta start somewhere! This is the start of
implementing the Temporal proposal (currently stage 3).
I have decided to start a new subdirectory (Runtime/Temporal/) as well
as a new C++ namespace (JS::Temporal) for this so we don't have to
prefix all the files and classes with "Temporal" - there will be a lot.
https://tc39.es/proposal-temporal/
This only causes 1 new test262 test to pass. Other tests that rely on
this coercion fail due to receiving an unexpected value for 'this' when
invoking a functional replacement. For example:
String/prototype/replaceAll/replaceValue-call-matching-empty.js
Receives 'undefined' for 'this' in the functional replacement invocation
but is expected to receive the global 'this'.
The String.prototype.replace spec requires evaluating the replacement
value (if it is not a function) before searching the source string.
Fixes 4 test262 tests.
10.4.2 Array Exotic Objects
https://tc39.es/ecma262/#sec-array-exotic-objects
A String property name P is an array index if and only if
ToString(ToUint32(P)) equals P and ToUint32(P) is not the same value
as 𝔽(2^32 - 1).
Per the spec, before invoking the GetSubstitution abstraction, the named
capture groups (if not undefined) should be coerced to an object via the
ToObject abstraction.
The implementation of String.prototype.replaceAll cannot use AK's
implementation of String::find_all when finding the indices of the
search string in the source string. String::find_all will return indices
[0, 1] for String("aaa").find_all("aa") - i.e. it returns overlapping
results. This is not allowed by the JavaScript specification for
replaceAll.
It's way too easy to get this wrong: for the IsArray abstract operation,
Value::is_array() needs to be called. Since we have RTTI, the virtual
Object::is_array() method is not needed anymore - if we need to know
whether something is *actually* a JS::Array (we currently check in more
cases than we should, I think) and not a Proxy with an Array target, we
should do that in a way that doesn't look like an abstract operation.
This removes all usages of the non-standard put helper method and
replaces all of it's usages with the specification required alternative
or with define_direct_property where appropriate.
These are usually incorrect, and people sometimes forget to add the
correct values as a result of them being optional, so they should just
be specified explicitly.
This removes all usages of the non-standard define_property helper
method and replaces all it's usages with the specification required
alternative or with define_direct_property where appropriate.