Bug 1337072 - Implement helper routines for inspecting and breaking on mark bits, r=jonco
authorSteve Fink <sfink@mozilla.com>
Mon, 06 Feb 2017 10:56:16 -0800
changeset 344829 96b7a5189c50
parent 344828 1d4116cb3c9d
child 344830 f36062d04d16
child 344885 82cdbd24d06f
push id31417
push userkwierso@gmail.com
push dateSat, 25 Feb 2017 00:46:36 +0000
treeherdermozilla-central@f36062d04d16 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1337072
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1337072 - Implement helper routines for inspecting and breaking on mark bits, r=jonco MozReview-Commit-ID: FhdPEVo3BOi
js/src/gc/Heap.h
js/src/gc/Marking.cpp
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -1368,11 +1368,57 @@ TenuredCell::isAligned() const
     return Arena::isAligned(address(), arena()->getThingSize());
 }
 #endif
 
 static const int32_t ChunkLocationOffsetFromLastByte =
     int32_t(gc::ChunkLocationOffset) - int32_t(gc::ChunkMask);
 
 } /* namespace gc */
+
+namespace debug {
+
+// Utility functions meant to be called from an interactive debugger.
+enum class MarkInfo : int {
+    BLACK = js::gc::BLACK,
+    GRAY = js::gc::GRAY,
+    UNMARKED = -1,
+    NURSERY = -2,
+};
+
+// Get the mark color for a cell, in a way easily usable from a debugger.
+MOZ_NEVER_INLINE MarkInfo
+GetMarkInfo(js::gc::Cell* cell);
+
+// Sample usage from gdb:
+//
+//   (gdb) p $word = js::debug::GetMarkWordAddress(obj)
+//   $1 = (uintptr_t *) 0x7fa56d5fe360
+//   (gdb) p/x $mask = js::debug::GetMarkMask(obj, js::gc::GRAY)
+//   $2 = 0x200000000
+//   (gdb) watch *$word
+//   Hardware watchpoint 7: *$word
+//   (gdb) cond 7 *$word & $mask
+//   (gdb) cont
+//
+// Note that this is *not* a watchpoint on a single bit. It is a watchpoint on
+// the whole word, which will trigger whenever the word changes and the
+// selected bit is set after the change.
+//
+// So if the bit changing is the desired one, this is exactly what you want.
+// But if a different bit changes (either set or cleared), you may still stop
+// execution if the $mask bit happened to already be set. gdb does not expose
+// enough information to restrict the watchpoint to just a single bit.
+
+// Return the address of the word containing the mark bits for the given cell,
+// or nullptr if the cell is in the nursery.
+MOZ_NEVER_INLINE uintptr_t*
+GetMarkWordAddress(js::gc::Cell* cell);
+
+// Return the mask for the given cell and color, or 0 if the cell is in the
+// nursery.
+MOZ_NEVER_INLINE uintptr_t
+GetMarkMask(js::gc::Cell* cell, uint32_t color);
+
+} /* namespace debug */
 } /* namespace js */
 
 #endif /* gc_Heap_h */
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -3368,8 +3368,52 @@ js::UnmarkGrayShapeRecursively(Shape* sh
     return TypedUnmarkGrayCellRecursively(shape);
 }
 
 JS_FRIEND_API(bool)
 JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr thing)
 {
     return js::UnmarkGrayCellRecursively(thing.asCell(), thing.kind());
 }
+
+namespace js {
+namespace debug {
+
+MarkInfo
+GetMarkInfo(Cell* rawCell)
+{
+    if (!rawCell->isTenured())
+        return MarkInfo::NURSERY;
+
+    TenuredCell* cell = &rawCell->asTenured();
+    if (cell->isMarked(GRAY))
+        return MarkInfo::GRAY;
+    if (cell->isMarked(BLACK))
+        return MarkInfo::BLACK;
+    return MarkInfo::UNMARKED;
+}
+
+uintptr_t*
+GetMarkWordAddress(Cell* cell)
+{
+    if (!cell->isTenured())
+        return nullptr;
+
+    uintptr_t* wordp;
+    uintptr_t mask;
+    js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::BLACK, &wordp, &mask);
+    return wordp;
+}
+
+uintptr_t
+GetMarkMask(Cell* cell, uint32_t color)
+{
+    if (!cell->isTenured())
+        return 0;
+
+    uintptr_t* wordp;
+    uintptr_t mask;
+    js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), color, &wordp, &mask);
+    return mask;
+}
+
+}
+}