Skip to content

Commit 6eeea05

Browse files
author
Markus Westerlind
committed
refactor: Make UnifyLog have lower overhead snapshots
1 parent 65014d8 commit 6eeea05

File tree

2 files changed

+103
-35
lines changed

2 files changed

+103
-35
lines changed

compiler/rustc_data_structures/src/logged_unification_table.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::ops::Range;
22

3-
use rustc_index::vec::{Idx, IndexVec};
3+
use rustc_index::vec::Idx;
44

55
use crate::modified_set as ms;
66
use crate::unify as ut;
@@ -10,7 +10,6 @@ pub struct LoggedUnificationTable<K: ut::UnifyKey, I: Idx = K> {
1010
relations: ut::UnificationTable<ut::InPlace<K>>,
1111
unify_log: ul::UnifyLog<I>,
1212
modified_set: ms::ModifiedSet<I>,
13-
reference_counts: IndexVec<I, u32>,
1413
}
1514

1615
impl<K, I> LoggedUnificationTable<K, I>
@@ -23,7 +22,6 @@ where
2322
relations: ut::UnificationTable::new(),
2423
unify_log: ul::UnifyLog::new(),
2524
modified_set: ms::ModifiedSet::new(),
26-
reference_counts: IndexVec::new(),
2725
}
2826
}
2927

