Changeset 234363 in webkit


Ignore:
Timestamp:
Jul 30, 2018 7:46:25 AM (6 years ago)
Author:
mark.lam@apple.com
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:
Location:
trunk/Source/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r234335 r234363  
     12018-07-30  Mark Lam  <mark.lam@apple.com>
     2
     3        Add a debugging utility to dump the memory layout of a JSCell.
     4        https://bugs.webkit.org/show_bug.cgi?id=188157
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        This patch adds $vm.dumpCell() and VMInspector::dumpCellMemory() to allow us to
     9        dump the memory contents of a cell and if present, its butterfly for debugging
     10        purposes.
     11
     12        Example usage for JS code when JSC_useDollarVM=true:
     13
     14            $vm.dumpCell(obj);
     15
     16        Example usage from C++ code or from lldb:
     17
     18            (lldb) p JSC::VMInspector::dumpCellMemory(obj)
     19
     20        Some examples of dumps:
     21
     22            <0x104bc8260, Object>
     23              [0] 0x104bc8260 : 0x010016000000016c header
     24                structureID 364 0x16c structure 0x104b721b0
     25                indexingTypeAndMisc 0 0x0 NonArray
     26                type 22 0x16
     27                flags 0 0x0
     28                cellState 1
     29              [1] 0x104bc8268 : 0x0000000000000000 butterfly
     30              [2] 0x104bc8270 : 0xffff000000000007
     31              [3] 0x104bc8278 : 0xffff000000000008
     32
     33            <0x104bb4360, Array>
     34              [0] 0x104bb4360 : 0x0108210b00000171 header
     35                structureID 369 0x171 structure 0x104b723e0
     36                indexingTypeAndMisc 11 0xb ArrayWithArrayStorage
     37                type 33 0x21
     38                flags 8 0x8
     39                cellState 1
     40              [1] 0x104bb4368 : 0x00000008000f4718 butterfly
     41                base 0x8000f46e0
     42                hasIndexingHeader YES hasAnyArrayStorage YES
     43                publicLength 4 vectorLength 7 indexBias 2
     44                preCapacity 2 propertyCapacity 4
     45                  <--- preCapacity
     46                  [0] 0x8000f46e0 : 0x0000000000000000
     47                  [1] 0x8000f46e8 : 0x0000000000000000
     48                  <--- propertyCapacity
     49                  [2] 0x8000f46f0 : 0x0000000000000000
     50                  [3] 0x8000f46f8 : 0x0000000000000000
     51                  [4] 0x8000f4700 : 0xffff00000000000d
     52                  [5] 0x8000f4708 : 0xffff00000000000c
     53                  <--- indexingHeader
     54                  [6] 0x8000f4710 : 0x0000000700000004
     55                  <--- butterfly
     56                  <--- arrayStorage
     57                  [7] 0x8000f4718 : 0x0000000000000000
     58                  [8] 0x8000f4720 : 0x0000000400000002
     59                  <--- indexedProperties
     60                  [9] 0x8000f4728 : 0xffff000000000008
     61                  [10] 0x8000f4730 : 0xffff000000000009
     62                  [11] 0x8000f4738 : 0xffff000000000005
     63                  [12] 0x8000f4740 : 0xffff000000000006
     64                  [13] 0x8000f4748 : 0x0000000000000000
     65                  [14] 0x8000f4750 : 0x0000000000000000
     66                  [15] 0x8000f4758 : 0x0000000000000000
     67                  <--- unallocated capacity
     68                  [16] 0x8000f4760 : 0x0000000000000000
     69                  [17] 0x8000f4768 : 0x0000000000000000
     70                  [18] 0x8000f4770 : 0x0000000000000000
     71                  [19] 0x8000f4778 : 0x0000000000000000
     72
     73        * runtime/JSObject.h:
     74        * tools/JSDollarVM.cpp:
     75        (JSC::functionDumpCell):
     76        (JSC::JSDollarVM::finishCreation):
     77        * tools/VMInspector.cpp:
     78        (JSC::VMInspector::dumpCellMemory):
     79        (JSC::IndentationScope::IndentationScope):
     80        (JSC::IndentationScope::~IndentationScope):
     81        (JSC::VMInspector::dumpCellMemoryToStream):
     82        * tools/VMInspector.h:
     83
    1842018-07-27  Mark Lam  <mark.lam@apple.com>
    285
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r234089 r234363  
    10151015private:
    10161016    friend class LLIntOffsetsExtractor;
    1017        
     1017    friend class VMInspector;
     1018
    10181019    // Nobody should ever ask any of these questions on something already known to be a JSObject.
    10191020    using JSCell::isAPIValueWrapper;
  • trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp

    r233285 r234363  
    14891489}
    14901490
     1491// Dumps the internal memory layout of a JSCell.
     1492// Usage: $vm.dumpCell(cell)
     1493static EncodedJSValue JSC_HOST_CALL functionDumpCell(ExecState* exec)
     1494{
     1495    JSValue value = exec->argument(0);
     1496    if (!value.isCell())
     1497        return encodedJSUndefined();
     1498   
     1499    VMInspector::dumpCellMemory(value.asCell());
     1500    return encodedJSUndefined();
     1501}
     1502
    14911503// Gets the dataLog dump of the indexingMode of the passed value.
    14921504// Usage: $vm.print("indexingMode = " + $vm.indexingMode(jsValue))
     
    19902002    addFunction(vm, "dumpStack", functionDumpStack, 0);
    19912003
     2004    addFunction(vm, "dumpCell", functionDumpCell, 1);
     2005
    19922006    addFunction(vm, "indexingMode", functionIndexingMode, 1);
    19932007    addFunction(vm, "inlineCapacity", functionInlineCapacity, 1);
  • trunk/Source/JavaScriptCore/tools/VMInspector.cpp

    r233285 r234363  
    3131#include "HeapInlines.h"
    3232#include "HeapIterationScope.h"
     33#include "JSCInlines.h"
    3334#include "MachineContext.h"
    3435#include "MarkedSpaceInlines.h"
     
    382383}
    383384
     385void VMInspector::dumpCellMemory(JSCell* cell)
     386{
     387    dumpCellMemoryToStream(cell, WTF::dataFile());
     388}
     389
     390class IndentationScope {
     391public:
     392    IndentationScope(unsigned& indentation)
     393        : m_indentation(indentation)
     394    {
     395        ++m_indentation;
     396    }
     397
     398    ~IndentationScope()
     399    {
     400        --m_indentation;
     401    }
     402
     403private:
     404    unsigned& m_indentation;
     405};
     406
     407void VMInspector::dumpCellMemoryToStream(JSCell* cell, PrintStream& out)
     408{
     409    VM& vm = *cell->vm();
     410    StructureID structureID = cell->structureID();
     411    Structure* structure = cell->structure(vm);
     412    IndexingType indexingTypeAndMisc = cell->indexingTypeAndMisc();
     413    IndexingType indexingType = structure->indexingType();
     414    IndexingType indexingMode = structure->indexingMode();
     415    JSType type = cell->type();
     416    TypeInfo::InlineTypeFlags inlineTypeFlags = cell->inlineTypeFlags();
     417    CellState cellState = cell->cellState();
     418    size_t cellSize = cell->cellSize();
     419    size_t slotCount = cellSize / sizeof(EncodedJSValue);
     420
     421    EncodedJSValue* slots = bitwise_cast<EncodedJSValue*>(cell);
     422    unsigned indentation = 0;
     423
     424    auto indent = [&] {
     425        for (unsigned i = 0 ; i < indentation; ++i)
     426            out.print("  ");
     427    };
     428
     429#define INDENT indent(),
     430   
     431    auto dumpSlot = [&] (EncodedJSValue* slots, unsigned index, const char* label = nullptr) {
     432        out.print("[", index, "] ", format("%p : 0x%016" PRIx64, &slots[index], slots[index]));
     433        if (label)
     434            out.print(" ", label);
     435        out.print("\n");
     436    };
     437
     438    out.printf("<%p, %s>\n", cell, cell->className(vm));
     439    IndentationScope scope(indentation);
     440
     441    INDENT dumpSlot(slots, 0, "header");
     442    {
     443        IndentationScope scope(indentation);
     444        INDENT out.println("structureID ", format("%d 0x%" PRIx32, structureID, structureID), " structure ", RawPointer(structure));
     445        INDENT out.println("indexingTypeAndMisc ", format("%d 0x%" PRIx8, indexingTypeAndMisc, indexingTypeAndMisc), " ", IndexingTypeDump(indexingMode));
     446        INDENT out.println("type ", format("%d 0x%" PRIx8, type, type));
     447        INDENT out.println("flags ", format("%d 0x%" PRIx8, inlineTypeFlags, inlineTypeFlags));
     448        INDENT out.println("cellState ", format("%d", cellState));
     449    }
     450
     451    unsigned slotIndex = 1;
     452    if (cell->isObject()) {
     453        JSObject* obj = static_cast<JSObject*>(const_cast<JSCell*>(cell));
     454        Butterfly* butterfly = obj->butterfly();
     455        size_t butterflySize = obj->butterflyTotalSize();
     456
     457        INDENT dumpSlot(slots, slotIndex, "butterfly");
     458        slotIndex++;
     459
     460        if (butterfly) {
     461            IndentationScope scope(indentation);
     462
     463            bool hasIndexingHeader = structure->hasIndexingHeader(cell);
     464            bool hasAnyArrayStorage = JSC::hasAnyArrayStorage(indexingType);
     465
     466            size_t preCapacity = obj->butterflyPreCapacity();
     467            size_t propertyCapacity = structure->outOfLineCapacity();
     468
     469            void* base = hasIndexingHeader
     470                ? butterfly->base(preCapacity, propertyCapacity)
     471                : butterfly->base(structure);
     472
     473            unsigned publicLength = butterfly->publicLength();
     474            unsigned vectorLength = butterfly->vectorLength();
     475            size_t butterflyCellSize = MarkedSpace::optimalSizeFor(butterflySize);
     476
     477            size_t endOfIndexedPropertiesIndex = butterflySize / sizeof(EncodedJSValue);
     478            size_t endOfButterflyIndex = butterflyCellSize / sizeof(EncodedJSValue);
     479
     480            INDENT out.println("base ", RawPointer(base));
     481            INDENT out.println("hasIndexingHeader ", (hasIndexingHeader ? "YES" : "NO"), " hasAnyArrayStorage ", (hasAnyArrayStorage ? "YES" : "NO"));
     482            if (hasIndexingHeader) {
     483                INDENT out.print("publicLength ", publicLength, " vectorLength ", vectorLength);
     484                if (hasAnyArrayStorage)
     485                    out.print(" indexBias ", butterfly->arrayStorage()->m_indexBias);
     486                out.print("\n");
     487            }
     488            INDENT out.println("preCapacity ", preCapacity, " propertyCapacity ", propertyCapacity);
     489
     490            unsigned index = 0;
     491            EncodedJSValue* slots = reinterpret_cast<EncodedJSValue*>(base);
     492
     493            auto asVoidPtr = [] (void* p) {
     494                return p;
     495            };
     496
     497            auto dumpSectionHeader = [&] (const char* name) {
     498                out.println("<--- ", name);
     499            };
     500
     501            auto dumpSection = [&] (unsigned startIndex, unsigned endIndex, const char* name) -> unsigned {
     502                for (unsigned index = startIndex; index < endIndex; ++index) {
     503                    if (name && index == startIndex)
     504                        INDENT dumpSectionHeader(name);
     505                    INDENT dumpSlot(slots, index);
     506                }
     507                return endIndex;
     508            };
     509
     510            {
     511                IndentationScope scope(indentation);
     512
     513                index = dumpSection(index, preCapacity, "preCapacity");
     514                index = dumpSection(index, preCapacity + propertyCapacity, "propertyCapacity");
     515
     516                if (hasIndexingHeader)
     517                    index = dumpSection(index, index + 1, "indexingHeader");
     518
     519                INDENT dumpSectionHeader("butterfly");
     520                if (hasAnyArrayStorage) {
     521                    RELEASE_ASSERT(asVoidPtr(butterfly->arrayStorage()) == asVoidPtr(&slots[index]));
     522                    RELEASE_ASSERT(ArrayStorage::vectorOffset() == 2 * sizeof(EncodedJSValue));
     523                    index = dumpSection(index, index + 2, "arrayStorage");
     524                }
     525
     526                index = dumpSection(index, endOfIndexedPropertiesIndex, "indexedProperties");
     527                index = dumpSection(index, endOfButterflyIndex, "unallocated capacity");
     528            }
     529        }
     530    }
     531
     532    for (; slotIndex < slotCount; ++slotIndex)
     533        INDENT dumpSlot(slots, slotIndex);
     534
     535#undef INDENT
     536}
     537
    384538} // namespace JSC
  • trunk/Source/JavaScriptCore/tools/VMInspector.h

    r233285 r234363  
    7373    JS_EXPORT_PRIVATE static void dumpStack(CallFrame* topCallFrame, unsigned framesToSkip = 0);
    7474    JS_EXPORT_PRIVATE static void dumpValue(JSValue);
     75    JS_EXPORT_PRIVATE static void dumpCellMemory(JSCell*);
     76    JS_EXPORT_PRIVATE static void dumpCellMemoryToStream(JSCell*, PrintStream&);
    7577
    7678private:
Note: See TracChangeset for help on using the changeset viewer.