GCCellPtr.py (4624B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 # You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 # Pretty-printers for GCCellPtr values. 6 7 import gdb 8 9 import mozilla.prettyprinters 10 from mozilla.prettyprinters import pretty_printer 11 12 # Forget any printers from previous loads of this module. 13 mozilla.prettyprinters.clear_module_printers(__name__) 14 15 # Cache information about the types for this objfile. 16 17 18 class GCCellPtrTypeCache: 19 def __init__(self, cache): 20 self.TraceKind_t = gdb.lookup_type("JS::TraceKind") 21 self.AllocKind_t = gdb.lookup_type("js::gc::AllocKind") 22 self.Arena_t = gdb.lookup_type("js::gc::Arena") 23 self.Cell_t = gdb.lookup_type("js::gc::Cell") 24 self.TenuredCell_t = gdb.lookup_type("js::gc::TenuredCell") 25 26 trace_kinds = gdb.types.make_enum_dict(self.TraceKind_t) 27 alloc_kinds = gdb.types.make_enum_dict(self.AllocKind_t) 28 29 def trace_kind(k): 30 return trace_kinds["JS::TraceKind::" + k] 31 32 def alloc_kind(k): 33 return alloc_kinds["js::gc::AllocKind::" + k] 34 35 # Build a mapping from TraceKind enum values to the types they denote. 36 trace_map = { 37 # Inline types. 38 "Object": "JSObject", 39 "BigInt": "JS::BigInt", 40 "String": "JSString", 41 "GetterSetter": "js::GetterSetter", 42 "Symbol": "JS::Symbol", 43 "Shape": "js::Shape", 44 "Null": "std::nullptr_t", 45 # Out-of-line types. 46 "BaseShape": "js::BaseShape", 47 "JitCode": "js::jit::JitCode", 48 "Script": "js::BaseScript", 49 "Scope": "js::Scope", 50 "RegExpShared": "js::RegExpShared", 51 "PropMap": "js::PropMap", 52 } 53 54 # Map from AllocKind to TraceKind for out-of-line types. 55 alloc_map = { 56 "BASE_SHAPE": "BaseShape", 57 "JITCODE": "JitCode", 58 "SCRIPT": "Script", 59 "SCOPE": "Scope", 60 "REGEXP_SHARED": "RegExpShared", 61 "COMPACT_PROP_MAP": "PropMap", 62 "NORMAL_PROP_MAP": "PropMap", 63 "DICT_PROP_MAP": "PropMap", 64 } 65 66 self.trace_kind_to_type = { 67 trace_kind(k): gdb.lookup_type(v) for k, v in trace_map.items() 68 } 69 self.alloc_kind_to_trace_kind = { 70 alloc_kind(k): trace_kind(v) for k, v in alloc_map.items() 71 } 72 73 self.Null = trace_kind("Null") 74 self.tracekind_mask = gdb.parse_and_eval("JS::OutOfLineTraceKindMask") 75 self.arena_mask = gdb.parse_and_eval("js::gc::ArenaMask") 76 77 78 @pretty_printer("JS::GCCellPtr") 79 class GCCellPtr: 80 def __init__(self, value, cache): 81 self.value = value 82 if not cache.mod_GCCellPtr: 83 cache.mod_GCCellPtr = GCCellPtrTypeCache(cache) 84 self.cache = cache 85 86 def to_string(self): 87 ptr = self.value["ptr"] 88 kind = ptr & self.cache.mod_GCCellPtr.tracekind_mask 89 if kind == self.cache.mod_GCCellPtr.Null: 90 return "JS::GCCellPtr(nullptr)" 91 if kind == self.cache.mod_GCCellPtr.tracekind_mask: 92 # Out-of-line trace kinds. 93 # 94 # Compute the underlying type for out-of-line kinds by 95 # reimplementing the GCCellPtr::outOfLineKind() method. 96 # 97 # The extra casts below are only present to make it easier to 98 # compare this code against the C++ implementation. 99 100 # GCCellPtr::asCell() 101 cell_ptr = ptr & ~self.cache.mod_GCCellPtr.tracekind_mask 102 cell = cell_ptr.reinterpret_cast(self.cache.mod_GCCellPtr.Cell_t.pointer()) 103 104 # Cell::asTenured() 105 tenured = cell.cast(self.cache.mod_GCCellPtr.TenuredCell_t.pointer()) 106 107 # TenuredCell::arena() 108 addr = int(tenured) 109 arena_ptr = addr & ~self.cache.mod_GCCellPtr.arena_mask 110 arena = arena_ptr.reinterpret_cast( 111 self.cache.mod_GCCellPtr.Arena_t.pointer() 112 ) 113 114 # Arena::getAllocKind() 115 alloc_kind = arena["allocKind"].cast(self.cache.mod_GCCellPtr.AllocKind_t) 116 alloc_idx = int( 117 alloc_kind.cast(self.cache.mod_GCCellPtr.AllocKind_t.target()) 118 ) 119 120 # Map the AllocKind to a TraceKind. 121 kind = self.cache.mod_GCCellPtr.alloc_kind_to_trace_kind[alloc_idx] 122 type_name = self.cache.mod_GCCellPtr.trace_kind_to_type[int(kind)] 123 return f"JS::GCCellPtr(({type_name}*) {ptr.cast(self.cache.void_ptr_t)})"