No functional changes - we can still very easily get to the global
object via `Realm::global_object()`. This is in preparation of moving
the intrinsics to the realm and no longer having to pass a global
object when allocating any object.
In a few (now, and many more in subsequent commits) places we get a
realm using `GlobalObject::associated_realm()`, this is intended to be
temporary. For example, create() functions will later receive the same
treatment and are passed a realm instead of a global object.
The existing code looks innocently correct, implementing the following
step:
3. If IsCallable(func) is false, set func to the intrinsic function
%Object.prototype.toString%.
as
return ObjectPrototype::to_string(vm, global_object);
However, this misses the fact that the next step calls the function with
the previously ToObject()'d this value (`array`):
4. Return ? Call(func, array).
This doesn't happen in the current implementation, which will use the
unaltered this value from the Array.prototype.toString() call, and make
another, unequal object in %Object.prototype.toString%. Since both that
and Array.prototype.toString() do a Get() call on said object, this
behavior is observable (see newly added test).
Fix this by actually doing what the spec says and calling the fallback
function the regular way.
We were previously manually initializing them instead of just calling
GlobalObject::initialize_constructor, which aside from duplicating code
also meant we didn't set the required name property.
The spec says:
27.5.1.1 Generator.prototype.constructor
https://tc39.es/ecma262/#sec-generator.prototype.constructor
The initial value of Generator.prototype.constructor is
%GeneratorFunction.prototype%.
But we had it set to %GeneratorFunction% (the GeneratorFunction
constructor).
Given we usually call objects Foo{Object,Constructor,Prototype} or
Foo{,Constructor,Prototype}, this name was an odd choice.
The new one matches the spec better, which calls it the "Generator
Prototype Object", so we simply omit the Object suffix as usual as it's
implied.
In order to reduce our reliance on __builtin_{ffs, clz, ctz, popcount},
this commit removes all calls to these functions and replaces them with
the equivalent functions in AK/BuiltinWrappers.h.
This adds plumbing for the Intl.DateTimeFormat object, constructor, and
prototype.
Note that unlike other Intl objects, the Intl.DateTimeFormat object has
a LibUnicode structure as a base. This is to prevent wild amounts of
code duplication between LibUnicode, Intl.DateTimeFormat, and other
not-yet-defined Intl structures, because there's 12 fields shared
between them.
This commit adds support for the most bare bones version of async
functions, support for async generator functions, async arrow functions
and await expressions are TODO.
The old versions were renamed to JS_DECLARE_OLD_NATIVE_FUNCTION and
JS_DEFINE_OLD_NATIVE_FUNCTION, and will be eventually removed once all
native functions were converted to the new format.
This is just another workaround, but it should be much more reliable
than Interpreter::realm(), especially when allocating NativeFunctions
and ECMAScriptFunctionObjects: we're guaranteed to have a GlobalObject
at that point, and it likely was set as the GlobalObject of a Realm and
can lead us back to it. We're however not guaranteed that the VM can
give us an Interpreter, which is why functions in LibWeb can be a bit
crashy at the moment.
We use a WeakPtr<Realm> to properly handle the unlikely case where the
Realm goes away after associating a GlobalObject to it.
We'll always need _something_ of this sort if we want to support
OrdinaryFunctionCreate and CreateBuiltinFunction without the explicit
realm argument while no JS is running, because they want to use the
current Realm Record (always in the first and as fallback in the second
case).
The way that transition avoidance (foo_without_transition) was
implemented led to shapes being unshareable and caused shape explosion
instead, precisely what we were trying to avoid.
This patch removes all the attempts to avoid transitioning shapes, and
instead *adds* transitions when changing an object's prototype.
This makes transitions flow naturally, and as a result we end up with
way fewer shape objects in real-world situations.
When we run out of big problems, we can get back to avoiding transitions
as an optimization, but for now, let's avoid ballooning our processes
with a unique shape for every object.