tor-browser

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

commit 10bb1622d02686b10596948eb8ab258bca45eff9
parent 4d851b34a0aa8b743a08cb64cc00efcfbf2cb9e5
Author: Jan de Mooij <jdemooij@mozilla.com>
Date:   Fri, 28 Nov 2025 11:46:07 +0000

Bug 2001986 - Optimize LiveRange::tryToMoveDefAndUsesInto a bit. r=jseward

In some JS profiles of popular websites (bug 2001273, bug 1936209) we were spending
quite a bit of time under `LiveRange::tryToMoveDefAndUsesInto` called from
the non-Wasm code path in `trySplitAcrossHotcode`.

This patch adds a fast path based on `moveAllUsesToTheEndOf`. Running some JS benchmarks
locally, this fast path hits in the majority of cases.

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

Diffstat:
Mjs/src/jit/BacktrackingAllocator.cpp | 33+++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp @@ -835,6 +835,28 @@ void LiveRange::tryToMoveDefAndUsesInto(LiveRange* other) { CodePosition otherFrom = other->from(); CodePosition otherTo = other->to(); + // Copy the has-definition flag to |other|, if possible. + if (hasDefinition() && from() == otherFrom) { + other->setHasDefinition(); + } + + // If we have no uses, we're done. + if (!hasUses()) { + return; + } + + // Fast path for when we can use |moveAllUsesToTheEndOf|. This is very common + // for the non-Wasm code path in |trySplitAcrossHotcode|. This fast path had a + // hit rate of 75% when running Octane in the JS shell. + // + // Note: the |!other->hasUses()| check could be more precise, but this didn't + // improve the hit rate at all. + if (!other->hasUses() && usesBegin()->pos >= otherFrom && + lastUse()->pos < otherTo) { + moveAllUsesToTheEndOf(other); + return; + } + // The uses are sorted by position, so first skip all uses before |other| // starts. UsePositionIterator iter = usesBegin(); @@ -852,22 +874,21 @@ void LiveRange::tryToMoveDefAndUsesInto(LiveRange* other) { } MOZ_ASSERT_IF(iter, !other->covers(iter->pos)); - - // Distribute the definition to |other| as well, if possible. - if (hasDefinition() && from() == other->from()) { - other->setHasDefinition(); - } } void LiveRange::moveAllUsesToTheEndOf(LiveRange* other) { MOZ_ASSERT(&other->vreg() == &vreg()); MOZ_ASSERT(this != other); - MOZ_ASSERT(other->contains(this)); + MOZ_ASSERT(intersects(other)); if (uses_.empty()) { return; } + // Assert |other| covers all of our uses. + MOZ_ASSERT(other->covers(uses_.begin()->pos)); + MOZ_ASSERT(other->covers(uses_.back()->pos)); + // Assert |other->uses_| remains sorted after adding our uses at the end. MOZ_ASSERT_IF(!other->uses_.empty(), SortBefore(other->uses_.back(), *uses_.begin()));