The only subclass was already GC-allocated, so let's hoist the JS::Cell
inheritance up one level. This ends up simplifying a bit of rather
dubious looking code where we were previously slicing ESOs.
Changes the signature of queue_global_task() from AK:Function to
JS::HeapFunction to be more clear to the user of the function that this
is what it uses internally.
...and use HeapFunction instead of SafeFunction for task steps.
Since there is only one EventLoop per process, it lives as a global
handle in the VM custom data.
This makes it much easier to reason about lifetimes of tasks, task
steps, and random stuff captured by them.
This URL library ends up being a relatively fundamental base library of
the system, as LibCore depends on LibURL.
This change has two main benefits:
* Moving AK back more towards being an agnostic library that can
be used between the kernel and userspace. URL has never really fit
that description - and is not used in the kernel.
* URL _should_ depend on LibUnicode, as it needs punnycode support.
However, it's not really possible to do this inside of AK as it can't
depend on any external library. This change brings us a little closer
to being able to do that, but unfortunately we aren't there quite
yet, as the code generators depend on LibCore.
This will be used to transfer information about the parent context to
DedicatedWorkers and future out-of-process Worker/Worklet
implementations for fetching purposes. In order to properly check
same-origin and other policies, we need to know more about the outside
settings than we were previously passing to the WebWorker process.
We only need to know that the Global Object of the environment is an
event target in order to dispatch an event on it. This resolves a FIXME
where we assumed that the only type of Global in LibWeb is HTML::Window.
This commit un-deprecates DeprecatedString, and repurposes it as a byte
string.
As the null state has already been removed, there are no other
particularly hairy blockers in repurposing this type as a byte string
(what it _really_ is).
This commit is auto-generated:
$ xs=$(ack -l \bDeprecatedString\b\|deprecated_string AK Userland \
Meta Ports Ladybird Tests Kernel)
$ perl -pie 's/\bDeprecatedString\b/ByteString/g;
s/deprecated_string/byte_string/g' $xs
$ clang-format --style=file -i \
$(git diff --name-only | grep \.cpp\|\.h)
$ gn format $(git ls-files '*.gn' '*.gni')
Stop worrying about tiny OOMs. Work towards #20449.
While going through these, I also changed the function signature in many
places where returning ThrowCompletionOr<T> is no longer necessary.
This is fixed by making the "about to be notified rejected promises
list" use JS::Handle instead of JS::NonnullGCPtr. This UAF happens
because notify_about_rejected_promises makes a local copy of this list,
empties the member variable list and then moves the local copy into a
JS::SafeFunction lambda. JS::SafeFunction can only see GC pointers that
are in its storage, not external storage.
Example exploit (requires fixed microtask timing by removing the dummy
execution context):
```html
<script>
Promise.reject(new Error);
// Exit the script block, causing a microtask checkpoint and thus
// queuing of a task to fire the unhandled rejection event for the
// above promise.
// During the time after being queued but before being ran, these
// promises are not kept alive. This is because JS::SafeFunction cannot
// see into a Vector, meaning it can't visit the stored NonnullGCPtrs.
</script>
<script defer>
// Cause a garbage collection, destroying the above promise.
const b = [];
for (var i = 0; i < 200000; i++)
b.push({});
// Some time after this script block, the queued unhandled rejection
// event task will fire, with the event object containing the dead
// promise.
window.onunhandledrejection = (event) => {
let value = event.promise;
console.log(value);
}
</script>
```
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 :^)
We can't be nuking the ESO while its owned execution context is still on
the VM's execution context stack, as that may lead to a use-after-free.
This patch solves this by adding a `context_owner` field to each context
and treating it as a GC root.
These lambdas were marked mutable as they captured a Ptr wrapper
class by value, which then only returned const-qualified references
to the value they point from the previous const pointer operators.
Nothing is actually mutating in the lambdas state here, and now
that the Ptr operators don't add extra const qualifiers these
can be removed.
(And BrowsingContextGroup had to come along for the ride as well.)
This solves a number of nasty reference cycles between browsing
contexts, history items, and their documents.
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 the ModuleMap class used to keep track of the type and
url of a module as well as the fetching state associated. Each
environment settings object now also has a module map.
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 :^).
Workers don't have a document, so we can't ask them if scripting is
enabled or not. This is not the right long-term fix, but it fixes an
assertion when trying to query the missing responsible document of a
web worker.
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.
This removes the requirement of having a global object that actually
inherits from JS::GlobalObject, which is now a perfectly valid scenario.
With the upcoming removal of wrapper objects in LibWeb, the HTML::Window
object will inherit from DOM::EventTarget, which means it cannot also
inherit from JS::GlobalObject.
- Prefer VM::current_realm() over GlobalObject::associated_realm()
- Prefer VM::heap() over GlobalObject::heap()
- Prefer Cell::vm() over Cell::global_object()
- Prefer Wrapper::vm() over Wrapper::global_object()
- Inline Realm::global_object() calls used to access intrinsics as they
will later perform a direct lookup without going through the global
object
This patch implements the "create a new browsing context" function from
the HTML spec and replaces our existing logic with it.
The big difference is that browsing contexts now initially navigate to
"about:blank" instead of starting out in a strange "empty" state.
This makes it possible for websites to create a new iframe and start
scripting inside it right away, without having to load an URL into it.
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.
This is now the source of truth for 'user enabled/disabled scripting',
but it has to ask the window's page, which actually stores the setting.
Also use this new functionality in two places where it was previously
marked as a FIXME.
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.