summaryrefslogtreecommitdiffstats
path: root/js/src/gdb/mozilla/Root.py
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/gdb/mozilla/Root.py')
-rw-r--r--js/src/gdb/mozilla/Root.py90
1 files changed, 90 insertions, 0 deletions
diff --git a/js/src/gdb/mozilla/Root.py b/js/src/gdb/mozilla/Root.py
new file mode 100644
index 000000000..4656a3852
--- /dev/null
+++ b/js/src/gdb/mozilla/Root.py
@@ -0,0 +1,90 @@
+# Pretty-printers and utilities for SpiderMonkey rooting templates:
+# Rooted, Handle, MutableHandle, etc.
+
+import mozilla.prettyprinters
+from mozilla.prettyprinters import pretty_printer, template_pretty_printer
+
+# Forget any printers from previous loads of this module.
+mozilla.prettyprinters.clear_module_printers(__name__)
+
+# Common base class for all the rooting template pretty-printers. All these
+# templates have one member holding the referent (or a pointer to it), so
+# there's not much to it.
+class Common(object):
+ # The name of the template member holding the referent.
+ member = 'ptr'
+
+ # If True, this is a handle type, and should be dereferenced. If False,
+ # the template member holds the referent directly.
+ handle = False
+
+ # If True, we should strip typedefs from our referent type. (Rooted<T>
+ # uses template magic that gives the referent a noisy type.)
+ strip_typedefs = False
+
+ # Initialize a pretty-printer for |value|, using |cache|.
+ #
+ # If given, |content_printer| is a pretty-printer constructor to use for
+ # this handle/root/etc.'s referent. Usually, we can just omit this argument
+ # and let GDB choose a pretty-printer for the referent given its type, but
+ # when the referent is a typedef of an integral type (say, |jsid| in a
+ # non-|DEBUG| build), the GNU toolchain (at least) loses the typedef name,
+ # and all we know about the referent is its fundamental integer type ---
+ # |JS::Rooted<jsid>|, for example, appears in GDB as |JS::Rooted<long>| ---
+ # and we are left with no way to choose a meaningful pretty-printer based on
+ # the type of the referent alone. However, because we know that the only
+ # integer type for which |JS::Rooted| is likely to be instantiated is
+ # |jsid|, we *can* register a pretty-printer constructor for the full
+ # instantiation |JS::Rooted<long>|. That constructor creates a |JS::Rooted|
+ # pretty-printer, and explicitly specifies the constructor for the referent,
+ # using this initializer's |content_printer| argument.
+ def __init__(self, value, cache, content_printer=None):
+ self.value = value
+ self.cache = cache
+ self.content_printer = content_printer
+ def to_string(self):
+ ptr = self.value[self.member]
+ if self.handle:
+ ptr = ptr.dereference()
+ if self.strip_typedefs:
+ ptr = ptr.cast(ptr.type.strip_typedefs())
+ if self.content_printer:
+ return self.content_printer(ptr, self.cache).to_string()
+ else:
+ # As of 2012-11, GDB suppresses printing pointers in replacement
+ # values; see http://sourceware.org/ml/gdb/2012-11/msg00055.html
+ # That means that simply returning the 'ptr' member won't work.
+ # Instead, just invoke GDB's formatter ourselves.
+ return str(ptr)
+
+@template_pretty_printer("JS::Rooted")
+class Rooted(Common):
+ strip_typedefs = True
+
+@template_pretty_printer("JS::Handle")
+class Handle(Common):
+ handle = True
+
+@template_pretty_printer("JS::MutableHandle")
+class MutableHandle(Common):
+ handle = True
+
+@template_pretty_printer("js::BarrieredBase")
+class BarrieredBase(Common):
+ member = 'value'
+
+# Return the referent of a HeapPtr, Rooted, or Handle.
+def deref(root):
+ tag = root.type.strip_typedefs().tag
+ if not tag:
+ raise TypeError("Can't dereference type with no structure tag: %s" % (root.type,))
+ elif tag.startswith('js::HeapPtr<'):
+ return root['value']
+ elif tag.startswith('JS::Rooted<'):
+ return root['ptr']
+ elif tag.startswith('JS::Handle<'):
+ return root['ptr']
+ elif tag.startswith('js::GCPtr<'):
+ return root['value']
+ else:
+ raise NotImplementedError("Unrecognized tag: " + tag)