This patch is to address an issue hit by one of our heavy SB API scripting developers; they have some code iterating over a large number of objects in SBValue's and one of the elements of the object has a type of void*; the Itanium ABI is trying to sniff the memory there to see if it might have a dynamic type. In this case, the elements often have the value 0, so lldb is trying to read memory at address 0, which fails, and the number of reads is quite large. Each failing memory read takes long enough in a JTAG like environment that this is a big perf issue.
We have a MemoryCache subsystem that saves blocks of inferior memory when we do a read, so repeated reads of the same address, or reads near the address that were cached, are saved at a single point in time. These memory cache buffers are flushed when execution is resumed.
This patch adds a new list of addresses we've tried to read from at this execution stop, which returned an error, and will not try to read from those addresses again. If lldb allocates memory in the inferior, or if we resume execution, this list of addresses is flushed.
I settled on using an llvm::SmallSet container for these addr_t's, but I'd appreciate if people have a different suggestion for the most appropriate container. I expect this list to be relatively small -- it is not common that lldb tries to read from addresses that are unreadable -- and my primary optimization concern is quick lookup because I will consult this list before I read from any address in memory.
When I was outlining my idea for this, Jim pointed out that MemoryCache has a InvalidRanges m_invalid_ranges ivar already, and could I reuse this. This is called by the DynamicLoader to mark a region of memory as never accessible (e.g. the lower 4GB on a 64-bit Darwin process), and is not flushed on execution resume / memory allocation. It is expressed in terms of memory ranges, when I don't know the range of memory that is inaccessible beyond an address. I could assume the range extends to the end of a page boundary, if I knew the page boundary size, but that still doesn't address the fact that m_invalid_ranges is intended to track inaccessible memory that is invariant during the process lifetime.
Should this be more specific like "failed because we know this is unreadable" or "has previously failed to read"?