@@ -53,7 +53,7 @@ struct StackCache {
53
53
impl StackCache {
54
54
/// When a tag is used, we call this function to add or refresh it in the cache.
55
55
///
56
- /// We use position in the cache to represent how recently a tag was used; the first position
56
+ /// We use the position in the cache to represent how recently a tag was used; the first position
57
57
/// is the most recently used tag. So an add shifts every element towards the end, and inserts
58
58
/// the new element at the start. We lose the last element.
59
59
/// This strategy is effective at keeping the most-accessed tags in the cache, but it costs a
@@ -104,7 +104,7 @@ impl<'tcx> Stack {
104
104
/// index is given it means the match was *not* in the known part of the stack.
105
105
/// `Ok(None)` indicates it matched the "unknown" part of the stack.
106
106
/// `Err` indicates it was not found.
107
- pub fn find_granting (
107
+ pub ( super ) fn find_granting (
108
108
& mut self ,
109
109
access : AccessKind ,
110
110
tag : SbTagExtra ,
@@ -167,9 +167,15 @@ impl<'tcx> Stack {
167
167
168
168
#[ cfg( feature = "stack-cache" ) ]
169
169
fn find_granting_cache ( & mut self , access : AccessKind , tag : SbTag ) -> Option < usize > {
170
- // When the borrow stack is empty, there are no tags we could put into the cache that would
171
- // be valid. Additionally, since lookups into the cache are a linear search it doesn't make
172
- // sense to use the cache when it is no smaller than a search of the borrow stack itself.
170
+ // This looks like a common-sense optimization; we're going to do a linear search of the
171
+ // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule
172
+ // and this check actually ensures we do not access an invalid cache.
173
+ // When a stack is created and when tags are removed from the top of the borrow stack, we
174
+ // need some valid value to populate the cache. In both cases, we try to use the bottom
175
+ // item. But when the stack is cleared in `set_unknown_bottom` there is nothing we could
176
+ // place in the cache that is correct. But due to the way we populate the cache in
177
+ // `StackCache::add`, we know that when the borrow stack has grown larger than the cache,
178
+ // every slot in the cache is valid.
173
179
if self . borrows . len ( ) <= CACHE_LEN {
174
180
return None ;
175
181
}
@@ -261,6 +267,9 @@ impl<'tcx> Stack {
261
267
}
262
268
263
269
pub fn set_unknown_bottom ( & mut self , tag : SbTag ) {
270
+ // We clear the borrow stack but the lookup cache doesn't support clearing per se. Instead,
271
+ // there is a check explained in `find_granting_cache` which protects against accessing the
272
+ // cache when it has been cleared and not yet refilled.
264
273
self . borrows . clear ( ) ;
265
274
self . unknown_bottom = Some ( tag) ;
266
275
}
0 commit comments