This is a weak pointer that integrates with the garbage collector.
It has a number of differences compared to AK::WeakPtr, including:
- The "control block" is allocated from a well-packed WeakBlock owned by
the GC heap, not just a generic malloc allocation.
- Pointers to dead cells are nulled out by the garbage collector
immediately before running destructors.
- It works on any GC::Cell derived type, meaning you don't have to
inherit from AK::Weakable for the ability to be weakly referenced.
- The Weak always points to a control block, even when "null" (it then
points to a null WeakImpl), which means one less null check when
chasing pointers.
When T in HashTable<T> has a potentially slow equality check, it can be
very profitable to check for a matching hash before full equality.
This patch adds may_have_slow_equality_check() to AK::Traits and
defaults it to true. For trivial types (pointers, integers, etc) we
default it to false. This means we skip the hash check when the equality
check would be a single-CPU-word compare anyway.
This synergizes really well with things like HashMap<String, V> where
collisions previously meant we may have to churn through multiple O(n)
equality checks.
Not having this led to a sneaky bug where, given a Variant like so:
Variant<double, GC::Root<T>>
An incorrectly-written visit() branch for the Root would just cause it
to be cast to a double and call that branch instead.
With the cast made explicit, we get a compiler error, which is far more
useful.
Co-authored-by: Jelle Raaijmakers <jelle@ladybird.org>
`ConservativeVector`, `RootVector` and `RootHashMap` are final types,
and their base classes have a protected destructor, so when their
destructor is called, the static and dynamic types will be the same
(can't destruct them through a pointer to a base or derived class).
Therefore, there is no need for a virtual destructor.
This fixes the newly introduced `-Wunnecessary-virtual-specifier`
Clang warning (llvm/llvm-project#131188).
This is a GC-aware wrapper around AK::HashMap. Entry values are treated
as GC roots, much like the GC::RootVector we already had.
We also provide GC::OrderedRootHashMap as a convenience.
Add the proper annotations for the Cell and Cell::Visitor classes to be
visible in Swift. This lets us remove some OpaquePointer shinangians in
the Swift bindings.
This patch adds a workaround for a Swift issue where boolean bitfields
with getters and setters in SWIFT_UNSAFE_REFERENCE types are improperly
imported, causing an ICE.
Previously, all `GC::Cell` derived classes were Weakable. Marking only
those classes that require this functionality as Weakable allows us to
reduce the memory footprint of some frequently used classes.
Previously, we would only keep the cell that must survive alive, but
none of it's edges.
This cropped up with a GC UAF in must_survive_garbage_collection of
WebSocket in .NET's SignalR frontend implementation, where an
out-of-scope WebSocket had it's underlying EventTarget properties
garbage collected, and must_survive_garbage_collection read from the
destroyed EventTarget properties.
See: https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/clients/ts/signalr/src/WebSocketTransport.ts#L81
Found on https://www.formula1.com/ during a live session.
Co-Authored-By: Tim Flynn <trflynn89@pm.me>
Before this change, it was possible for a second GC to get triggered
in the middle of a first GC, due to allocations happening in the
FinalizationRegistry cleanup host hook. To avoid this causing problems,
we add a "post-GC task" mechanism and use that to invoke the host hook
once all other GC activity is finished, and we've unset the "collecting
garbage" flag.
Note that the test included here only fails reliably when running with
the -g flag (collect garbage after each allocation).
Fixes#3051
Whenever we create a GC function, it should always be so that we can
pass it to a platform event loop spin, HTML event loop spin, or some
queued task on the HTML event loop. For every use case, any local
variables will be out of scope by the time the function executes.
Lazily coercing might have made sense in the past, but since hashing
and comparing requires the `PropertyKey` to be coerced, and since a
`PropertyKey` will be used to index into a hashmap 99% of the time,
which will hash the `PropertyKey` and use it in comparisons, the
extra complexity and branching produced by lazily coercing has
become more trouble than it is worth.
Remove the lazy coercions, which then also neatly allows us to
switch to a `Variant`-based implementation.
This includes a protocol for creating LibGC Heap allocated Swift
objects. Pay no attention to the Unmanaged shenanigans, they are
all behind the curtain.
This will allow us to use the GC to manage the lifetime of objects
that are not C++ objects, such as Swift objects. In the future we
could expand this cursed FFI to other languages as well.
While we don't want arbitrary callers deferring GC, we do want
deferral to be available to the Swift. In order for Swift to
understand the RAII nature of DeferGC, we need to mark it as
non-copyable.
Resulting in a massive rename across almost everywhere! Alongside the
namespace change, we now have the following names:
* JS::NonnullGCPtr -> GC::Ref
* JS::GCPtr -> GC::Ptr
* JS::HeapFunction -> GC::Function
* JS::CellImpl -> GC::Cell
* JS::Handle -> GC::Root