address nits

This commit is contained in:
Johannes Hostert 2024-08-28 13:55:30 +02:00
parent e34f35edd8
commit 84134c61bc
No known key found for this signature in database
GPG Key ID: 0BA6032B5A38D049
3 changed files with 26 additions and 15 deletions

View File

@ -71,6 +71,12 @@ pub struct FrameState {
impl VisitProvenance for FrameState { impl VisitProvenance for FrameState {
fn visit_provenance(&self, visit: &mut VisitWith<'_>) { fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
// Visit all protected tags. At least in Tree Borrows,
// protected tags can not be GC'd because they still have
// an access coming when the protector ends. Additionally,
// the tree compacting mechanism of TB's GC relies on the fact
// that all protected tags are marked as live for correctness,
// so we _have_ to visit them here.
for (id, tag) in &self.protected_tags { for (id, tag) in &self.protected_tags {
visit(Some(*id), Some(*tag)); visit(Some(*id), Some(*tag));
} }

View File

@ -288,18 +288,19 @@ pub fn can_be_replaced_by_child(self, child: Self) -> bool {
(ReservedFrz { .. }, ReservedIM) => false, (ReservedFrz { .. }, ReservedIM) => false,
(ReservedFrz { .. }, _) => true, (ReservedFrz { .. }, _) => true,
// Active can not be replaced by something surviving // Active can not be replaced by something surviving
// foreign reads and then remaining writable // foreign reads and then remaining writable.
(Active, ReservedIM) => false, (Active, ReservedIM) => false,
(Active, ReservedFrz { .. }) => false, (Active, ReservedFrz { .. }) => false,
// Replacing a state by itself is always okay, even if the child state is protected.
(Active, Active) => true, (Active, Active) => true,
// Active can be replaced by Frozen, since it is not protected // Active can be replaced by Frozen, since it is not protected.
(Active, Frozen) => true, (Active, Frozen) => true,
(Active, Disabled) => true, (Active, Disabled) => true,
// Frozen can only be replaced by Disabled // Frozen can only be replaced by Disabled (and itself).
(Frozen, Frozen) => true, (Frozen, Frozen) => true,
(Frozen, Disabled) => true, (Frozen, Disabled) => true,
(Frozen, _) => false, (Frozen, _) => false,
// Disabled can not be replaced by anything else // Disabled can not be replaced by anything else.
(Disabled, Disabled) => true, (Disabled, Disabled) => true,
(Disabled, _) => false, (Disabled, _) => false,
} }

View File

@ -128,10 +128,10 @@ fn perform_access(
Ok(transition) Ok(transition)
} }
/// Like `perform_access`, but ignores the diagnostics, and also is pure. /// Like `perform_access`, but ignores the concrete error cause and also uses state-passing
/// As such, it returns `Some(x)` if the transition succeeded, or `None` /// rather than a mutable reference. As such, it returns `Some(x)` if the transition succeeded,
/// if there was an error. /// or `None` if there was an error.
#[allow(unused)] #[cfg(test)]
fn perform_access_no_fluff( fn perform_access_no_fluff(
mut self, mut self,
access_kind: AccessKind, access_kind: AccessKind,
@ -865,14 +865,18 @@ fn can_be_replaced_by_single_child(
live: &FxHashSet<BorTag>, live: &FxHashSet<BorTag>,
) -> Option<UniIndex> { ) -> Option<UniIndex> {
let node = self.nodes.get(idx).unwrap(); let node = self.nodes.get(idx).unwrap();
// We never want to replace the root node, as it is also kept in `root_ptr_tags`.
if node.children.len() != 1 || live.contains(&node.tag) || node.parent.is_none() { if node.children.len() != 1 || live.contains(&node.tag) || node.parent.is_none() {
return None; return None;
} }
// Since protected nodes are never GC'd (see `borrow_tracker::GlobalStateInner::visit_provenance`), // Since protected nodes are never GC'd (see `borrow_tracker::FrameExtra::visit_provenance`),
// we know that `node` is not protected because otherwise `live` would // we know that `node` is not protected because otherwise `live` would
// have contained `node.tag`. // have contained `node.tag`.
let child_idx = node.children[0]; let child_idx = node.children[0];
let child = self.nodes.get(child_idx).unwrap(); let child = self.nodes.get(child_idx).unwrap();
// Check that for that one child, `can_be_replaced_by_child` holds for the permission
// on all locations.
for (_, data) in self.rperms.iter_all() { for (_, data) in self.rperms.iter_all() {
let parent_perm = let parent_perm =
data.get(idx).map(|x| x.permission).unwrap_or_else(|| node.default_initial_perm); data.get(idx).map(|x| x.permission).unwrap_or_else(|| node.default_initial_perm);
@ -893,7 +897,6 @@ fn can_be_replaced_by_single_child(
/// should have no children, but this is not checked, so that nodes /// should have no children, but this is not checked, so that nodes
/// whose children were rotated somewhere else can be deleted without /// whose children were rotated somewhere else can be deleted without
/// having to first modify them to clear that array. /// having to first modify them to clear that array.
/// otherwise (i.e. the GC should have marked it as removable).
fn remove_useless_node(&mut self, this: UniIndex) { fn remove_useless_node(&mut self, this: UniIndex) {
// Due to the API of UniMap we must make sure to call // Due to the API of UniMap we must make sure to call
// `UniValMap::remove` for the key of this node on *all* maps that used it // `UniValMap::remove` for the key of this node on *all* maps that used it
@ -950,17 +953,18 @@ fn remove_useless_children(&mut self, root: UniIndex, live: &FxHashSet<BorTag>)
// Remove all useless children. // Remove all useless children.
children_of_node.retain_mut(|idx| { children_of_node.retain_mut(|idx| {
if self.is_useless(*idx, live) { if self.is_useless(*idx, live) {
// delete it everywhere else // Delete `idx` node everywhere else.
self.remove_useless_node(*idx); self.remove_useless_node(*idx);
// and delete it from children_of_node // And delete it from children_of_node.
false false
} else { } else {
if let Some(nextchild) = self.can_be_replaced_by_single_child(*idx, live) { if let Some(nextchild) = self.can_be_replaced_by_single_child(*idx, live) {
// delete the in-between child // `nextchild` is our grandchild, and will become our direct child.
// Delete the in-between node, `idx`.
self.remove_useless_node(*idx); self.remove_useless_node(*idx);
// set the new child's parent // Set the new child's parent.
self.nodes.get_mut(nextchild).unwrap().parent = Some(*tag); self.nodes.get_mut(nextchild).unwrap().parent = Some(*tag);
// save the new child in children_of_node // Save the new child in children_of_node.
*idx = nextchild; *idx = nextchild;
} }
// retain it // retain it