Source code

Revision control

Copy as Markdown

Other Tools

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at
# Pretty-printers for GCCellPtr values.
import gdb
import mozilla.prettyprinters
from mozilla.prettyprinters import pretty_printer
# Forget any printers from previous loads of this module.
# Cache information about the types for this objfile.
class GCCellPtrTypeCache(object):
def __init__(self, cache):
self.TraceKind_t = gdb.lookup_type("JS::TraceKind")
self.AllocKind_t = gdb.lookup_type("js::gc::AllocKind")
self.Arena_t = gdb.lookup_type("js::gc::Arena")
self.Cell_t = gdb.lookup_type("js::gc::Cell")
self.TenuredCell_t = gdb.lookup_type("js::gc::TenuredCell")
trace_kinds = gdb.types.make_enum_dict(self.TraceKind_t)
alloc_kinds = gdb.types.make_enum_dict(self.AllocKind_t)
def trace_kind(k):
return trace_kinds["JS::TraceKind::" + k]
def alloc_kind(k):
return alloc_kinds["js::gc::AllocKind::" + k]
# Build a mapping from TraceKind enum values to the types they denote.
trace_map = {
# Inline types.
"Object": "JSObject",
"BigInt": "JS::BigInt",
"String": "JSString",
"Symbol": "JS::Symbol",
"Shape": "js::Shape",
"BaseShape": "js::BaseShape",
"Null": "std::nullptr_t",
# Out-of-line types.
"JitCode": "js::jit::JitCode",
"Script": "js::BaseScript",
"Scope": "js::Scope",
"RegExpShared": "js::RegExpShared",
"GetterSetter": "js::GetterSetter",
"PropMap": "js::PropMap",
# Map from AllocKind to TraceKind for out-of-line types.
alloc_map = {
"JITCODE": "JitCode",
"SCRIPT": "Script",
"SCOPE": "Scope",
"REGEXP_SHARED": "RegExpShared",
"GETTER_SETTER": "GetterSetter",
"DICT_PROP_MAP": "PropMap",
self.trace_kind_to_type = {
trace_kind(k): gdb.lookup_type(v) for k, v in trace_map.items()
self.alloc_kind_to_trace_kind = {
alloc_kind(k): trace_kind(v) for k, v in alloc_map.items()
self.Null = trace_kind("Null")
self.tracekind_mask = gdb.parse_and_eval("JS::OutOfLineTraceKindMask")
self.arena_mask = gdb.parse_and_eval("js::gc::ArenaMask")
class GCCellPtr(object):
def __init__(self, value, cache):
self.value = value
if not cache.mod_GCCellPtr:
cache.mod_GCCellPtr = GCCellPtrTypeCache(cache)
self.cache = cache
def to_string(self):
ptr = self.value["ptr"]
kind = ptr & self.cache.mod_GCCellPtr.tracekind_mask
if kind == self.cache.mod_GCCellPtr.Null:
return "JS::GCCellPtr(nullptr)"
if kind == self.cache.mod_GCCellPtr.tracekind_mask:
# Out-of-line trace kinds.
# Compute the underlying type for out-of-line kinds by
# reimplementing the GCCellPtr::outOfLineKind() method.
# The extra casts below are only present to make it easier to
# compare this code against the C++ implementation.
# GCCellPtr::asCell()
cell_ptr = ptr & ~self.cache.mod_GCCellPtr.tracekind_mask
cell = cell_ptr.reinterpret_cast(self.cache.mod_GCCellPtr.Cell_t.pointer())
# Cell::asTenured()
tenured = cell.cast(self.cache.mod_GCCellPtr.TenuredCell_t.pointer())
# TenuredCell::arena()
addr = int(tenured)
arena_ptr = addr & ~self.cache.mod_GCCellPtr.arena_mask
arena = arena_ptr.reinterpret_cast(
# Arena::getAllocKind()
alloc_kind = arena["allocKind"].cast(self.cache.mod_GCCellPtr.AllocKind_t)
alloc_idx = int(
# Map the AllocKind to a TraceKind.
kind = self.cache.mod_GCCellPtr.alloc_kind_to_trace_kind[alloc_idx]
type_name = self.cache.mod_GCCellPtr.trace_kind_to_type[int(kind)]
return "JS::GCCellPtr(({}*) {})".format(
type_name, ptr.cast(self.cache.void_ptr_t)