This patch implements all changes to the specification touching the
subset of module script fetching we support.
Notably it adds parts of the specification for supporting import maps.
With this we are also able to get rid of a non standard workaround for a
spec issue we discovered while initially implementing module scripts :^)
This fixes an issue where GC would kill the internal realm if it ran at
the wrong time during startup. Found by aggressively GC'ing between
every allocation.
Due to the way we lazily construct prototypes and constructors for web
platform interfaces, it's possible for nested GC allocation to occur
while GC objects have been allocated but not fully constructed.
If the garbage collector ends up running in this state, it may attempt
to call JS::Cell::visit_edges() on an object whose vtable pointer hasn't
been set up yet.
This patch works around the issue by deferring GC while intrinsics are
being brought up. Furthermore, we also create a dummy global object for
the internal realm, and populate it with intrinsics. This works around
the same issue happening when allocating something (like the default UA
stylesheets) in the internal realm.
These solutions are pretty hacky and sad, so I've left FIXMEs about
finding a nicer way.
Print exceptions passed to `HTML::report_exception` in the JS console
Refactored `ExceptionReporter`: in order to report exception now
you need to pass the relevant realm in it. For passed `JS::Value`
we now create `JS::Error` object to print value as the error message.
This patch adds support for the HostGetSupportedImportAssertions and
HostResolveImportedModule host hooks.
Co-authored-by: davidot <davidot@serenityos.org>
...and clean up afterwards, of course. Additionally to preparing to run
a script, we also prepare to run a callback here. This matches WebIDL's
invoke_callback() / call_user_object_operation() functions, and prevents
a crash in host_make_job_callback() when getting the incumbent settings
object.
Running the following JS no longer crashes after this change:
```js
new Promise((resolve) => {
setTimeout(resolve, 0);
}).then(() => {
return Promise.reject();
});
```
See further discussion/investigation here:
995019647210268246241026922985
Many thanks to Luke for doing the hard work here, tracking this down,
and suggesting the fix!
Co-authored-by: Luke Wilde <lukew@serenityos.org>
Now that no one needs a Window just to create prototypes, we can remove
the internal window Object from the main thread VM and get rid of the
HTML::Window include for it.
This finally solves the reference binding to nullptr error in ladybird
that shows up when compiling it with ASAN.
This Intrinsics object hangs off of a new HostDefined struct that takes
the place of EnvironmentSettingsObject as the true [[HostDefined]] slot
on JS::Realm objects created by LibWeb.
This gets the intrinsics off of the GlobalObject, Window, similar to the
previous refactor of LibJS to move the intrinsics into the Realm's
[[Intrinics]] internal slot.
A side effect of this change is that we cannot fully initialize a Window
object until the [[HostDefined]] slot has been installed into the realm,
which happens with the creation of the WindowEnvironmentSettingsObject.
As such, any Window usage that has not been funned through a WindowESO
will not have any cached Web prototyped or constructors, and will not
have Window APIs available to javascript code. Currently this seems
limited to usage of Window in the CSS parser, but a subsequent commit
will clean those up to take Realm as well. However, this commit compiles
so let's cut it off here :^).
Instead of calling Core::EventLoop directly, LibJS now has a virtual
function on VM::CustomData for customizing this behavior.
We use this in LibWeb to plumb the spin request through to the
PlatformEventPlugin.
This is a monster patch that turns all EventTargets into GC-allocated
PlatformObjects. Their C++ wrapper classes are removed, and the LibJS
garbage collector is now responsible for their lifetimes.
There's a fair amount of hacks and band-aids in this patch, and we'll
have a lot of cleanup to do after this.
Also added a local test for ensuring this behavior since it is unique to
browsers. Since we don't actually use WindowProxy anywhere yet we just
test on location for now.
Similar to create() in LibJS, wrap() et al. are on a low enough level to
warrant passing a Realm directly instead of relying on the current realm
from the VM, as a wrapper may need to be allocated while no JS is being
executed.
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
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.
The way we've been creating DOM::Document has been pretty far from what
the spec tells us to do, and this is a first big step towards getting us
closer to spec.
The new Document::create_and_initialize() is called by FrameLoader after
loading a "text/html" resource.
We create the JS Realm and the Window object when creating the Document
(previously, we'd do it on first access to Document::interpreter().)
The realm execution context is owned by the Environment Settings Object.
A lot of code assumes that there's a current execution context. By
setting up a dummy context right after creating the main thread VM,
we ensure that such code can always run.
It makes no sense to require passing a global object and doing a stack
space check in some cases where running out of stack is highly unlikely,
we can't recover from errors, and currently ignore the result anyway.
This is most commonly in constructors and when setting things up, rather
than regular function calls.
This overrides the JS host hooks to follow the spec for queuing
promises, making/calling job callbacks, unhandled promise rejection
handling and FinalizationRegistry queuing.
This also allows us to drop the on_call_stack_emptied hook in
Document::interpreter().
This patch attaches a HTML::EventLoop to the main thread JS::VM used
for JavaScript bindings in the web engine.
The goal here is to model the various task scheduling mechanisms of the
HTML specification.
LibWeb is now responsible for logging unhandled exceptions itself,
which means set_should_log_exceptions() is no longer used and can be
removed. It turned out to be not the best option for web page exception
logging, as we would have no indication regarding whether the exception
was later handled of not.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.
See: https://spdx.dev/resources/use/#identifiers
This was done with the `ambr` search and replace tool.
ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *