Skip to content

Commit c387247

Browse files
TB: optimize accesses on large trees by ignoring subtrees if the access would mostly be a NOP
1 parent 9ca2f6b commit c387247

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

src/borrow_tracker/tree_borrows/perms.rs

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ impl Permission {
237237
pub fn is_active(&self) -> bool {
238238
self.inner == Active
239239
}
240+
/// Check if `self` is the never-allow-writes-again state of a pointer (is `Frozen`).
241+
pub fn is_frozen(&self) -> bool {
242+
self.inner == Frozen
243+
}
240244

241245
/// Default initial permission of the root of a new tree at inbounds positions.
242246
/// Must *only* be used for the root, this is not in general an "initial" permission!

src/borrow_tracker/tree_borrows/tree.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,31 @@ impl LocationState {
153153
) -> ContinueTraversal {
154154
if rel_pos.is_foreign() {
155155
let happening_now = IdempotentForeignAccess::from_foreign(access_kind);
156-
let new_access_noop =
156+
let mut new_access_noop =
157157
self.idempotent_foreign_access.can_skip_foreign_access(happening_now);
158+
if self.permission.is_disabled() {
159+
// A foreign access to a `Disabled` tag will have almost no observable effect.
160+
// It's a theorem that `Disabled` node have no protected initialized children,
161+
// and so this foreign access will never trigger any protector.
162+
// (Intuition: You're either protected initialized, and thus can't become Disabled
163+
// or you're already Disabled protected, but not initialized, and then can't
164+
// become initialized since that requires a child access, which Disabled blocks.)
165+
// Further, the children will never be able to read or write again, since they
166+
// have a `Disabled` parent. So this only affects diagnostics, such that the
167+
// blocking write will still be identified directly, just at a different tag.
168+
new_access_noop = true;
169+
}
170+
if self.permission.is_frozen() && access_kind == AccessKind::Read {
171+
// A foreign read to a `Frozen` tag will have almost no observable effect.
172+
// It's a theorem that `Frozen` nodes have no active children, so all children
173+
// already survive foreign reads. Foreign reads in general have almost no
174+
// effect, the only further thing they could do is make protected `Reserved`
175+
// nodes become conflicted, i.e. make them reject child writes for the further
176+
// duration of their protector. But such a child write is already rejected
177+
// because this node is frozen. So this only affects diagnostics, but the
178+
// blocking read will still be identified directly, just at a different tag.
179+
new_access_noop = true;
180+
}
158181
if new_access_noop {
159182
// Abort traversal if the new access is indeed guaranteed
160183
// to be noop.

tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ LL | *m = 42;
55
| ^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
66
|
77
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
8-
= help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access
9-
help: the accessed tag <TAG> was created here, in the initial state Reserved
8+
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
9+
= help: the conflicting tag <TAG> has state Frozen which forbids this child write access
10+
help: the accessed tag <TAG> was created here
1011
--> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC
1112
|
1213
LL | fn write_to_mut(m: &mut u8, other_ptr: *const u8) {
1314
| ^
14-
help: the accessed tag <TAG> later transitioned to Reserved (conflicted) due to a foreign read access at offsets [0x0..0x1]
15+
help: the conflicting tag <TAG> was created here, in the initial state Frozen
1516
--> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC
1617
|
17-
LL | std::hint::black_box(*other_ptr);
18-
| ^^^^^^^^^^
19-
= help: this transition corresponds to a temporary loss of write permissions until function exit
18+
LL | let intermediary = &root;
19+
| ^^^^^
2020
= note: BACKTRACE (of the first span):
2121
= note: inside `write_to_mut` at tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC
2222
note: inside `main`

0 commit comments

Comments
 (0)