summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Marchi <simon.marchi@polymtl.ca>2020-07-30 14:05:03 -0400
committerSimon Marchi <simon.marchi@efficios.com>2020-08-05 15:40:21 -0400
commitfe0e47ac81ddf56f54f389f397e39be85b0567d1 (patch)
treeed5c47502c3bb6c815af44b3bd0b81160eb71bcd
parent5672720dd1ab2d4e9bf7a7c2f86599df07afa96c (diff)
downloadbinutils-gdb-users/simark/regcache-multimap-v2.tar.gz
Change-Id: I008ddd9a1ef773a8d17e439d24d75d37bbf1a076
-rw-r--r--gdb/regcache.c146
1 files changed, 72 insertions, 74 deletions
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 8ca59fd2bec..394efdfe127 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -313,41 +313,17 @@ reg_buffer::assert_regnum (int regnum) const
gdb_assert (regnum < gdbarch_num_regs (arch ()));
}
-/* Key type for target_ptid_regcache_map. */
+/* Type to map a ptid to a list of regcaches (one thread may have multiple
+ regcaches, associated to different gdbarches). */
-struct target_ptid
-{
- target_ptid (process_stratum_target *target, ptid_t ptid)
- : target (target), ptid (ptid)
- {}
-
- process_stratum_target *target;
- ptid_t ptid;
-
- bool operator== (const target_ptid &other) const
- {
- return (this->target == other.target
- && this->ptid == other.ptid);
- }
-};
-
-/* Hash function for target_ptid. */
+using ptid_regcache_map
+ = std::unordered_multimap<ptid_t, regcache_up, hash_ptid>;
-struct hash_target_ptid
-{
- size_t operator() (const target_ptid &val) const
- {
- std::hash<process_stratum_target *> h_ptr;
- hash_ptid h_ptid;
-
- return h_ptr (val.target) + h_ptid (val.ptid);
- }
-};
-
-/* Type to map a (target, ptid) tuple to a regcache. */
+/* Type to map a target to a ptid_regcache_map, holding the regcaches for the
+ threads defined by that target. */
using target_ptid_regcache_map
- = std::unordered_multimap<target_ptid, regcache_up, hash_target_ptid>;
+ = std::unordered_map<process_stratum_target *, ptid_regcache_map>;
/* Global structure containing the existing regcaches. */
@@ -364,9 +340,11 @@ get_thread_arch_aspace_regcache (process_stratum_target *target,
{
gdb_assert (target != nullptr);
- /* Look up the regcache for this (target, ptid, arch). */
- target_ptid key (target, ptid);
- auto range = regcaches.equal_range (key);
+ /* Find the ptid -> regcache map for this target. */
+ auto &ptid_regc_map = regcaches[target];
+
+ /* Check first if a regcache for this arch already exists. */
+ auto range = ptid_regc_map.equal_range (ptid);
for (auto it = range.first; it != range.second; it++)
{
if (it->second->arch () == arch)
@@ -374,11 +352,9 @@ get_thread_arch_aspace_regcache (process_stratum_target *target,
}
/* It does not exist, create it. */
- regcache *new_regcache = new regcache (target, arch, aspace);
+ regcache *new_regcache (new regcache (target, arch, aspace));
new_regcache->set_ptid (ptid);
-
- /* Insert it in the map. */
- regcaches.insert (std::make_pair (key, new_regcache));
+ ptid_regc_map.insert (std::make_pair (ptid, new_regcache));
return new_regcache;
}
@@ -458,19 +434,22 @@ static void
regcache_thread_ptid_changed (process_stratum_target *target,
ptid_t old_ptid, ptid_t new_ptid)
{
- target_ptid old_key (target, old_ptid);
- target_ptid new_key (target, new_ptid);
+ auto ptid_regc_map_it = regcaches.find (target);
- auto range = regcaches.equal_range (old_key);
+ if (ptid_regc_map_it == regcaches.end ())
+ return;
+
+ auto &ptid_regc_map = ptid_regc_map_it->second;
+ auto range = ptid_regc_map.equal_range (old_ptid);
for (auto it = range.first; it != range.second;)
{
regcache_up rc = std::move (it->second);
rc->set_ptid (new_ptid);
- /* Remove old before inserting new, to avoid rehashing, which would
- invalidate iterators. */
- it = regcaches.erase (it);
- regcaches.insert (std::make_pair (new_key, std::move (rc)));
+ /* Remove old before inserting new, to avoid rehashing,
+ which would invalidate iterators. */
+ it = ptid_regc_map.erase (it);
+ ptid_regc_map.insert (std::make_pair (new_ptid, std::move (rc)));
}
}
@@ -495,29 +474,31 @@ registers_changed_ptid (process_stratum_target *target, ptid_t ptid)
gdb_assert (ptid == minus_one_ptid);
/* Delete all the regcaches. */
- regcaches.clear ();
+ for (auto &pair : regcaches)
+ pair.second.clear ();
}
else if (ptid != minus_one_ptid)
{
/* Non-NULL target and non-minus_one_ptid, delete all regcaches belonging
- to this (TARGET, PTID). */
- regcaches.erase (target_ptid (target, ptid));
+ to this (TARGET, PTID). */
+ auto ptid_regc_map_it = regcaches.find (target);
+ if (ptid_regc_map_it != regcaches.end ())
+ {
+ auto &ptid_regc_map = ptid_regc_map_it->second;
+ ptid_regc_map.erase (ptid);
+ }
}
else
{
- /* Non-NULL target and minus_one_ptid, delete all regcaches associated
- to this target.
-
- We unfortunately don't have an efficient way to do this. Fall back
- to iterating all items to find all those belonging to TARGET. */
- for (auto it = regcaches.begin (); it != regcaches.end ();)
- {
- if (it->second->target () == target)
- it = regcaches.erase (it);
- else
- it++;
- }
- }
+ /* Non-NULL target and minus_one_ptid, delete all regcaches
+ associated to this target. */
+ auto ptid_regc_map_it = regcaches.find (target);
+ if (ptid_regc_map_it != regcaches.end ())
+ {
+ auto &ptid_regc_map = ptid_regc_map_it->second;
+ ptid_regc_map.clear ();
+ }
+ }
if ((target == nullptr || current_thread_target == target)
&& current_thread_ptid.matches (ptid))
@@ -1498,6 +1479,18 @@ register_dump::dump (ui_file *file)
namespace selftests {
+static size_t
+regcaches_size ()
+{
+ size_t size = 0;
+ for (auto it = regcaches.begin (); it != regcaches.end (); ++it)
+ {
+ auto &ptid_regc_map = it->second;
+ size += ptid_regc_map.size ();
+ }
+ return size;
+}
+
/* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */
static void
@@ -1517,7 +1510,7 @@ static void
regcaches_test (void)
{
/* It is empty at the start. */
- SELF_CHECK (regcaches.size () == 0);
+ SELF_CHECK (regcaches_size () == 0);
ptid_t ptid1 (1), ptid2 (2), ptid3 (3);
@@ -1529,52 +1522,52 @@ regcaches_test (void)
test_get_thread_arch_aspace_regcache (&test_target1, ptid1,
target_gdbarch (),
NULL);
- SELF_CHECK (regcaches.size () == 1);
+ SELF_CHECK (regcaches_size () == 1);
/* Get regcache from (target1,ptid2), a new regcache is added to
REGCACHES. */
test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
target_gdbarch (),
NULL);
- SELF_CHECK (regcaches.size () == 2);
+ SELF_CHECK (regcaches_size () == 2);
/* Get regcache from (target1,ptid3), a new regcache is added to
REGCACHES. */
test_get_thread_arch_aspace_regcache (&test_target1, ptid3,
target_gdbarch (),
NULL);
- SELF_CHECK (regcaches.size () == 3);
+ SELF_CHECK (regcaches_size () == 3);
/* Get regcache from (target1,ptid2) again, nothing is added to
REGCACHES. */
test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
target_gdbarch (),
NULL);
- SELF_CHECK (regcaches.size () == 3);
+ SELF_CHECK (regcaches_size () == 3);
/* Get regcache from (target2,ptid2), a new regcache is added to
REGCACHES, since this time we're using a different target. */
test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
target_gdbarch (),
NULL);
- SELF_CHECK (regcaches.size () == 4);
+ SELF_CHECK (regcaches_size () == 4);
/* Mark that (target1,ptid2) changed. The regcache of (target1,
ptid2) should be removed from REGCACHES. */
registers_changed_ptid (&test_target1, ptid2);
- SELF_CHECK (regcaches.size () == 3);
+ SELF_CHECK (regcaches_size () == 3);
/* Get the regcache from (target2,ptid2) again, confirming the
registers_changed_ptid call above did not delete it. */
test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
target_gdbarch (),
NULL);
- SELF_CHECK (regcaches.size () == 3);
+ SELF_CHECK (regcaches_size () == 3);
/* Confirm that marking all regcaches of all targets as changed
clears REGCACHES. */
registers_changed_ptid (nullptr, minus_one_ptid);
- SELF_CHECK (regcaches.size () == 0);
+ SELF_CHECK (regcaches_size () == 0);
}
class target_ops_no_register : public test_target_ops
@@ -1911,11 +1904,16 @@ regcache_thread_ptid_changed ()
/* Return the count of regcaches for (TARGET, PTID) in REGCACHES. */
auto regcache_count = [] (process_stratum_target *target, ptid_t ptid)
+ -> int
{
- target_ptid key (target, ptid);
-
- auto range = regcaches.equal_range (key);
- return std::distance (range.first, range.second);
+ auto ptid_regc_map_it = regcaches.find (target);
+ if (ptid_regc_map_it != regcaches.end ())
+ {
+ auto &ptid_regc_map = ptid_regc_map_it->second;
+ auto range = ptid_regc_map.equal_range (ptid);
+ return std::distance (range.first, range.second);
+ }
+ return 0;
};
gdb_assert (regcaches.size () == 2);