@@ -38,7 +36,7 @@ where
3836
where
3937
K::Value: ut::UnifyValue<Error = ut::NoError>,
4038
{
41-
if self.needs_log(vid) {
39+
if self.unify_log.needs_log(vid) {
4240
warn!("ModifiedSet {:?} => {:?}", vid, ty);
4341
self.modified_set.set(vid);
4442
}
@@ -59,7 +57,7 @@ where
5957
value: K::Value,
6058
) -> Result<(), <K::Value as ut::UnifyValue>::Error> {
6159
let vid = self.find(vid).into();
62-
if self.needs_log(vid) {
60+
if self.unify_log.needs_log(vid) {
6361
self.modified_set.set(vid);
6462
}
6563
self.relations.unify_var_value(vid, value)
@@ -75,24 +73,13 @@ where
7573
self.relations.unify_var_var(a, b)?;
7674

7775
if a == self.relations.find(a) {
78-
if self.needs_log(b.into()) {
79-
warn!("Log: {:?} {:?} => {:?}", a, b, I::from(self.relations.find(a)));
80-
self.unify_log.unify(a.into(), b.into());
81-
}
76+
self.unify_log.unify(a.into(), b.into());
8277
} else {
83-
if self.needs_log(a.into()) {
84-
warn!("Log: {:?} {:?} => {:?}", a, b, I::from(self.relations.find(a)));
85-
self.unify_log.unify(b.into(), a.into());
86-
}
78+
self.unify_log.unify(b.into(), a.into());
8779
}
8880
Ok(())
8981
}
9082

91-
fn needs_log(&self, vid: I) -> bool {
92-
!self.unify_log.get(vid).is_empty()
93-
|| self.reference_counts.get(vid).map_or(false, |c| *c != 0)
94-
}
95-
9683
pub fn union_value(&mut self, vid: I, value: K::Value)
9784
where
9885
K::Value: ut::UnifyValue<Error = ut::NoError>,
@@ -154,12 +141,11 @@ where
154141

155142
pub fn watch_variable(&mut self, index: I) {
156143
debug_assert!(index == self.relations.find(index).into());
157-
self.reference_counts.ensure_contains_elem(index, || 0);
158-
self.reference_counts[index] += 1;
144+
self.unify_log.watch_variable(index)
159145
}
160146

161147
pub fn unwatch_variable(&mut self, index: I) {
162-
self.reference_counts[index] -= 1;
148+
self.unify_log.unwatch_variable(index)
163149
}
164150

165151
pub fn drain_modified_set(&mut self, offset: &ms::Offset<I>, mut f: impl FnMut(I) -> bool) {

compiler/rustc_data_structures/src/unify_log.rs

Lines changed: 96 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,105 @@ use std::marker::PhantomData;
22

33
use rustc_index::vec::{Idx, IndexVec};
44

5+
enum Undo<T> {
6+
Move { index: T, old: usize },
7+
Extend { group_index: usize, len: usize },
8+
NewGroup { index: T },
9+
}
10+
511
pub struct UnifyLog<T: Idx> {
6-
unified_vars: IndexVec<T, Vec<T>>,
7-
undo_log: Vec<(T, u32)>,
12+
unified_vars: IndexVec<T, usize>,
13+
groups: Vec<Vec<T>>,
14+
undo_log: Vec<Undo<T>>,
15+
reference_counts: IndexVec<T, u32>,
816
snapshots: usize,
917
}
1018

19+
fn pick2_mut<T, I: Idx>(self_: &mut [T], a: I, b: I) -> (&mut T, &mut T) {
20+
let (ai, bi) = (a.index(), b.index());
21+
assert!(ai != bi);
22+
23+
if ai < bi {
24+
let (c1, c2) = self_.split_at_mut(bi);
25+
(&mut c1[ai], &mut c2[0])
26+
} else {
27+
let (c2, c1) = pick2_mut(self_, b, a);
28+
(c1, c2)
29+
}
30+
}
31+
1132
impl<T: Idx> UnifyLog<T> {
1233
pub fn new() -> Self {
13-
UnifyLog { unified_vars: IndexVec::new(), undo_log: Vec::new(), snapshots: 0 }
34+
UnifyLog {
35+
unified_vars: IndexVec::new(),
36+
groups: Vec::new(),
37+
undo_log: Vec::new(),
38+
reference_counts: IndexVec::new(),
39+
snapshots: 0,
40+
}
1441
}
1542

1643
pub fn unify(&mut self, root: T, other: T) {
17-
self.unified_vars.ensure_contains_elem(root, Vec::new);
18-
self.unified_vars.ensure_contains_elem(other, Vec::new);
19-
let (root_ids, other_ids) = self.unified_vars.pick2_mut(root, other);
20-
self.undo_log.push((root, root_ids.len() as u32));
21-
for &other in &*other_ids {
22-
if !root_ids.contains(&other) {
23-
root_ids.push(other);
44+
if !self.needs_log(other) {
45+
return;
46+
}
47+
self.unified_vars.ensure_contains_elem(root, usize::max_value);
48+
self.unified_vars.ensure_contains_elem(other, usize::max_value);
49+
let mut root_group = self.unified_vars[root];
50+
let other_group = self.unified_vars[other];
51+
52+
if other_group == usize::max_value() {
53+
let root_vec = if root_group == usize::max_value() {
54+
root_group = self.groups.len();
55+
self.unified_vars[root] = root_group;
56+
self.groups.push(Vec::new());
57+
self.undo_log.push(Undo::NewGroup { index: root });
58+
self.groups.last_mut().unwrap()
59+
} else {
60+
let root_vec = &mut self.groups[root_group];
61+
self.undo_log.push(Undo::Extend { group_index: root_group, len: root_vec.len() });
62+
root_vec
63+
};
64+
root_vec.push(other);
65+
} else {
66+
if root_group == usize::max_value() {
67+
let group = &mut self.unified_vars[root];
68+
self.undo_log.push(Undo::Move { index: root, old: *group });
69+
*group = other_group;
70+
self.groups[other_group].push(other);
71+
} else {
72+
let (root_vec, other_vec) = pick2_mut(&mut self.groups, root_group, other_group);
73+
self.undo_log.push(Undo::Extend { group_index: root_group, len: root_vec.len() });
74+
root_vec.extend_from_slice(other_vec);
75+
76+
if self.reference_counts.get(other).map_or(false, |c| *c != 0) {
77+
root_vec.push(other);
78+
}
2479
}
2580
}
26-
root_ids.push(other);
2781
}
2882

2983
pub fn get(&self, root: T) -> &[T] {
30-
self.unified_vars.get(root).map(|v| &v[..]).unwrap_or(&[][..])
84+
match self.unified_vars.get(root) {
85+
Some(group) => match self.groups.get(*group) {
86+
Some(v) => v,
87+
None => &[],
88+
},
89+
None => &[],
90+
}
91+
}
92+
93+
pub fn needs_log(&self, vid: T) -> bool {
94+
!self.get(vid).is_empty() || self.reference_counts.get(vid).map_or(false, |c| *c != 0)
95+
}
96+
97+
pub fn watch_variable(&mut self, index: T) {
98+
self.reference_counts.ensure_contains_elem(index, || 0);
99+
self.reference_counts[index] += 1;
100+
}
101+
102+
pub fn unwatch_variable(&mut self, index: T) {
103+
self.reference_counts[index] -= 1;
31104
}
32105

33106
pub fn snapshot(&mut self) -> Snapshot<T> {
@@ -44,8 +117,17 @@ impl<T: Idx> UnifyLog<T> {
44117

45118
pub fn rollback_to(&mut self, snapshot: Snapshot<T>) {
46119
self.snapshots -= 1;
47-
for (index, len) in self.undo_log.drain(snapshot.undo_log_len as usize..) {
48-
self.unified_vars[index].truncate(len as usize);
120+
for undo in self.undo_log.drain(snapshot.undo_log_len as usize..).rev() {
121+
match undo {
122+
Undo::Extend { group_index, len } => {
123+
self.groups[group_index].truncate(len as usize)
124+
}
125+
Undo::Move { index, old } => self.unified_vars[index] = old,
126+
Undo::NewGroup { index } => {
127+
self.groups.pop();
128+
self.unified_vars[index] = usize::max_value();
129+
}
130+
}
49131
}
50132
}
51133
}

0 commit comments

Comments
 (0)