Change regcache list to be an hash map
[deliverable/binutils-gdb.git] / gdb / regcache.c
index 2dfe8eaf5feb13b23bebbd8323c2fb6bd00d34da..87d95010e3bd37b2b3027dab37464c2cf9937573 100644 (file)
@@ -318,26 +318,65 @@ reg_buffer::assert_regnum (int regnum) const
    recording if the register values have been changed (eg. by the
    user).  Therefore all registers must be written back to the
    target when appropriate.  */
-std::forward_list<regcache *> regcache::current_regcache;
+
+/* Key for the hash map keeping the regcaches.  */
+
+struct target_ptid_arch
+{
+  target_ptid_arch (process_stratum_target *target, ptid_t ptid, gdbarch *arch)
+    : target (target), ptid (ptid), arch (arch)
+  {}
+
+  process_stratum_target *target;
+  ptid_t ptid;
+  gdbarch *arch;
+
+  bool operator== (const target_ptid_arch &other) const
+  {
+    return (this->target == other.target
+           && this->ptid == other.ptid
+           && this->arch == other.arch);
+  }
+};
+
+/* Hash function for target_ptid_arch.  */
+
+struct hash_target_ptid_arch
+{
+  size_t operator() (const target_ptid_arch &val) const
+  {
+    hash_ptid h_ptid;
+    std::hash<long> h_long;
+    return h_ptid (val.ptid) + h_long ((long) val.arch);
+  }
+};
+
+using target_ptid_arch_regcache_map
+  = std::unordered_map<target_ptid_arch, regcache *, hash_target_ptid_arch>;
+
+/* Hash map containing the regcaches.  */
+
+static target_ptid_arch_regcache_map the_regcaches;
 
 struct regcache *
 get_thread_arch_aspace_regcache (process_stratum_target *target,
-                                ptid_t ptid, struct gdbarch *gdbarch,
+                                ptid_t ptid, gdbarch *arch,
                                 struct address_space *aspace)
 {
   gdb_assert (target != nullptr);
 
-  for (const auto &regcache : regcache::current_regcache)
-    if (regcache->target () == target
-       && regcache->ptid () == ptid
-       && regcache->arch () == gdbarch)
-      return regcache;
-
-  regcache *new_regcache = new regcache (target, gdbarch, aspace);
+  /* Look up a regcache for this (target, ptid, arch).  */
+  target_ptid_arch key (target, ptid, arch);
+  auto it = the_regcaches.find (key);
+  if (it != the_regcaches.end ())
+    return it->second;
 
-  regcache::current_regcache.push_front (new_regcache);
+  /* It does not exist, create it.  */
+  regcache *new_regcache = new regcache (target, arch, aspace);
   new_regcache->set_ptid (ptid);
 
+  the_regcaches[key] = new_regcache;
+
   return new_regcache;
 }
 
@@ -413,13 +452,32 @@ regcache_observer_target_changed (struct target_ops *target)
 
 /* Update global variables old ptids to hold NEW_PTID if they were
    holding OLD_PTID.  */
-void
-regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
+static void
+regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
 {
-  for (auto &regcache : regcache::current_regcache)
+  std::vector<target_ptid_arch> keys_to_update;
+
+  /* Find all the regcaches to updates.  */
+  for (auto &pair : the_regcaches)
     {
-      if (regcache->ptid () == old_ptid)
-       regcache->set_ptid (new_ptid);
+      regcache *rc = pair.second;
+      if (rc->ptid () == old_ptid)
+       keys_to_update.push_back (pair.first);
+    }
+
+  for (const target_ptid_arch &old_key : keys_to_update)
+    {
+      /* Get the regcache, delete the hash map entry.  */
+      auto it = the_regcaches.find (old_key);
+      gdb_assert (it != the_regcaches.end ());
+      regcache *rc = it->second;
+
+      the_regcaches.erase (it);
+
+      /* Insert the regcache back, with an updated key.  */
+      target_ptid_arch new_key (rc->target (), new_ptid, rc->arch ());
+      rc->set_ptid (new_ptid);
+      the_regcaches[new_key] = rc;
     }
 }
 
@@ -437,20 +495,22 @@ regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
 void
 registers_changed_ptid (process_stratum_target *target, ptid_t ptid)
 {
-  for (auto oit = regcache::current_regcache.before_begin (),
-        it = std::next (oit);
-       it != regcache::current_regcache.end ();
-       )
+  /* If we have a non-minus_one_ptid, we must have a non-NULL target.  */
+  if (ptid != minus_one_ptid)
+    gdb_assert (target != nullptr);
+
+  for (auto iter = the_regcaches.begin (); iter != the_regcaches.end (); )
     {
-      struct regcache *regcache = *it;
-      if ((target == nullptr || regcache->target () == target)
-         && regcache->ptid ().matches (ptid))
+      regcache *rc = iter->second;
+
+      if ((target == nullptr || rc->target () == target)
+         && rc->ptid ().matches (ptid))
        {
-         delete regcache;
-         it = regcache::current_regcache.erase_after (oit);
+         delete iter->second;
+         iter = the_regcaches.erase (iter);
        }
       else
-       oit = it++;
+       ++iter;
     }
 
   if ((target == nullptr || current_thread_target == target)
@@ -1423,8 +1483,7 @@ public:
   static size_t
   current_regcache_size ()
   {
-    return std::distance (regcache::current_regcache.begin (),
-                         regcache::current_regcache.end ());
+    return the_regcaches.size ();
   }
 };
 
@@ -1861,8 +1920,7 @@ _initialize_regcache (void)
     = gdbarch_data_register_post_init (init_regcache_descr);
 
   gdb::observers::target_changed.attach (regcache_observer_target_changed);
-  gdb::observers::thread_ptid_changed.attach
-    (regcache::regcache_thread_ptid_changed);
+  gdb::observers::thread_ptid_changed.attach (regcache_thread_ptid_changed);
 
   add_com ("flushregs", class_maintenance, reg_flush_command,
           _("Force gdb to flush its register cache (maintainer command)."));
This page took 0.02459 seconds and 4 git commands to generate.