Bug 1621256: Update GCCellPtr gdb pretty printer and add support for out-of-line types. r=sfink

Differential Revision: https://phabricator.services.mozilla.com/D66216

--HG--
extra : source : e6218eafa1112c29badc2f988469b0ffc89b2c33
This commit is contained in:
André Bargull 2020-03-11 18:05:47 +00:00
Родитель 69a239d155
Коммит 5ad35aac9b
3 изменённых файлов: 132 добавлений и 19 удалений

Просмотреть файл

@ -12,31 +12,64 @@ 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 JS::TraceKind type for this objfile.
# 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.
e = gdb.types.make_enum_dict(self.TraceKind_t)
kind_to_type = {}
trace_map = {
# Inline types.
'Object': 'JSObject',
'BigInt': 'JS::BigInt',
'String': 'JSString',
'Symbol': 'JS::Symbol',
'Shape': 'js::Shape',
'ObjectGroup': 'js::ObjectGroup',
'Null': 'std::nullptr_t',
def kind(k, t):
kind_to_type[e['JS::TraceKind::' + k]] = gdb.lookup_type(t)
kind('Object', 'JSObject')
kind('String', 'JSString')
kind('Symbol', 'JS::Symbol')
kind('Script', 'js::BaseScript')
kind('Shape', 'js::Shape')
kind('ObjectGroup', 'js::ObjectGroup')
kind('BaseShape', 'js::BaseShape')
kind('JitCode', 'js::jit::JitCode')
self.kind_to_type = kind_to_type
# Out-of-line types.
'BaseShape': 'js::BaseShape',
'JitCode': 'js::jit::JitCode',
'Script': 'js::BaseScript',
'Scope': 'js::Scope',
'RegExpShared': 'js::RegExpShared',
}
self.Null = e['JS::TraceKind::Null']
self.mask = gdb.parse_and_eval('JS::OutOfLineTraceKindMask')
# Map from AllocKind to TraceKind for out-of-line types.
alloc_map = {
'BASE_SHAPE': 'BaseShape',
'JITCODE': 'JitCode',
'SCRIPT': 'Script',
'SCOPE': 'Scope',
'REGEXP_SHARED': 'RegExpShared',
}
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')
@ -49,8 +82,35 @@ class GCCellPtr(object):
def to_string(self):
ptr = self.value['ptr']
kind = ptr & self.cache.mod_GCCellPtr.mask
kind = ptr & self.cache.mod_GCCellPtr.tracekind_mask
if kind == self.cache.mod_GCCellPtr.Null:
return "JS::GCCellPtr(nullptr)"
tipe = self.cache.mod_GCCellPtr.kind_to_type[int(kind)]
return "JS::GCCellPtr(({}*) {})".format(tipe, ptr.cast(self.cache.void_ptr_t))
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))

Просмотреть файл

@ -1,18 +1,57 @@
#include "gdb-tests.h"
#include "mozilla/Unused.h"
#include "jsapi.h"
#include "js/CompileOptions.h"
#include "js/CompilationAndEvaluation.h"
#include "js/HeapAPI.h"
#include "js/RegExpFlags.h"
#include "js/SourceText.h"
#include "js/Symbol.h"
#include "js/TypeDecls.h"
#include "vm/BigIntType.h"
#include "vm/JSObject.h"
#include "vm/ObjectGroup.h"
#include "vm/RegExpObject.h"
#include "vm/Shape.h"
#include "vm/JSObject-inl.h"
FRAGMENT(GCCellPtr, simple) {
JS::Rooted<JSObject*> glob(cx, JS::CurrentGlobalOrNull(cx));
JS::Rooted<JSString*> empty(cx, JS_NewStringCopyN(cx, nullptr, 0));
JS::Rooted<JS::Symbol*> unique(cx, JS::NewSymbol(cx, nullptr));
JS::Rooted<JS::BigInt*> zeroBigInt(cx, JS::BigInt::zero(cx));
JS::Rooted<js::ObjectGroup*> rootedObjGroup(cx, JSObject::getGroup(cx, glob));
JS::Rooted<js::RegExpObject*> regExp(
cx, js::RegExpObject::create(cx, u"", 0, JS::RegExpFlags{},
js::GenericObject));
JS::Rooted<js::RegExpShared*> rootedRegExpShared(
cx, js::RegExpObject::getShared(cx, regExp));
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
JS::SourceText<char16_t> srcBuf;
mozilla::Unused << srcBuf.init(cx, nullptr, 0, JS::SourceOwnership::Borrowed);
JS::RootedScript emptyScript(cx, JS::Compile(cx, options, srcBuf));
// Inline TraceKinds.
JS::GCCellPtr nulll(nullptr);
JS::GCCellPtr object(glob.get());
JS::GCCellPtr string(empty.get());
JS::GCCellPtr symbol(unique.get());
JS::GCCellPtr bigint(zeroBigInt.get());
JS::GCCellPtr shape(glob->shape());
JS::GCCellPtr objectGroup(rootedObjGroup.get());
// Out-of-line TraceKinds.
JS::GCCellPtr baseShape(glob->shape()->base());
// JitCode can't easily be tested here, so skip it.
JS::GCCellPtr script(emptyScript.get());
JS::GCCellPtr scope(emptyScript->bodyScope());
JS::GCCellPtr regExpShared(rootedRegExpShared.get());
breakpoint();
@ -20,4 +59,11 @@ FRAGMENT(GCCellPtr, simple) {
use(object);
use(string);
use(symbol);
use(bigint);
use(shape);
use(objectGroup);
use(baseShape);
use(script);
use(scope);
use(regExpShared);
}

Просмотреть файл

@ -9,3 +9,10 @@ assert_pretty('nulll', 'JS::GCCellPtr(nullptr)')
assert_pretty('object', 'JS::GCCellPtr((JSObject*) )')
assert_pretty('string', 'JS::GCCellPtr((JSString*) )')
assert_pretty('symbol', 'JS::GCCellPtr((JS::Symbol*) )')
assert_pretty('bigint', 'JS::GCCellPtr((JS::BigInt*) )')
assert_pretty('shape', 'JS::GCCellPtr((js::Shape*) )')
assert_pretty('objectGroup', 'JS::GCCellPtr((js::ObjectGroup*) )')
assert_pretty('baseShape', 'JS::GCCellPtr((js::BaseShape*) )')
assert_pretty('script', 'JS::GCCellPtr((js::BaseScript*) )')
assert_pretty('scope', 'JS::GCCellPtr((js::Scope*) )')
assert_pretty('regExpShared', 'JS::GCCellPtr((js::RegExpShared*) )')