================
@@ -489,6 +497,168 @@ TEST_F(MemoryTest, TestReadStopsAtAnInvalidRange) {
   EXPECT_TRUE(process->m_reads.empty());
 }
 
+TEST_F(MemoryTest, TestReadRangesFromCaches) {
+  CacheTestProcess proc;
+  ASSERT_TRUE(proc.process());
+  DummyProcess *process = proc.process();
+  const lldb::addr_t line = proc.line();
+
+  { // A short fetch must expose only the bytes it read, and must not disturb a
+    // range the caches already served.
+    TestMemoryCache cache(*process);
+    AddCacheChunk(cache, 0xB000, 40, 0xAA);
+    AddCacheChunk(cache, 0xC000, 8, 0xCC);
+    process->SetMaxReadSize(20);
+    process->SetFiller(0xBB);
+    process->m_reads.clear();
+    llvm::SmallVector<uint8_t, 0> buffer(72, 0);
+    llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0xB000, 64},
+                                                       {0xC000, 8}};
+    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results =
+        cache.ReadRanges(ranges, buffer);
+    ASSERT_EQ(results.size(), 2u);
+    ASSERT_EQ(results[0].size(), 20u);
+    EXPECT_TRUE(AllBytesAre(results[0], 0xBB));
+    ASSERT_EQ(results[1].size(), 8u);
+    EXPECT_TRUE(AllBytesAre(results[1], 0xCC));
+  }
+
+  { // A range ReadRanges fetched is cached, so asking for it again serves it
+    // without going to the inferior.
+    TestMemoryCache cache(*process);
+    process->SetMaxReadSize(4 * line);
+    process->SetFiller(0xBB);
+    process->m_reads.clear();
+    llvm::SmallVector<uint8_t, 0> buffer(24, 0);
+    llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0x16000, 24}};
+    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results =
+        cache.ReadRanges(ranges, buffer);
+    ASSERT_EQ(results.size(), 1u);
+    ASSERT_EQ(results[0].size(), 24u);
+    EXPECT_TRUE(AllBytesAre(results[0], 0xBB));
+    ASSERT_FALSE(process->m_reads.empty());
+
+    process->SetMaxReadSize(0);
+    process->m_reads.clear();
+    llvm::SmallVector<uint8_t, 0> again(24, 0);
+    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> second =
+        cache.ReadRanges(ranges, again);
+    ASSERT_EQ(second.size(), 1u);
+    ASSERT_EQ(second[0].size(), 24u);
+    EXPECT_TRUE(AllBytesAre(second[0], 0xBB));
+    EXPECT_TRUE(process->m_reads.empty());
+  }
+
+  { // A range inside an invalid range gets an empty result without reaching 
the
+    // inferior, and leaves the ranges on either side of it alone.
+    TestMemoryCache cache(*process);
+    AddCacheChunk(cache, 0x17000, 8, 0xAA);
+    cache.AddInvalidRange(0x17100, 8);
+    process->SetMaxReadSize(4 * line);
+    process->SetFiller(0xBB);
+    process->m_reads.clear();
+    llvm::SmallVector<uint8_t, 0> buffer(24, 0);
+    llvm::SmallVector<Range<addr_t, size_t>> ranges = {
+        {0x17000, 8}, {0x17100, 8}, {0x17200, 8}};
+    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results =
+        cache.ReadRanges(ranges, buffer);
+    ASSERT_EQ(results.size(), 3u);
+    ASSERT_EQ(results[0].size(), 8u); // a cache hit
+    EXPECT_TRUE(AllBytesAre(results[0], 0xAA));
+    EXPECT_TRUE(results[1].empty());  // the invalid range
+    ASSERT_EQ(results[2].size(), 8u); // a miss, fetched
+    EXPECT_TRUE(AllBytesAre(results[2], 0xBB));
+    // Only the miss reached the inferior.
+    ASSERT_EQ(process->m_reads.size(), 1u);
+    EXPECT_EQ(process->m_reads[0].first, 0x17200u);
+    EXPECT_EQ(process->m_reads[0].second, 8u);
+  }
+}
+
+TEST_F(MemoryTest, TestReadRequestShape) {
+  CacheTestProcess proc;
+  ASSERT_TRUE(proc.process());
+  DummyProcess *process = proc.process();
+  const lldb::addr_t line = proc.line();
+
+  { // A read longer than a line that L1 cannot serve whole goes to the 
inferior
+    // as one request for the whole range.
+    //         v base         v base + line
+    // cache:  |AAAAAAAAAAAAAA|AA|
+    // process:|BBBBBBBBBBBBBB|BBBBBBBBBBBB|BBBBBBBBBBBB|
+    // buf:    |BBBBBBBBBBBBBB|BBBBBBBBBBBB|BBBBBBBBBBBB|
+    TestMemoryCache cache(*process);
+    Status error;
+    const lldb::addr_t base = 0x15000;
+    AddCacheChunk(cache, base, line + 8, 0xAA); // a whole line plus a 
remainder
+    process->SetMaxReadSize(4 * line);
+    process->SetFiller(0xBB);
+    process->m_reads.clear();
+    std::vector<uint8_t> buf(3 * line, 0);
+    ASSERT_EQ(cache.Read(base, buf.data(), buf.size(), error), buf.size());
+    EXPECT_TRUE(AllBytesAre(buf, 0xBB));
+    // One request, for exactly what the caller asked.
+    ASSERT_EQ(process->m_reads.size(), 1u);
+    EXPECT_EQ(process->m_reads[0].first, base);
+    EXPECT_EQ(process->m_reads[0].second, buf.size());
+
+    // Cached where it was read from, so the same read now sends nothing and
+    // returns the same bytes.
+    process->SetMaxReadSize(0);
+    process->m_reads.clear();
+    std::vector<uint8_t> again(3 * line, 0);
+    EXPECT_EQ(cache.Read(base, again.data(), again.size(), error),
+              again.size());
+    EXPECT_EQ(again, buf);
+    EXPECT_TRUE(process->m_reads.empty());
+  }
+}
+
+// A flushed range whose end wraps past UINT64_MAX must stop at the top line.
----------------
JDevlieghere wrote:

The description says "TestFlushAtTheTopOfTheAddressSpace pins Flush's current 
behavior at
the wrap, not correct behavior." but this pins that buggy behavor as the 
contract. Should this be a FIXME?

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

Reply via email to