Record the refcount removal beside the sweep that raised it

This commit is contained in:
iris-ai committed 2026-09-21 00:16:55 -04:00
1 parent d24ff83d6b
commit 6450615434
2 files changed
+45 -26

No files matched your search

+24 -9
View File
@@ -10,7 +10,7 @@ the current plan is in `docs/HANDOFF.md`.
Over the whole branch again, aimed first at what allocates -- `Vec`s, `Arc`s,
capacity dropped and re-grown -- and then at whatever else the reading turned
up. Eight findings.
up. Nine findings.
- **A container's draw was quadratic in its children.** Every per-child step
in one draw asked "have I done this one already?" by searching a list:
@@ -116,7 +116,24 @@ up. Eight findings.
does not clip it, because masking is a capability a caller opts into by
putting a `Masked` around it. The code is right; the reason was not.
Five things the sweep **looked at and left**:
- **`StrongWidget` carried a `RefCounter(Arc<AtomicU32>)` it could never
use.** It deliberately has no `Clone`, so the count never rose above zero,
`RefCounter::drop` always answered true, and `StrongWidget::refs` had no
caller -- while every widget made paid a heap allocation and every one
created or dropped paid two atomic read-modify-writes. Removed: the handle is
the id, the sender and the type, and `Drop` sends. It is 32 bytes rather than
40, and 40 rather than 48 for a `dyn` one. Raised as something to leave for
the pre-gate pass, `handle.rs` being outside #19, and Bryan asked for it here
(2026-09-21): not being `Clone` is what makes one handle the only one, which
is the same fact the child note above rests on.
`RefCounter` stays for `TextureHandle`, which does clone -- several widgets
showing one picture share its slot -- and is down to what that needs:
`quiet_clone` and `refs` had no callers at all, and `new` was `Default` spelt
out, so the default is derived now and says in one line that zero means one
handle.
Four things the sweep **looked at and left**:
- **Text allocates about six times per re-broken paragraph per frame**, and it
is not worth removing. One is the whole text copied into the placement store
@@ -129,13 +146,6 @@ Five things the sweep **looked at and left**:
is **0.07%**. The machinery is two pools and a changed `place` signature for
that, so the count is recorded here instead. Allocation count is not the
same quantity as cost, and this is where the two part.
- **`StrongWidget` carries a `RefCounter(Arc<AtomicU32>)` it can never use.**
`StrongWidget` deliberately has no `Clone`, so the count never rises above
zero and `RefCounter::drop` always answers true -- but every widget still
allocates an `Arc`, and creating and dropping one is two atomic
read-modify-writes. `StrongWidget::refs` has no caller. `handle.rs` is
untouched by #19, so this belongs to the review of the code written before
the gate; recorded there.
- **More for that same pass, all dead and all older than #19**:
`Size::to_uivec2`, `Size::rel`, `Size::leftover`, `Len::to_uivec2`,
`Vec2::with_x`, `Vec2::with_y`, `Vec2::ceil`, `Layers::iter_orderless_mut`.
@@ -151,6 +161,11 @@ Five things the sweep **looked at and left**:
the duplication is bounded by what the caller wrote rather than by anything
the arena does on its own.
One more thing **looked at and left** in passing: `RefCounter` decrements with
`Ordering::Release` and has no acquire on the last drop, which is the shape an
`Arc` gets wrong when handles cross threads. Left because nothing here is
threaded and the orderings are not this sweep's to guess at.
Verified at the sweep's tip: format, workspace clippy under `-D warnings` with
and without `layout-diagnostics`, **190** ordinary, **193** diagnostic and
**189** release tests (188 and 191 before, with release failing), and the cold