java-topology/defects/bevy/patch/bevy-0001-slab-allocator-free-empty-slabs.patch

67 lines
2.8 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000011
Fixes bevy-0001: slab_allocator — O(E×L×S) Vec::iter().position() in free_empty_slabs().
--- a/crates/bevy_render/src/slab_allocator.rs
+++ b/crates/bevy_render/src/slab_allocator.rs
@@ DEFECT bevy-0001: free_empty_slabs() — Vec::iter().position() inside nested loop
@@ Called every frame from DeallocationStage::commit() for every freed GPU slab.
@@ No reverse map slab_id→layout; must scan all layout buckets to find the slab.
pub struct SlabAllocator<I>
where
I: SlabItem,
{
pub slabs: HashMap<SlabId<I>, Slab<I>>,
next_slab_id: SlabId<I>,
pub key_to_slab: HashMap<I::Key, SlabId<I>>,
slab_layouts: HashMap<I::Layout, Vec<SlabId<I>>>,
+ /// FIX bevy-0001: reverse map — slab_id → layout for O(1) lookup in free_empty_slabs
+ slab_id_to_layout: HashMap<SlabId<I>, I::Layout>,
}
// In SlabAllocator::new() / Default impl — initialize the new field:
- SlabAllocator {
+ SlabAllocator {
slabs: HashMap::default(),
next_slab_id: SlabId { ... },
key_to_slab: HashMap::default(),
slab_layouts: HashMap::default(),
+ slab_id_to_layout: HashMap::default(),
}
// In allocate_general() — when a new slab is created, record its layout:
self.slabs.insert(new_slab_id, Slab::General(new_slab));
candidate_slabs.push(new_slab_id);
+ // FIX bevy-0001: maintain reverse map for O(1) free_empty_slabs lookup
+ self.slab_id_to_layout.insert(new_slab_id, layout.clone());
// Replace the O(E×L×S) implementation:
- fn free_empty_slabs(&mut self, empty_slabs: impl Iterator<Item = SlabId<I>>) {
- for empty_slab in empty_slabs {
- self.slab_layouts.values_mut().for_each(|slab_ids| {
- let idx = slab_ids.iter().position(|&slab_id| slab_id == empty_slab);
- // O(S) linear scan per layout bucket — CWE-407
- if let Some(idx) = idx {
- slab_ids.remove(idx);
- }
- });
- self.slabs.remove(&empty_slab);
- }
- }
+ fn free_empty_slabs(&mut self, empty_slabs: impl Iterator<Item = SlabId<I>>) {
+ for empty_slab in empty_slabs {
+ // FIX bevy-0001: O(1) layout lookup via reverse map
+ if let Some(layout) = self.slab_id_to_layout.remove(&empty_slab) {
+ if let Some(slab_ids) = self.slab_layouts.get_mut(&layout) {
+ if let Some(pos) = slab_ids.iter().position(|&id| id == empty_slab) {
+ slab_ids.swap_remove(pos); // O(1) swap-remove (order irrelevant)
+ }
+ if slab_ids.is_empty() {
+ self.slab_layouts.remove(&layout);
+ }
+ }
+ }
+ self.slabs.remove(&empty_slab);
+ }
+ }