tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 47845a79208786f8de20475ebe424d5a0128e5e1
parent c70a763817dac5749308e67f5f57057f32021595
Author: Steve Fink <sfink@mozilla.com>
Date:   Tue, 14 Oct 2025 04:16:37 +0000

Bug 1935829 - Use tagged ptrs for EphemeronEdge r=jonco

Differential Revision: https://phabricator.services.mozilla.com/D266262

Diffstat:
Mjs/src/gc/GCMarker.h | 38++++++++++++++++++++++++++++----------
Mjs/src/gc/Marking.cpp | 6+++---
Mjs/src/gc/Zone.cpp | 5++++-
3 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/js/src/gc/GCMarker.h b/js/src/gc/GCMarker.h @@ -53,16 +53,34 @@ class MarkStackIter; class ParallelMarkTask; class UnmarkGrayTracer; -// Ephemeron edges have two source nodes and one target, and mark the target -// with the minimum (least-marked) color of the sources. Currently, one of -// those sources will always be a WeakMapBase, so this will refer to its color -// at the time the edge is traced through. The other source's color will be -// given by the current mark color of the GCMarker. -struct EphemeronEdge { - MarkColor color; - Cell* target; - - EphemeronEdge(MarkColor color_, Cell* cell) : color(color_), target(cell) {} +// Ephemerons are edges from a source to a target that are only materialized +// into a table when the owner is marked. (The owner is something like a +// WeakMap, which contains a set of ephemerons each going from a WeakMap key to +// its value.) When marking a ephemeron, only the color of the owner is needed: +// the target is marked with the minimum (least-marked) color of the owner and +// source. So an EphemeronEdge need store only the owner color and the target +// pointer, which can fit into a tagged pointer since targets are aligned Cells. +// +// Note: if the owner's color changes, new EphemeronEdges will be created for +// it. +class EphemeronEdge { + static constexpr uintptr_t ColorMask = 0x3; + static_assert(uintptr_t(MarkColor::Gray) <= ColorMask); + static_assert(uintptr_t(MarkColor::Black) <= ColorMask); + static_assert(ColorMask < CellAlignBytes); + + uintptr_t taggedTarget; + + public: + EphemeronEdge(MarkColor color, Cell* cell) + : taggedTarget(uintptr_t(cell) | uintptr_t(color)) { + MOZ_ASSERT((uintptr_t(cell) & ColorMask) == 0); + } + + MarkColor color() const { return MarkColor(taggedTarget & ColorMask); } + Cell* target() const { + return reinterpret_cast<Cell*>(taggedTarget & ~ColorMask); + } }; using EphemeronEdgeVector = Vector<EphemeronEdge, 2, js::SystemAllocPolicy>; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp @@ -742,10 +742,10 @@ void GCMarker::markEphemeronEdges(EphemeronEdgeVector& edges, DebugOnly<size_t> initialLength = edges.length(); for (auto& edge : edges) { - MarkColor targetColor = std::min(srcColor, MarkColor(edge.color)); + MarkColor targetColor = std::min(srcColor, MarkColor(edge.color())); MOZ_ASSERT(markColor() >= targetColor); if (targetColor == markColor()) { - ApplyGCThingTyped(edge.target, edge.target->getTraceKind(), + ApplyGCThingTyped(edge.target(), edge.target()->getTraceKind(), [this](auto t) { markAndTraverse<MarkingOptions::MarkImplicitEdges>(t); }); @@ -762,7 +762,7 @@ void GCMarker::markEphemeronEdges(EphemeronEdgeVector& edges, // delegate zone to get marked later, look up an edge in this table, and // then try to mark something in a Zone that is no longer marking. if (srcColor == MarkColor::Black && markColor() == MarkColor::Black) { - edges.eraseIf([](auto& edge) { return edge.color == MarkColor::Black; }); + edges.eraseIf([](auto& edge) { return edge.color() == MarkColor::Black; }); } } diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp @@ -257,7 +257,10 @@ static void EraseIf(js::gc::EphemeronEdgeVector& entries, Pred pred) { static void SweepEphemeronEdgesWhileMinorSweeping( js::gc::EphemeronEdgeVector& entries) { EraseIf(entries, [](js::gc::EphemeronEdge& edge) -> bool { - return IsAboutToBeFinalizedDuringMinorSweep(&edge.target); + Cell* target = edge.target(); + bool dead = IsAboutToBeFinalizedDuringMinorSweep(&target); + edge = js::gc::EphemeronEdge(edge.color(), target); + return dead; }); }