04 Aug 2026

feedPlanet Mozilla

The Rust Programming Language Blog: Enabling the next iteration of the borrow checker on nightly

TL;DR We are enabling the next iteration of the borrow checker (coined Polonius Alpha) on nightly in preparation for stabilization in the next few months.

Whaaaaaat?

Yes! You heard it right! The next iteration of the Rust borrow checker is coming! Rust's first borrow checker ("AST borrowck") was very limited and was phased out in 2019 in favor of NLL, other than a "migrate mode" that was used to provide nice error messages. That migrate mode was finally removed in 2022.

The Polonius borrow checker spun out of the NLL effort in 2018. The initial formulation passed the NLL test suite and accepted (sound) code that NLL did not. However, performance was a critically-limiting factor; generally borrow check was slower than NLL, but certain programs were considerably slower than NLL to the extent that using that implementation/formulation of Polonius was a non-starter. Attempts were made over the years to implement the Polonius formulation in a performant manner, without much luck in addressing the core issues.

In 2023, a new formulation of a Polonius-style borrow checker was imagined that required minimal rearchitecture of the existing NLL implementation and could be extended to allow more code to compile. We had hoped, to try to stabilize this new formulation in 2024; but, various things popped up that delayed this.

But! We're nearly there now! At this point, there are no known remaining issues with the subset coined Polonius Alpha that we intend to stabilize. And, performance is generally acceptable for stabilization (will discuss that a bit below).

So, we are enabling the Polonius Alpha borrow checker on nightly for testing until we stabilize fully later in the year. We're doing this in order to help find:

You can report any issues on Github or on Zulip.

Okay, what's new?

The key thing that Polonius Alpha enables that NLL does not is flow-sensitive borrow checking of lifetime outlives relationships.

Perhaps the smallest example demonstrating what will pass with Polonius Alpha but not the current NLL is:

fn reborrow(a: &mut u8) -> &mut u8 {
    let b = &mut *a;
    if true { b } else { a }
}

However, the example you will see more often is:

fn get_mut_or_default<'r, K: Hash + Eq + Copy, V: Default>(
    map: &'r mut HashMap<K, V>,
    key: K,
) -> &'r mut V {
    match map.get_mut(&key) {
        Some(value) => value,
        None => {
            map.insert(key, V::default());
            map.get_mut(&key).unwrap()
        }
    }
}

