Title: [234363] trunk/Source/_javascript_Core
Revision
234363
Author
[email protected]
Date
2018-07-30 07:46:25 -0700 (Mon, 30 Jul 2018)

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

Reply via email to