================
@@ -48,7 +49,66 @@ void MemoryCache::AddL1CacheData(lldb::addr_t addr, const 
void *src,
 void MemoryCache::AddL1CacheData(lldb::addr_t addr,
                                  const DataBufferSP &data_buffer_sp) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  m_L1_cache[addr] = data_buffer_sp;
+  // The L1 cache is kept as a set of non-overlapping chunks: both Flush() and
+  // FindL1CacheEntry() only inspect the single chunk whose start is closest to
+  // a given address, so they assume no two chunks cover the same address.
+  //
+  // A new chunk can overlap ones that are already cached.  Merge the new chunk
+  // with every chunk it intersects into a single chunk spanning their union, 
so
+  // the coverage of all of them is kept while the invariant holds.  The 
process
+  // is stopped while the cache is populated, so overlapping chunks hold
+  // identical bytes; where they might differ, the just fetched data wins.
+  const size_t data_byte_size = data_buffer_sp->GetByteSize();
+  // A zero-length chunk can never satisfy a read and would never be flushed, 
so
+  // there is nothing to cache.
+  if (data_byte_size == 0)
+    return;
+
+  AddrRange new_range(addr, data_byte_size);
+  addr_t merged_base = new_range.GetRangeBase();
+  addr_t merged_end = new_range.GetRangeEnd();
+
+  // Chunks are ordered by start address and do not overlap, so the chunks that
+  // intersect the new one form a contiguous run.  The first one that can
+  // intersect is the chunk starting at or immediately below addr; start there
+  // and walk forward while a chunk still intersects the new range.
+  BlockMap::iterator pos = m_L1_cache.upper_bound(addr);
+  if (pos != m_L1_cache.begin())
+    --pos;
+  BlockMap::iterator merge_first = m_L1_cache.end();
+  BlockMap::iterator merge_end = m_L1_cache.end();
+  while (pos != m_L1_cache.end() && pos->first < new_range.GetRangeEnd()) {
+    AddrRange chunk_range(pos->first, pos->second->GetByteSize());
+    if (chunk_range.DoesIntersect(new_range)) {
+      merged_base = std::min(merged_base, chunk_range.GetRangeBase());
+      merged_end = std::max(merged_end, chunk_range.GetRangeEnd());
+      if (merge_first == m_L1_cache.end())
+        merge_first = pos;
+      merge_end = std::next(pos);
----------------
felipepiovezan wrote:

I think you can initialize both `merge_first` and `merge_end` to the original 
value of `pos` (after the decrement), and only advance `merge_end` here.

Then, at the end, you only compare `merge_first != merge_pos`.

It's a bit less branchy this way,

https://github.com/llvm/llvm-project/pull/208347
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to