The issue is that the Some(value) => value branch causes the borrow checker to think that the borrow returned by map.get_mut(&key) lives for the entire function (because of the &'r mut V return type), even though that borrow isn't live in the None branch. NLL's analysis is flow-insensitive.

Polonius Alpha passes this because its analysis is flow-sensitive, and it knows that the borrow isn't live in the None branch.

Now, Polonius Alpha is not perfect; some programs that would compile under legacy Polonius (the slow original implementation) don't compile with Polonius Alpha. (This is of course why we call it "Polonius Alpha"). For example:

struct X { next: Option<Box<X>> }

fn conditional() {
    let mut b = Some(Box::new(X { next: None }));
    let mut p = &mut b;
    while let Some(now) = p {
        if true {
            p = &mut now.next;
        }
    }
}

(As a slight note: we have also found programs that compile with Polonius Alpha but not legacy Polonius, so it's not really a full subset.)

So, what about performance?

Polonius Alpha currently does strictly equal or more work compared to NLL, so we have been paying particular attention to potential performance regressions.

From the top ten thousand crates by downloads on crates.io, we have seen relatively few "significant" regressions, and even crates that have a "significant" regression are typically relatively minimal:

top10k_leaf_graph

Each point represents a crate within the 10,000 most-downloaded crates. The black line is an arbitrary threshold of significance, set to a 1% regression and quadratically scaled below 30 seconds. Red points are crates that pass this arbitrary regression threshold. X-axis is compile time (for the leaf crate only without dependencies) under NLL; Y-axis is the ratio of compile time under Polonius Time compared to NLL.

If you look at the top five crates, they are:

top10k_leaf_table

Outside the top ten thousand crates, we have focused mainly on crates with many borrows. The worst case we've seen is a 2-3x regression.

We have done some initial triage of the causes of these regressions and are thinking about the best way to fix them. Though, overall we think these regressions are fairly reasonable even if we can't fix them, given how rare and relatively minimal they are compared to the additional power Polonius Alpha brings over NLL.

I really don't want this. How do I opt-out?

To reiterate: this is only being enabled on nightly. But if you want to disable Polonius Alpha, and only use the stable NLL, you can pass -Zpolonius=off to rustc, use RUSTFLAGS=-Zpolonius=off, or with a project's .cargo/config.toml configuration file:

[target.x86_64-unknown-linux-gnu]
rustflags = ["-Zpolonius=off"]

If you have to do this, for some reason, please do tell us why on Github or on Zulip.

What's next?

Over the next few months, we will be monitoring Github and Zulip for any reported issues about Polonius Alpha. We will also be working to address known performance regressions. Finally, we will be working on internal documentation about the implementation. All prior to stabilization. Then, we are aiming to stabilize prior to the end of the year!

Although some programs that we want to compile don't work with Polonius Alpha (nor NLL today), we don't currently have any concrete plans to continue active feature work on the Polonius implementation after the stabilization of Polonius Alpha. We expect to continue to optimize the implementation and address any performance regressions for a little while. We will likely come back to Polonius feature-work at some point, but given that Polonius Alpha solves the most-encountered borrow-check issues, we are shifting our time to other high-priority work for the near future.

04 Aug 2026 12:00am GMT

03 Aug 2026

feedPlanet Mozilla

Firefox Tooling Announcements: Firefox Profiler Deployment (August 3, 2026)

The latest version of the Firefox Profiler is now live! Check out the full changelog below to see what's changed:

Highlights:

Other Changes:

Big thanks to our amazing localizers for making this release possible:

Find out more about the Firefox Profiler on profiler.firefox.com! If you have any questions, join the discussion on our Matrix channel!

1 post - 1 participant

Read full topic

03 Aug 2026 3:25pm GMT

31 Jul 2026

feedPlanet Mozilla

The Servo Blog: June in Servo: real world compat, media queries, SharedWorker, and more!

Servo 0.4.0 contains all of the changes we landed in June, which came out to yet another record 558 commits (April: 534, May: 391). For security fixes, see § Security.

servoshell 0.4.0 showing several new features: the ‘width’, ‘height’, ‘device-width’, ‘device-height’, and ‘aspect-ratio’ media query features, plus the upgraded ‘attr()’ function, with a box whose ‘background-color’ and ‘width’ are controlled by data attributes that are in turn set by range inputs

We've shipped several new web platform features:

Plus a bunch of new DOM APIs:

This is another big update, so here's an outline:

You can help!

Servo is steadily becoming a bigger and busier project every month, and by June 2026, we've been reading through over four times the commits as we did when we started in September 2023.

line chart showing how many commits landed in Servo’s main repo each month from September 2023 to June 2026 inclusive. there’s a clear linear trend, from 130 commits up to 551 commits

This is hard work, particularly since there are things we need to know that are often difficult to answer just by reading the changes:

Thanks to an initiative by @jdm, it's now easier than ever for you to help us answer those questions, using the Servo Highfive bot! If you're working on a pull request that you think might be interesting for the next monthly update, even if you're not 100% sure, tell us about it by following the steps below:

  1. You add the monthly update label to your pull request, or comment @servo-highfive monthly update

  2. Highfive posts a comment asking you some questions

  3. You answer those questions in a comment containing @servo-highfive monthly update answer

Security

Servo's JS runtime, SpiderMonkey 140.10.1, had several security bugs that have been fixed in Servo 0.4.0 with the update to SpiderMonkey 140.11.0 (@jschwe, #45584). For more details, see CVE-2026-8388, CVE-2026-8391, CVE-2026-8974, CVE-2026-8975, and MFSA 2026-48.

Several more security bugs in Servo's JS runtime have been fixed in Servo 0.4.0 with the update to SpiderMonkey 140.12.0 (@jschwe, #45766). The exact CVEs that apply to us are not yet known, but for more details, see MFSA 2026-58.

RSA operations in Subtle­Crypto now do modular exponentiation in constant time (@kkoyung, #45631). Please note that our RSA implementation is currently vulnerable to the Marvin Attack - for more details, see RUSTSEC-2023-0071.

ML-DSA operations in Subtle­Crypto now do the Decompose step in constant time, fixing RUSTSEC-2025-0144 (@kkoyung, #45294).

We've fixed an HTML injection bug (XSS) in file:/// directory listings, which affected file names containing </script> (@sahvx655-wq, #45510).

Real world compat

Layout correctness has significantly improved on lichess.org, and many websites have become a lot more readable thanks to our improved handling of variable fonts (@simonwuelker, #45768), including Zulip (servo.zulipchat.com) and Speedtest (speedtest.net).

v0.3.0
v0.4.0
lichess.org
v0.3.0
v0.4.0
Zulip (servo.zulipchat.com)
v0.3.0
v0.4.0
Speedtest (speedtest.net)

Many websites worked in Servo even before version 0.4.0, including Google Photos (photos.google.com) and Cash Converters (cashconverters.com.au), and continue to work in version 0.4.0. Other websites, like Google Maps (maps.google.com) and OpenStreetMap (www.openstreetmap.org), render well but have some issues with interactivity.

Google Photos (photos.google.com)
Cash Converters (cashconverters.com.au)
Google Maps (maps.google.com)
OpenStreetMap (www.openstreetmap.org)

We're interested to hear how well your favourite websites run in Servo! Report successes in this Zulip thread, and failures in our GitHub issues.

Work in progress

We're implementing the more powerful version of 'attr()' that can be used anywhere, not just in 'content', under --pref layout­_css­_attr­_enabled (@Loirooriol, #45041, #45421, #45495, #45752).

WebGPU support has improved, under --pref dom­_webgpu­_enabled:

All of the features above are enabled in servoshell's experimental mode.

We've made more progress towards accessibility support, under --pref accessibility_enabled (@alice, @delan, #45555, #45554, #44949).

We've started implementing visible and interactive text selection (@mrobinson, @SimonSapin, #46107), one of the most long-awaited features of any web browser. Stay tuned!

We've also started working on Web Animations, under --pref dom­_web­_animations­_enabled (@simonwuelker, #45522, #45983), as well as webkit­Relative­Path on File, under --pref dom­_entries­_api­_enabled (@yezhizhen, #45666).

Rust doesn't have a stable ABI, so it has generally not been possible to embed Servo in another application without building Servo from source. To make it possible, we've started designing a wrapper C API that will let you consume Servo as a prebuilt shared library using the stable and ubiquitous C ABI (@mukilan, #44984). Eventually the idea is that we'll create a wrapper Rust API around that wrapper C API, so you can have both the ergonomics of Rust and the build simplicity of C.

Embedding API

New in the Servo API:

Breaking changes:

We've improved the docs for Web­View, Web­View­Delegate, JS­Value, Alert­Dialog, Allow­Or­Deny­Request, Authentication­Response, Bluetooth­Device­Description, Confirm­Dialog, Console­Log­Level, Create­New­Web­View­Request, Embedder­Control, Embedder­Control­Response, File­Picker, Image, Java­Script­Error­Info, Navigation­Request, Permission­Request, Pixel­Format, Prompt­Dialog, Protocol­Handler­Registration, Protocol­Handler­Update­Registration, Scroll, Select­Element, Select­Element­Request, and Web­View­Vector (@mukilan, #45282, #45467).

For users and developers

In servoshell:

When using the Firefox DevTools:

We've fixed some build issues on riscv32, riscv64, and arm64 (@fxzjshm, @saschanaz, #45285, #45731), and modernised servoshell for Android to use Compose UI and Kotlin (@veyndan, #45923, #45932, #45941, #45982, #45985, #46015, #46035, #46037, #46046, #46053, #46061, #46071, #45641, #45643, #45650, #45665, #45671, #45676, #45679, #45683, #45712, #45713, #45734, #45738).

For developers of Servo itself:

More on the web platform

To allow for more performant scrolling, 'wheel' events are no longer .cancelable unless there are one or more non-passive event listeners (@kunalmohan, #45667). Note that like in Firefox, 'wheel' events are passive by default.

'dotted', 'dashed', and 'wavy' text decorations are now continuous across element boundaries (@mrobinson, #45726).

We've improved the conformance of <dialog> (@skyz1, @mrobinson, #45825, #45761), <iframe sandbox> (@cychronex-labs, #45880), <input minlength> and <input maxlength> (@skyz1, #45705), CSS gradients (@mrobinson, #43945), 'font-style' and 'unicode-range' in '@font-face' (@Loirooriol, #45821), FontFaceSet (@mrobinson, #45390, #45382), HTML­Input­Element (@steigeo, #45416), Intersection­Observer (@jdm, #45655, #45659, #45680), new Response() (@yezhizhen, #45953), URL.create­Object­URL() and URL.revoke­Object­URL() (@yezhizhen, #45182, #45417), and ECDSA and Ed25519 in Subtle­Crypto (@kkoyung, #45833, #46017).

We've fixed bugs related to <input hidden> (@mrobinson, #45750), 'animation-delay' (@yezhizhen, #45013), 'clip-path' (@Loirooriol, #45468, #45373), 'tab-size' (@SimonSapin, @mrobinson, #45309), 'width' and 'height' (@RichardTjokroutomo, #44627), 'box-shadow: inset' (@Loirooriol, #45620), 'animation­iteration' events (@Loirooriol, #45990), 'click' events (@mrobinson, #45751), 'load' events (@jdm, #45883), 'error' events in Worker global scopes (@Gae24, #45829), and document­.get­Element­By­Id() (@mrobinson, #45433).

Garbage collection safety

We use a RefCell-based mechanism to store many of our DOM types in other DOM types, enforcing Rust's "aliasing xor mutability" rule at runtime by panicking if the rule is violated. But when garbage collection happens, we need to borrow() each DomRefCell to trace the references, and this is the source of many panic bugs. To fix that whole class of bugs, we initially created CanGc, a marker type that would annotate the code paths where GC can occur, in conjunction with custom static analysis (@jdm, #33140).

With the Rust type system we can do even better, if we flip that around and require any borrow_mut() call to prove that GC can not occur by passing a NoGC marker value. We can then require that a &NoGC must be borrowed from a &JSContext (which blocks GC) and not a &mut JSContext (which allows GC), taking advantage of how Rust references work without needing any custom static analysis.

We have a large codebase that needs to be migrated in parts, so for now we've created the new method safe­_borrow­_mut() (@sagudev, #46050). We also need to update all of our script-related code to borrow our safe JSContext wrapper, rather than creating an owned JSContext on the spot.

This continues our long-running effort to use the Rust type system to make Servo's integration with SpiderMonkey safer and more reliable (@Gae24, @Keerti707, @Narfinger, @TimvdLippe, @sagudev, @guptapiyush16, @ivomurrell, @kunalmohan, @skyz1, #45230, #45436, #45503, #45617, #45711, #45797, #45800, #45858, #45884, #45937, #45902, #45968, #45977, #45991, #46003, #46005, #46084, #45548, #45552, #45590, #45909, #45912, #45943, #46089, #46117, #46114, #45320, #45324, #45328, #45340, #45381, #45385, #45410, #45392, #45409, #45604, #45616, #45618, #45627, #45636, #45662, #45663, #45675, #45674, #45677, #45684, #45735, #45807, #45810, #45816, #45818, #45828, #45838, #45836, #45837, #45840, #45841, #45857, #45859, #45862, #45875, #45887, #45931, #45964, #45935, #45987, #45988, #46001, #46040, #46051, #46057, #46106, #46125, #45678, #46002, #45845, #45645, #45673, #45259, #45817, #45822, #45876, #45877, #45891).

Performance and stability

NoGC was designed to prevent dynamic borrow failures, but it also enables some performance optimisations! If we can prove that garbage collection is impossible in some part of Servo, we can often avoid rooting JavaScript objects when interacting with them within that region of code. This has allowed us to reduce overheads by over 1% in the layout process and in HTML­Collection (@Narfinger, #46092, #45582).

Our memory usage has improved, with BoxFragment now 17% smaller (288 → 240 bytes on amd64) and ShapeCacheEntry now smaller too (@SimonSapin, @mrobinson, @simonwuelker, #45183, #45496).

We've fixed some nasty memory leaks when reloading and in 2D canvases (@Taym95, @sagudev, @jschwe, #45455, #45261, #45414).

Speaking of which, 2D canvases now use up to 23% less power (@yezhizhen, #45301), and we now avoid rasterising the same SVG more than once (@Narfinger, @jschwe, #44805).

Servo now decodes all images asynchronously and fills image caches asynchronously, leaving script threads (web content processes) more time for other work (@Narfinger, #45542, #44483). On top of that, we've improved incremental layout (@mrobinson, @Loirooriol, #45411) and reduced reflows in IntersectionObserver (@jschwe, #45986).

We've started working on incremental updates for the stacking context tree, and as a side effect, we've made some layout-bound microbenchmarks up to 10% faster (@mrobinson, @Loirooriol, #45208).

We've also reduced allocations, copies, GC rooting steps, and other operations in many parts of Servo (@Narfinger, @SimonSapin, @mrobinson, @Loirooriol, #45506, #45969, #45940, #45760, #46090, #45335, #45413, #45511).

For several months, Frédéric (@fred-wang) has been fuzzing for Servo bugs, and thanks to his work we've fixed sixteen (16) crash bugs in June, affecting <iframe>, <slot>, <link onerror>, 'animation', 'clip-path', 'content', 'rotate', 'transition', 'transform-style', 'display: contents', 'overflow: clip', CSS­Keyframes­Rule, Font­Face, stop() on Window, document­.element­From­Point(), and the DOM tree (@mrobinson, @Loirooriol, @fred-wang, #46031, #46027, #46054, #46058, #46016, #46028, #46033, #45287, #45951, #45634, #45629, #46110, #46094, #45799, #45611, #45682, #45788, #45612, #45834).

We've also fixed crash bugs related to IPC failures, HTML­Input­Element, Range, the DevTools Debugger tab, and when servoshell is built with --features native-bluetooth (@jschwe, @Taym95, @mrobinson, @atbrakhi, @mukilan, #45311, #45619, #45765, #45513, #45702).

New contributors

A special thanks to the following people for landing their first patch in Servo:

Interested in helping build a web browser? Take a look at our curated list of issues that are good for new contributors!

Donations

Thanks again for your generous support! We are now receiving 7681 USD/month (+0.2% from May) in recurring donations. This helps us cover the cost of our speedy CI and benchmarking servers, one of our latest Outreachy interns, and funding maintainer work that helps more people contribute to Servo.

Servo is also on thanks.dev, and already 35 GitHub users (same as May) that depend on Servo are sponsoring us there. If you use Servo libraries like url, html5ever, selectors, or cssparser, signing up for thanks.dev could be a good way for you (or your employer) to give back to the community.

We now have sponsorship tiers that allow you or your organisation to donate to the Servo project with public acknowlegement of your support. If you're interested in this kind of sponsorship, please contact us at join@servo.org.

7681 USD/month
10000

Use of donations is decided transparently via the Technical Steering Committee's public funding request process, and active proposals are tracked in servo/project#187. For more details, head to our Sponsorship page.

31 Jul 2026 12:00am GMT