Log Message
Add a debugging utility to dump the memory layout of a JSCell. https://bugs.webkit.org/show_bug.cgi?id=188157
Reviewed by Yusuke Suzuki.
This patch adds $vm.dumpCell() and VMInspector::dumpCellMemory() to allow us to
dump the memory contents of a cell and if present, its butterfly for debugging
purposes.
Example usage for JS code when JSC_useDollarVM=true:
$vm.dumpCell(obj);
Example usage from C++ code or from lldb:
(lldb) p JSC::VMInspector::dumpCellMemory(obj)
Some examples of dumps:
<0x104bc8260, Object>
[0] 0x104bc8260 : 0x010016000000016c header
structureID 364 0x16c structure 0x104b721b0
indexingTypeAndMisc 0 0x0 NonArray
type 22 0x16
flags 0 0x0
cellState 1
[1] 0x104bc8268 : 0x0000000000000000 butterfly
[2] 0x104bc8270 : 0xffff000000000007
[3] 0x104bc8278 : 0xffff000000000008
<0x104bb4360, Array>
[0] 0x104bb4360 : 0x0108210b00000171 header
structureID 369 0x171 structure 0x104b723e0
indexingTypeAndMisc 11 0xb ArrayWithArrayStorage
type 33 0x21
flags 8 0x8
cellState 1
[1] 0x104bb4368 : 0x00000008000f4718 butterfly
base 0x8000f46e0
hasIndexingHeader YES hasAnyArrayStorage YES
publicLength 4 vectorLength 7 indexBias 2
preCapacity 2 propertyCapacity 4
<--- preCapacity
[0] 0x8000f46e0 : 0x0000000000000000
[1] 0x8000f46e8 : 0x0000000000000000
<--- propertyCapacity
[2] 0x8000f46f0 : 0x0000000000000000
[3] 0x8000f46f8 : 0x0000000000000000
[4] 0x8000f4700 : 0xffff00000000000d
[5] 0x8000f4708 : 0xffff00000000000c
<--- indexingHeader
[6] 0x8000f4710 : 0x0000000700000004
<--- butterfly
<--- arrayStorage
[7] 0x8000f4718 : 0x0000000000000000
[8] 0x8000f4720 : 0x0000000400000002
<--- indexedProperties
[9] 0x8000f4728 : 0xffff000000000008
[10] 0x8000f4730 : 0xffff000000000009
[11] 0x8000f4738 : 0xffff000000000005
[12] 0x8000f4740 : 0xffff000000000006
[13] 0x8000f4748 : 0x0000000000000000
[14] 0x8000f4750 : 0x0000000000000000
[15] 0x8000f4758 : 0x0000000000000000
<--- unallocated capacity
[16] 0x8000f4760 : 0x0000000000000000
[17] 0x8000f4768 : 0x0000000000000000
[18] 0x8000f4770 : 0x0000000000000000
[19] 0x8000f4778 : 0x0000000000000000
* runtime/JSObject.h:
* tools/JSDollarVM.cpp:
(JSC::functionDumpCell):
(JSC::JSDollarVM::finishCreation):
* tools/VMInspector.cpp:
(JSC::VMInspector::dumpCellMemory):
(JSC::IndentationScope::IndentationScope):
(JSC::IndentationScope::~IndentationScope):
(JSC::VMInspector::dumpCellMemoryToStream):
* tools/VMInspector.h:
Modified Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (234362 => 234363)
--- trunk/Source/_javascript_Core/ChangeLog 2018-07-30 13:06:24 UTC (rev 234362)
+++ trunk/Source/_javascript_Core/ChangeLog 2018-07-30 14:46:25 UTC (rev 234363)
@@ -1,3 +1,86 @@
+2018-07-30 Mark Lam <[email protected]>
+
+ Add a debugging utility to dump the memory layout of a JSCell.
+ https://bugs.webkit.org/show_bug.cgi?id=188157
+
+ Reviewed by Yusuke Suzuki.
+
+ This patch adds $vm.dumpCell() and VMInspector::dumpCellMemory() to allow us to
+ dump the memory contents of a cell and if present, its butterfly for debugging
+ purposes.
+
+ Example usage for JS code when JSC_useDollarVM=true:
+
+ $vm.dumpCell(obj);
+
+ Example usage from C++ code or from lldb:
+
+ (lldb) p JSC::VMInspector::dumpCellMemory(obj)
+
+ Some examples of dumps:
+
+ <0x104bc8260, Object>
+ [0] 0x104bc8260 : 0x010016000000016c header
+ structureID 364 0x16c structure 0x104b721b0
+ indexingTypeAndMisc 0 0x0 NonArray
+ type 22 0x16
+ flags 0 0x0
+ cellState 1
+ [1] 0x104bc8268 : 0x0000000000000000 butterfly
+ [2] 0x104bc8270 : 0xffff000000000007
+ [3] 0x104bc8278 : 0xffff000000000008
+
+ <0x104bb4360, Array>
+ [0] 0x104bb4360 : 0x0108210b00000171 header
+ structureID 369 0x171 structure 0x104b723e0
+ indexingTypeAndMisc 11 0xb ArrayWithArrayStorage
+ type 33 0x21
+ flags 8 0x8
+ cellState 1
+ [1] 0x104bb4368 : 0x00000008000f4718 butterfly
+ base 0x8000f46e0
+ hasIndexingHeader YES hasAnyArrayStorage YES
+ publicLength 4 vectorLength 7 indexBias 2
+ preCapacity 2 propertyCapacity 4
+ <--- preCapacity
+ [0] 0x8000f46e0 : 0x0000000000000000
+ [1] 0x8000f46e8 : 0x0000000000000000
+ <--- propertyCapacity
+ [2] 0x8000f46f0 : 0x0000000000000000
+ [3] 0x8000f46f8 : 0x0000000000000000
+ [4] 0x8000f4700 : 0xffff00000000000d
+ [5] 0x8000f4708 : 0xffff00000000000c
+ <--- indexingHeader
+ [6] 0x8000f4710 : 0x0000000700000004
+ <--- butterfly
+ <--- arrayStorage
+ [7] 0x8000f4718 : 0x0000000000000000
+ [8] 0x8000f4720 : 0x0000000400000002
+ <--- indexedProperties
+ [9] 0x8000f4728 : 0xffff000000000008
+ [10] 0x8000f4730 : 0xffff000000000009
+ [11] 0x8000f4738 : 0xffff000000000005
+ [12] 0x8000f4740 : 0xffff000000000006
+ [13] 0x8000f4748 : 0x0000000000000000
+ [14] 0x8000f4750 : 0x0000000000000000
+ [15] 0x8000f4758 : 0x0000000000000000
+ <--- unallocated capacity
+ [16] 0x8000f4760 : 0x0000000000000000
+ [17] 0x8000f4768 : 0x0000000000000000
+ [18] 0x8000f4770 : 0x0000000000000000
+ [19] 0x8000f4778 : 0x0000000000000000
+
+ * runtime/JSObject.h:
+ * tools/JSDollarVM.cpp:
+ (JSC::functionDumpCell):
+ (JSC::JSDollarVM::finishCreation):
+ * tools/VMInspector.cpp:
+ (JSC::VMInspector::dumpCellMemory):
+ (JSC::IndentationScope::IndentationScope):
+ (JSC::IndentationScope::~IndentationScope):
+ (JSC::VMInspector::dumpCellMemoryToStream):
+ * tools/VMInspector.h:
+
2018-07-27 Mark Lam <[email protected]>
Add some crash info to Heap::checkConn() RELEASE_ASSERTs.
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (234362 => 234363)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2018-07-30 13:06:24 UTC (rev 234362)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2018-07-30 14:46:25 UTC (rev 234363)
@@ -1014,7 +1014,8 @@
private:
friend class LLIntOffsetsExtractor;
-
+ friend class VMInspector;
+
// Nobody should ever ask any of these questions on something already known to be a JSObject.
using JSCell::isAPIValueWrapper;
using JSCell::isGetterSetter;
Modified: trunk/Source/_javascript_Core/tools/JSDollarVM.cpp (234362 => 234363)
--- trunk/Source/_javascript_Core/tools/JSDollarVM.cpp 2018-07-30 13:06:24 UTC (rev 234362)
+++ trunk/Source/_javascript_Core/tools/JSDollarVM.cpp 2018-07-30 14:46:25 UTC (rev 234363)
@@ -1488,6 +1488,18 @@
return JSValue::encode(jsUndefined());
}
+// Dumps the internal memory layout of a JSCell.
+// Usage: $vm.dumpCell(cell)
+static EncodedJSValue JSC_HOST_CALL functionDumpCell(ExecState* exec)
+{
+ JSValue value = exec->argument(0);
+ if (!value.isCell())
+ return encodedJSUndefined();
+
+ VMInspector::dumpCellMemory(value.asCell());
+ return encodedJSUndefined();
+}
+
// Gets the dataLog dump of the indexingMode of the passed value.
// Usage: $vm.print("indexingMode = " + $vm.indexingMode(jsValue))
static EncodedJSValue JSC_HOST_CALL functionIndexingMode(ExecState* exec)
@@ -1989,6 +2001,8 @@
addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
addFunction(vm, "dumpStack", functionDumpStack, 0);
+ addFunction(vm, "dumpCell", functionDumpCell, 1);
+
addFunction(vm, "indexingMode", functionIndexingMode, 1);
addFunction(vm, "inlineCapacity", functionInlineCapacity, 1);
addFunction(vm, "value", functionValue, 1);
Modified: trunk/Source/_javascript_Core/tools/VMInspector.cpp (234362 => 234363)
--- trunk/Source/_javascript_Core/tools/VMInspector.cpp 2018-07-30 13:06:24 UTC (rev 234362)
+++ trunk/Source/_javascript_Core/tools/VMInspector.cpp 2018-07-30 14:46:25 UTC (rev 234363)
@@ -30,6 +30,7 @@
#include "CodeBlockSet.h"
#include "HeapInlines.h"
#include "HeapIterationScope.h"
+#include "JSCInlines.h"
#include "MachineContext.h"
#include "MarkedSpaceInlines.h"
#include "StackVisitor.h"
@@ -381,4 +382,157 @@
dataLog(value);
}
+void VMInspector::dumpCellMemory(JSCell* cell)
+{
+ dumpCellMemoryToStream(cell, WTF::dataFile());
+}
+
+class IndentationScope {
+public:
+ IndentationScope(unsigned& indentation)
+ : m_indentation(indentation)
+ {
+ ++m_indentation;
+ }
+
+ ~IndentationScope()
+ {
+ --m_indentation;
+ }
+
+private:
+ unsigned& m_indentation;
+};
+
+void VMInspector::dumpCellMemoryToStream(JSCell* cell, PrintStream& out)
+{
+ VM& vm = *cell->vm();
+ StructureID structureID = cell->structureID();
+ Structure* structure = cell->structure(vm);
+ IndexingType indexingTypeAndMisc = cell->indexingTypeAndMisc();
+ IndexingType indexingType = structure->indexingType();
+ IndexingType indexingMode = structure->indexingMode();
+ JSType type = cell->type();
+ TypeInfo::InlineTypeFlags inlineTypeFlags = cell->inlineTypeFlags();
+ CellState cellState = cell->cellState();
+ size_t cellSize = cell->cellSize();
+ size_t slotCount = cellSize / sizeof(EncodedJSValue);
+
+ EncodedJSValue* slots = bitwise_cast<EncodedJSValue*>(cell);
+ unsigned indentation = 0;
+
+ auto indent = [&] {
+ for (unsigned i = 0 ; i < indentation; ++i)
+ out.print(" ");
+ };
+
+#define INDENT indent(),
+
+ auto dumpSlot = [&] (EncodedJSValue* slots, unsigned index, const char* label = nullptr) {
+ out.print("[", index, "] ", format("%p : 0x%016" PRIx64, &slots[index], slots[index]));
+ if (label)
+ out.print(" ", label);
+ out.print("\n");
+ };
+
+ out.printf("<%p, %s>\n", cell, cell->className(vm));
+ IndentationScope scope(indentation);
+
+ INDENT dumpSlot(slots, 0, "header");
+ {
+ IndentationScope scope(indentation);
+ INDENT out.println("structureID ", format("%d 0x%" PRIx32, structureID, structureID), " structure ", RawPointer(structure));
+ INDENT out.println("indexingTypeAndMisc ", format("%d 0x%" PRIx8, indexingTypeAndMisc, indexingTypeAndMisc), " ", IndexingTypeDump(indexingMode));
+ INDENT out.println("type ", format("%d 0x%" PRIx8, type, type));
+ INDENT out.println("flags ", format("%d 0x%" PRIx8, inlineTypeFlags, inlineTypeFlags));
+ INDENT out.println("cellState ", format("%d", cellState));
+ }
+
+ unsigned slotIndex = 1;
+ if (cell->isObject()) {
+ JSObject* obj = static_cast<JSObject*>(const_cast<JSCell*>(cell));
+ Butterfly* butterfly = obj->butterfly();
+ size_t butterflySize = obj->butterflyTotalSize();
+
+ INDENT dumpSlot(slots, slotIndex, "butterfly");
+ slotIndex++;
+
+ if (butterfly) {
+ IndentationScope scope(indentation);
+
+ bool hasIndexingHeader = structure->hasIndexingHeader(cell);
+ bool hasAnyArrayStorage = JSC::hasAnyArrayStorage(indexingType);
+
+ size_t preCapacity = obj->butterflyPreCapacity();
+ size_t propertyCapacity = structure->outOfLineCapacity();
+
+ void* base = hasIndexingHeader
+ ? butterfly->base(preCapacity, propertyCapacity)
+ : butterfly->base(structure);
+
+ unsigned publicLength = butterfly->publicLength();
+ unsigned vectorLength = butterfly->vectorLength();
+ size_t butterflyCellSize = MarkedSpace::optimalSizeFor(butterflySize);
+
+ size_t endOfIndexedPropertiesIndex = butterflySize / sizeof(EncodedJSValue);
+ size_t endOfButterflyIndex = butterflyCellSize / sizeof(EncodedJSValue);
+
+ INDENT out.println("base ", RawPointer(base));
+ INDENT out.println("hasIndexingHeader ", (hasIndexingHeader ? "YES" : "NO"), " hasAnyArrayStorage ", (hasAnyArrayStorage ? "YES" : "NO"));
+ if (hasIndexingHeader) {
+ INDENT out.print("publicLength ", publicLength, " vectorLength ", vectorLength);
+ if (hasAnyArrayStorage)
+ out.print(" indexBias ", butterfly->arrayStorage()->m_indexBias);
+ out.print("\n");
+ }
+ INDENT out.println("preCapacity ", preCapacity, " propertyCapacity ", propertyCapacity);
+
+ unsigned index = 0;
+ EncodedJSValue* slots = reinterpret_cast<EncodedJSValue*>(base);
+
+ auto asVoidPtr = [] (void* p) {
+ return p;
+ };
+
+ auto dumpSectionHeader = [&] (const char* name) {
+ out.println("<--- ", name);
+ };
+
+ auto dumpSection = [&] (unsigned startIndex, unsigned endIndex, const char* name) -> unsigned {
+ for (unsigned index = startIndex; index < endIndex; ++index) {
+ if (name && index == startIndex)
+ INDENT dumpSectionHeader(name);
+ INDENT dumpSlot(slots, index);
+ }
+ return endIndex;
+ };
+
+ {
+ IndentationScope scope(indentation);
+
+ index = dumpSection(index, preCapacity, "preCapacity");
+ index = dumpSection(index, preCapacity + propertyCapacity, "propertyCapacity");
+
+ if (hasIndexingHeader)
+ index = dumpSection(index, index + 1, "indexingHeader");
+
+ INDENT dumpSectionHeader("butterfly");
+ if (hasAnyArrayStorage) {
+ RELEASE_ASSERT(asVoidPtr(butterfly->arrayStorage()) == asVoidPtr(&slots[index]));
+ RELEASE_ASSERT(ArrayStorage::vectorOffset() == 2 * sizeof(EncodedJSValue));
+ index = dumpSection(index, index + 2, "arrayStorage");
+ }
+
+ index = dumpSection(index, endOfIndexedPropertiesIndex, "indexedProperties");
+ index = dumpSection(index, endOfButterflyIndex, "unallocated capacity");
+ }
+ }
+ }
+
+ for (; slotIndex < slotCount; ++slotIndex)
+ INDENT dumpSlot(slots, slotIndex);
+
+#undef INDENT
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/tools/VMInspector.h (234362 => 234363)
--- trunk/Source/_javascript_Core/tools/VMInspector.h 2018-07-30 13:06:24 UTC (rev 234362)
+++ trunk/Source/_javascript_Core/tools/VMInspector.h 2018-07-30 14:46:25 UTC (rev 234363)
@@ -72,6 +72,8 @@
JS_EXPORT_PRIVATE static void dumpCallFrame(CallFrame*, unsigned framesToSkip = 0);
JS_EXPORT_PRIVATE static void dumpStack(CallFrame* topCallFrame, unsigned framesToSkip = 0);
JS_EXPORT_PRIVATE static void dumpValue(JSValue);
+ JS_EXPORT_PRIVATE static void dumpCellMemory(JSCell*);
+ JS_EXPORT_PRIVATE static void dumpCellMemoryToStream(JSCell*, PrintStream&);
private:
template <typename Functor> void iterate(const Functor& functor)
_______________________________________________ webkit-changes mailing list [email protected] https://lists.webkit.org/mailman/listinfo/webkit-changes
