From ef6e51ee3c8ebc8a2c7c4edef33607c0907c1b32 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Thu, 20 Dec 2012 13:24:45 -0800 Subject: [PATCH] Bug 822563: Pretty-print references to JSObject and its subclasses. r=sfink --- js/src/gdb/mozilla/JSObject.py | 14 ++++-- js/src/gdb/mozilla/prettyprinters.py | 59 ++++++++++++++++++------- js/src/gdb/tests/test-JSObject.cpp | 6 ++- js/src/gdb/tests/test-JSObject.py | 5 +++ js/src/gdb/tests/test-prettyprinters.py | 4 ++ 5 files changed, 66 insertions(+), 22 deletions(-) diff --git a/js/src/gdb/mozilla/JSObject.py b/js/src/gdb/mozilla/JSObject.py index f0f86bdffb96..9504caea3071 100644 --- a/js/src/gdb/mozilla/JSObject.py +++ b/js/src/gdb/mozilla/JSObject.py @@ -3,7 +3,7 @@ import gdb import mozilla.JSString import mozilla.prettyprinters as prettyprinters -from mozilla.prettyprinters import ptr_pretty_printer +from mozilla.prettyprinters import ptr_pretty_printer, ref_pretty_printer from mozilla.Root import deref prettyprinters.clear_module_printers(__name__) @@ -19,9 +19,9 @@ class JSObjectTypeCache(object): # JSFunction has JSObject as a base class. @ptr_pretty_printer('JSObject') -class JSObjectPtr(prettyprinters.Pointer): +class JSObjectPtrOrRef(prettyprinters.Pointer): def __init__(self, value, cache): - super(JSObjectPtr, self).__init__(value, cache) + super(JSObjectPtrOrRef, self).__init__(value, cache) if not cache.mod_JSObject: cache.mod_JSObject = JSObjectTypeCache(value, cache) self.otc = cache.mod_JSObject @@ -34,9 +34,15 @@ class JSObjectPtr(prettyprinters.Pointer): is_delegate = bool(flags & self.otc.flag_DELEGATE) name = None if class_name == 'Function': - function = self.value.cast(self.otc.func_ptr_type) + if self.value.type.code == gdb.TYPE_CODE_PTR: + function = self.value.cast(self.otc.func_ptr_type) + elif self.value.type.code == gdb.TYPE_CODE_REF: + function = self.value.address.cast(self.otc.func_ptr_type) atom = deref(function['atom_']) name = str(atom) if atom else '' return '[object %s%s]%s' % (class_name, ' ' + name if name else '', ' delegate' if is_delegate else '') + +@ref_pretty_printer('JSObject') +def JSObjectRef(value, cache): return JSObjectPtrOrRef(value, cache) diff --git a/js/src/gdb/mozilla/prettyprinters.py b/js/src/gdb/mozilla/prettyprinters.py index 0a0524deafef..796318326202 100644 --- a/js/src/gdb/mozilla/prettyprinters.py +++ b/js/src/gdb/mozilla/prettyprinters.py @@ -45,6 +45,20 @@ def ptr_pretty_printer(type_name): return fn return add +# a dictionary mapping gdb.Type tags to pretty-printer functions for +# references to that type. +ref_printers_by_tag = {} + +# A decorator: add the decoratee as a pretty-printer lookup function for +# references to instances of types named |type_name|. +def ref_pretty_printer(type_name): + def add(fn): + check_for_reused_pretty_printer(fn) + add_to_subprinter_list(fn, "ref-to-" + type_name) + ref_printers_by_tag[type_name] = fn + return fn + return add + # a dictionary mapping the template name portion of gdb.Type tags to # pretty-printer functions for instantiations of that template. template_printers_by_tag = {} @@ -83,7 +97,8 @@ def pretty_printer_for_regexp(pattern, name): # # clear_module_printers(__name__) def clear_module_printers(module_name): - global printers_by_tag, ptr_printers_by_tag, template_printers_by_tag, printers_by_regexp + global printers_by_tag, ptr_printers_by_tag, ref_printers_by_tag + global template_printers_by_tag, printers_by_regexp # Remove all pretty-printers defined in the module named |module_name| # from d. @@ -101,6 +116,7 @@ def clear_module_printers(module_name): clear_dictionary(printers_by_tag) clear_dictionary(ptr_printers_by_tag) + clear_dictionary(ref_printers_by_tag) clear_dictionary(template_printers_by_tag) # Iterate over printers_by_regexp, deleting entries from the given module. @@ -226,28 +242,31 @@ def lookup_for_objfile(objfile): return f(value, cache) return None + def check_table_by_type_name(table, t): + if t.code == gdb.TYPE_CODE_TYPEDEF: + return check_table(table, str(t)) + elif t.code == gdb.TYPE_CODE_STRUCT and t.tag: + return check_table(table, t.tag) + else: + return None + for t in implemented_types(value.type): if t.code == gdb.TYPE_CODE_PTR: for t2 in implemented_types(t.target()): - if t2.code == gdb.TYPE_CODE_TYPEDEF: - p = check_table(ptr_printers_by_tag, str(t2)) - elif t2.code == gdb.TYPE_CODE_STRUCT and t2.tag: - p = check_table(ptr_printers_by_tag, t2.tag) - else: - p = None + p = check_table_by_type_name(ptr_printers_by_tag, t2) + if p: return p + elif t.code == gdb.TYPE_CODE_REF: + for t2 in implemented_types(t.target()): + p = check_table_by_type_name(ref_printers_by_tag, t2) if p: return p else: - if t.code == gdb.TYPE_CODE_TYPEDEF: - p = check_table(printers_by_tag, str(t)) - elif t.code == gdb.TYPE_CODE_STRUCT and t.tag: + p = check_table_by_type_name(printers_by_tag, t) + if p: return p + if t.code == gdb.TYPE_CODE_STRUCT and t.tag: m = template_regexp.match(t.tag) if m: p = check_table(template_printers_by_tag, m.group(1)) - else: - p = check_table(printers_by_tag, t.tag) - else: - p = None - if p: return p + if p: return p # Failing that, look for a printer in printers_by_regexp. We have # to scan the whole list, so regexp printers should be used @@ -275,6 +294,8 @@ def lookup_for_objfile(objfile): # pointers, by declining to construct a pretty-printer for them at all. # Derived classes may simply assume that self.value is non-null. # +# To help share code, this class can also be used with reference types. +# # This class provides the following methods, which subclasses are free to # override: # @@ -291,7 +312,8 @@ def lookup_for_objfile(objfile): class Pointer(object): def __new__(cls, value, cache): # Don't try to provide pretty-printers for NULL pointers. - if value == 0: return None + if value.type.code == gdb.TYPE_CODE_PTR and value == 0: + return None return super(Pointer, cls).__new__(cls) def __init__(self, value, cache): @@ -301,7 +323,10 @@ class Pointer(object): def to_string(self): # See comment above. assert not hasattr(self, 'display_hint') or self.display_hint() != 'string' - address = self.value.cast(self.cache.void_ptr_t) + if self.value.type.code == gdb.TYPE_CODE_PTR: + address = self.value.cast(self.cache.void_ptr_t) + elif self.value.type.code == gdb.TYPE_CODE_REF: + address = '@' + str(self.value.address.cast(self.cache.void_ptr_t)) try: summary = self.summary() except gdb.MemoryError as r: diff --git a/js/src/gdb/tests/test-JSObject.cpp b/js/src/gdb/tests/test-JSObject.cpp index 1d7ce07718c3..d02dc4b53a6f 100644 --- a/js/src/gdb/tests/test-JSObject.cpp +++ b/js/src/gdb/tests/test-JSObject.cpp @@ -10,6 +10,9 @@ FRAGMENT(JSObject, simple) { js::Rooted funcPtr(cx, JS_NewFunction(cx, (JSNative) 1, 0, 0, JS_GetGlobalObject(cx), "formFollows")); + JSObject &plainRef = *plain; + JSFunction &funcRef = *funcPtr; + breakpoint(); (void) glob; @@ -17,6 +20,8 @@ FRAGMENT(JSObject, simple) { (void) func; (void) anon; (void) funcPtr; + (void) plainRef; + (void) funcRef; } FRAGMENT(JSObject, null) { @@ -26,4 +31,3 @@ FRAGMENT(JSObject, null) { (void) null; } - diff --git a/js/src/gdb/tests/test-JSObject.py b/js/src/gdb/tests/test-JSObject.py index ddd357b91724..35122e14a5d4 100644 --- a/js/src/gdb/tests/test-JSObject.py +++ b/js/src/gdb/tests/test-JSObject.py @@ -1,6 +1,8 @@ # Printing JSObjects. assert_subprinter_registered('SpiderMonkey', 'ptr-to-JSObject') +assert_subprinter_registered('SpiderMonkey', 'ref-to-JSObject') + run_fragment('JSObject.simple') # These patterns look a little strange because of prolog.py's 'set print @@ -13,3 +15,6 @@ assert_pretty('plain', '(JSObject *) [object Object]') assert_pretty('func', '(JSObject *) [object Function "dys"]') assert_pretty('anon', '(JSObject *) [object Function ]') assert_pretty('funcPtr', '(JSFunction *) [object Function "formFollows"]') + +assert_pretty('plainRef', '(JSObject &) @ [object Object]') +assert_pretty('funcRef', '(JSFunction &) @ [object Function "formFollows"]') diff --git a/js/src/gdb/tests/test-prettyprinters.py b/js/src/gdb/tests/test-prettyprinters.py index f36eb450a391..9c380fdda8f8 100644 --- a/js/src/gdb/tests/test-prettyprinters.py +++ b/js/src/gdb/tests/test-prettyprinters.py @@ -16,3 +16,7 @@ assert_eq(implemented_type_names('e'), ['E', 'C', 'D']) assert_eq(implemented_type_names('e_'), ['E_', 'E', 'C', 'D']) assert_eq(implemented_type_names('f'), ['F', 'C', 'D']) assert_eq(implemented_type_names('h'), ['H', 'F', 'G', 'C', 'D']) + +# Check that our pretty-printers aren't interfering with printing other types. +assert_pretty('10', '10') +assert_pretty('(void*) 0', '') # Because of 'set print address off'