Added a per-process cache for reserved memory
regions that aren't actually allocated in the process. This cache is used by the expression parser if the underlying process doesn't support memory allocation, to avoid needless repeated searches for unused address ranges. Also fixed a silly bug in IRMemoryMap where it would continue searching even after it found a valid region. <rdar://problem/13866629> llvm-svn: 182028
This commit is contained in:
parent
9daaf5775c
commit
bb77704cd1
|
@ -3533,6 +3533,72 @@ public:
|
|||
return m_public_run_lock;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// This is a cache of reserved and available memory address ranges
|
||||
// for a single modification ID (see m_mod_id). It's meant for use
|
||||
// by IRMemoryMap, but to stick with the process. These memory
|
||||
// ranges happen to be unallocated in the underlying process, but we
|
||||
// make no guarantee that at a future modification ID they won't be
|
||||
// gone. This is only useful if the underlying process can't
|
||||
// allocate memory.
|
||||
//
|
||||
// When a memory space is determined to be available it is
|
||||
// registered as reserved at the current modification. If it is
|
||||
// freed later, it is added to the free list if the modification ID
|
||||
// hasn't changed. Then clients can simply query the free list for
|
||||
// the size they want.
|
||||
//------------------------------------------------------------------
|
||||
class ReservationCache
|
||||
{
|
||||
public:
|
||||
ReservationCache (Process &process);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Mark that a particular range of addresses is in use. Adds it
|
||||
// to the reserved map, implicitly tying it to the current
|
||||
// modification ID.
|
||||
//------------------------------------------------------------------
|
||||
void
|
||||
Reserve (lldb::addr_t addr, size_t size);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Mark that a range is no longer in use. If it's found in the
|
||||
// reservation list, that means that the modification ID hasn't
|
||||
// changed since it was reserved, so it can be safely added to the
|
||||
// free list.
|
||||
//------------------------------------------------------------------
|
||||
void
|
||||
Unreserve (lldb::addr_t addr);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Try to find an unused range of the given size in the free list.
|
||||
//------------------------------------------------------------------
|
||||
lldb::addr_t
|
||||
Find (size_t size);
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// Clear all lists if the modification ID has changed.
|
||||
//------------------------------------------------------------------
|
||||
void CheckModID();
|
||||
|
||||
typedef std::map <lldb::addr_t, size_t> ReservedMap;
|
||||
typedef std::vector <lldb::addr_t> FreeList;
|
||||
typedef std::map <size_t, FreeList> FreeMap;
|
||||
|
||||
ReservedMap m_reserved_cache;
|
||||
FreeMap m_free_cache;
|
||||
|
||||
Process &m_process;
|
||||
ProcessModID m_mod_id;
|
||||
};
|
||||
|
||||
ReservationCache &
|
||||
GetReservationCache ()
|
||||
{
|
||||
return m_reservation_cache;
|
||||
}
|
||||
private:
|
||||
ReservationCache m_reservation_cache;
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
// NextEventAction provides a way to register an action on the next
|
||||
|
|
|
@ -31,19 +31,14 @@ IRMemoryMap::~IRMemoryMap ()
|
|||
|
||||
if (process_sp)
|
||||
{
|
||||
for (AllocationMap::value_type &allocation : m_allocations)
|
||||
{
|
||||
if (allocation.second.m_policy == eAllocationPolicyMirror ||
|
||||
allocation.second.m_policy == eAllocationPolicyProcessOnly ||
|
||||
(allocation.second.m_policy == eAllocationPolicyHostOnly && process_sp->CanJIT()))
|
||||
process_sp->DeallocateMemory(allocation.second.m_process_alloc);
|
||||
AllocationMap::iterator iter;
|
||||
|
||||
if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
|
||||
Error err;
|
||||
|
||||
while ((iter = m_allocations.begin()) != m_allocations.end())
|
||||
{
|
||||
log->Printf("IRMemoryMap::~IRMemoryMap deallocated [0x%llx..0x%llx)",
|
||||
(uint64_t)allocation.second.m_process_start,
|
||||
(uint64_t)allocation.second.m_process_start + (uint64_t)allocation.second.m_size);
|
||||
}
|
||||
err.Clear();
|
||||
Free(iter->first, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +63,14 @@ IRMemoryMap::FindSpace (size_t size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (process_sp)
|
||||
{
|
||||
ret = process_sp->GetReservationCache().Find(size);
|
||||
|
||||
if (ret != LLDB_INVALID_ADDRESS)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int iterations = 0; iterations < 16; ++iterations)
|
||||
{
|
||||
lldb::addr_t candidate = LLDB_INVALID_ADDRESS;
|
||||
|
@ -106,6 +109,11 @@ IRMemoryMap::FindSpace (size_t size)
|
|||
continue;
|
||||
|
||||
ret = candidate;
|
||||
|
||||
if (process_sp)
|
||||
process_sp->GetReservationCache().Reserve(candidate, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -382,8 +390,13 @@ IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
|
|||
case eAllocationPolicyHostOnly:
|
||||
{
|
||||
lldb::ProcessSP process_sp = m_process_wp.lock();
|
||||
if (process_sp && process_sp->CanJIT())
|
||||
if (process_sp)
|
||||
{
|
||||
if (process_sp->CanJIT())
|
||||
process_sp->DeallocateMemory(allocation.m_process_alloc); // FindSpace allocated this for real
|
||||
else
|
||||
process_sp->GetReservationCache().Unreserve(allocation.m_process_alloc); // FindSpace registered this memory
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -996,6 +996,7 @@ Process::Process(Target &target, Listener &listener) :
|
|||
ProcessProperties (false),
|
||||
UserID (LLDB_INVALID_PROCESS_ID),
|
||||
Broadcaster (&(target.GetDebugger()), "lldb.process"),
|
||||
m_reservation_cache (*this),
|
||||
m_target (target),
|
||||
m_public_state (eStateUnloaded),
|
||||
m_private_state (eStateUnloaded),
|
||||
|
@ -5589,3 +5590,60 @@ Process::DidExec ()
|
|||
DoDidExec();
|
||||
CompleteAttach ();
|
||||
}
|
||||
|
||||
Process::ReservationCache::ReservationCache (Process &process) : m_process(process)
|
||||
{
|
||||
m_mod_id = process.GetModID();
|
||||
}
|
||||
|
||||
void
|
||||
Process::ReservationCache::Reserve (lldb::addr_t addr, size_t size)
|
||||
{
|
||||
CheckModID();
|
||||
m_reserved_cache[addr] = size;
|
||||
}
|
||||
|
||||
void
|
||||
Process::ReservationCache::Unreserve (lldb::addr_t addr)
|
||||
{
|
||||
CheckModID();
|
||||
ReservedMap::iterator iter = m_reserved_cache.find(addr);
|
||||
|
||||
if (iter != m_reserved_cache.end())
|
||||
{
|
||||
size_t size = iter->second;
|
||||
m_reserved_cache.erase(iter);
|
||||
m_free_cache[size].push_back(addr);
|
||||
}
|
||||
}
|
||||
|
||||
lldb::addr_t
|
||||
Process::ReservationCache::Find (size_t size)
|
||||
{
|
||||
CheckModID();
|
||||
lldb::addr_t ret = LLDB_INVALID_ADDRESS;
|
||||
FreeMap::iterator map_iter = m_free_cache.find(size);
|
||||
if (map_iter != m_free_cache.end())
|
||||
{
|
||||
if (!map_iter->second.empty())
|
||||
{
|
||||
ret = map_iter->second.back();
|
||||
map_iter->second.pop_back();
|
||||
m_reserved_cache[ret] = size;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
Process::ReservationCache::CheckModID()
|
||||
{
|
||||
if (m_mod_id != m_process.GetModID())
|
||||
{
|
||||
// wipe all our caches, they're invalid
|
||||
m_reserved_cache.clear();
|
||||
m_free_cache.clear();
|
||||
m_mod_id = m_process.GetModID();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue