Bug 1294627 - Enhance gdb pretty printer for nsTHashtable to pierce alias templates and handle when it's used as a hashset, like for ManagedTemplate. r=tromey
authorAndrew Sutherland <asutherland@asutherland.org>
Fri, 12 Aug 2016 02:08:30 -0400
changeset 309329 e002e37dff5b3a6f156d6d433439d64521a92007
parent 309328 6accce4abaadad6c8de1de4da908132aad1f196e
child 309330 ae30528224ba5e6a125f21b037f7906a0f478fde
push id30561
push userkwierso@gmail.com
push dateMon, 15 Aug 2016 21:20:49 +0000
treeherdermozilla-central@91a319101587 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstromey
bugs1294627
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1294627 - Enhance gdb pretty printer for nsTHashtable to pierce alias templates and handle when it's used as a hashset, like for ManagedTemplate. r=tromey
python/gdbpp/gdbpp/thashtable.py
--- a/python/gdbpp/gdbpp/thashtable.py
+++ b/python/gdbpp/gdbpp/thashtable.py
@@ -10,16 +10,23 @@ from gdbpp import GeckoPrettyPrinter
 
 def walk_template_to_given_base(value, desired_tag_prefix):
     '''Given a value of some template subclass, walk up its ancestry until we
     hit the desired type, then return the appropriate value (which will then
     have that type).
     '''
     # Base case
     t = value.type
+    # It's possible that we're dealing with an alias template that looks like:
+    #   template<typename Protocol>
+    #   using ManagedContainer = nsTHashtable<nsPtrHashKey<Protocol>>;
+    # In which case we want to strip the indirection, and strip_typedefs()
+    # accomplishes this.  (Disclaimer: I tried it and it worked and it didn't
+    # break my other use cases, if things start exploding, do reconsider.)
+    t = t.strip_typedefs()
     if t.tag.startswith(desired_tag_prefix):
         return value
     for f in t.fields():
         # we only care about the inheritance hierarchy
         if not f.is_base_class:
             continue
         # This is the answer or something we're going to need to recurse into.
         fv = value[f]
@@ -43,40 +50,55 @@ def walk_template_to_given_base(value, d
 @GeckoPrettyPrinter('nsTHashtable', '^nsTHashtable<.*>$')
 class thashtable_printer(object):
     def __init__(self, outer_value):
         self.outermost_type = outer_value.type
 
         value = walk_template_to_given_base(outer_value, 'nsTHashtable<')
         self.value = value
 
-        # This will be the nsBaseHashtableET.
         self.entry_type = value.type.template_argument(0)
+
+        # -- Determine whether we're a hashTABLE or a hashSET
+        # If we're a table, the entry type will be a nsBaseHashtableET template.
+        # If we're a set, it will be something like nsPtrHashKey.
+        #
+        # So, assume we're a set if we're not nsBaseHashtableET<
+        # (It should ideally also be true that the type ends with HashKey, but
+        # since nsBaseHashtableET causes us to assume "mData" exists, let's
+        # pivot based on that.)
+        self.is_table = self.entry_type.tag.startswith('nsBaseHashtableET<')
+
         # While we know that it has a field `mKeyHash` for the hash-code and
-        # book-keeping, and a DataType field mData for the value, the key field
-        # frustratingly varies by key type.
+        # book-keeping, and a DataType field mData for the value (if we're a
+        # table), the key field frustratingly varies by key type.
         #
         # So we want to walk its key type to figure out the field name.  And we
         # do mean field name.  The field object is no good for subscripting the
         # value unless the field was directly owned by that value's type.  But
         # by using a string name, we save ourselves all that fanciness.
-        key_type = self.entry_type.template_argument(0)
+
+        if self.is_table:
+            # For nsBaseHashtableET<KeyClass, DataType>, we want the KeyClass
+            key_type = self.entry_type.template_argument(0)
+        else:
+            # If we're a set, our entry type is the key class already!
+            key_type = self.entry_type
         self.key_field_name = None
         for f in key_type.fields():
             # No need to traverse up the type hierarchy...
             if f.is_base_class:
                 continue
             # ...just to skip the fields we know exist...
             if f.name == 'mKeyHash' or f.name == 'mData':
                 continue
             # ...and assume the first one we find is the key.
             self.key_field_name = f.name
             break
 
-
     def children(self):
         table = self.value['mTable']
         # Number of entries
         entryCount = table['mEntryCount']
         # Pierce generation-tracking EntryStore class to get at buffer.  The
         # class instance always exists, but this char* may be null.
         store = table['mEntryStore']['mEntryStore']
 
@@ -84,17 +106,22 @@ class thashtable_printer(object):
 
         pEntry = store.cast(self.entry_type.pointer())
         for i in range(0, int(entryCount)):
             entry = (pEntry + i).dereference()
             # An mKeyHash of 0 means empty, 1 means deleted sentinel, so skip
             # if that's the case.
             if entry['mKeyHash'] <= 1:
                 continue
+
             yield ('%d' % i, entry[key_field_name])
-            yield ('%d' % i, entry['mData'])
+            if self.is_table:
+                yield ('%d' % i, entry['mData'])
 
     def to_string(self):
         # The most specific template type is the most interesting.
         return str(self.outermost_type)
 
     def display_hint(self):
-        return 'map'
+        if self.is_table:
+            return 'map'
+        else:
+            return 'array'