# 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 http://mozilla.org/MPL/2.0/.
# 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.
mozilla.prettyprinters.clear_module_printers(__name__)
# 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",
"COMPACT_PROP_MAP":
"PropMap",
"NORMAL_PROP_MAP":
"PropMap",
"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")
@pretty_printer(
"JS::GCCellPtr")
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(
self.cache.mod_GCCellPtr.Arena_t.pointer()
)
# Arena::getAllocKind()
alloc_kind = arena[
"allocKind"].cast(self.cache.mod_GCCellPtr.AllocKind_t)
alloc_idx = int(
alloc_kind.cast(self.cache.mod_GCCellPtr.AllocKind_t.target())
)
# 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)
)