Ignore:
Timestamp:
Feb 29, 2016, 6:07:12 PM (9 years ago)
Author:
[email protected]
Message:

Add new MethodTable method to get an estimated size for a cell
https://bugs.webkit.org/show_bug.cgi?id=154838

Patch by Joseph Pecoraro <Joseph Pecoraro> on 2016-02-29
Reviewed by Filip Pizlo.

The new class method estimatedSize(JSCell*) estimates the size for a single cell.
As the name implies, this is meant to be an approximation. It is more important
that big objects report a large size, then to get perfect size information for
all objects in the heap.

Base implementation (JSCell):

  • returns the MarkedBlock bucket size for this cell.
  • This gets us the object size include inline storage. Basically a better sizeof.

Subclasses with "Extra Memory Cost":

  • Any class that reports extra memory (reportExtraMemoryVisited) should include that in the estimated size.
  • E.g. CodeBlock, JSGenericTypedArrayView, WeakMapData, etc.

Subclasses with "Copied Space" storage:

  • Any class with data in copied space (copyBackingStore) should include that in the estimated size.
  • E.g. JSObject, JSGenericTypedArrayView, JSMap, JSSet, DirectArguments, etc.

Add reportExtraMemoryVisited for UnlinkedCodeBlock's compressed unlinked
instructions because this can be larger than 1kb, which is significant.

This has one special case for RegExp generated bytecode / JIT code, which
does not currently fall into the extra memory cost or copied space storage.
In practice I haven't seen this grow to a significant cost.

  • runtime/ClassInfo.h:

Add the new estimatedSize method to the table.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedCodeBlock::visitChildren):
(JSC::UnlinkedCodeBlock::estimatedSize):
(JSC::UnlinkedCodeBlock::setInstructions):

  • bytecode/UnlinkedCodeBlock.h:

Report an extra memory cost for unlinked code blocks like
we do for linked code blocks.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::estimatedSize):

  • bytecode/CodeBlock.h:
  • bytecode/UnlinkedInstructionStream.cpp:

(JSC::UnlinkedInstructionStream::sizeInBytes):

  • bytecode/UnlinkedInstructionStream.h:
  • runtime/DirectArguments.cpp:

(JSC::DirectArguments::estimatedSize):

  • runtime/DirectArguments.h:
  • runtime/JSCell.cpp:

(JSC::JSCell::estimatedSizeInBytes):
(JSC::JSCell::estimatedSize):

  • runtime/JSCell.h:
  • runtime/JSGenericTypedArrayView.h:
  • runtime/JSGenericTypedArrayViewInlines.h:

(JSC::JSGenericTypedArrayView<Adaptor>::estimatedSize):

  • runtime/JSMap.cpp:

(JSC::JSMap::estimatedSize):

  • runtime/JSMap.h:
  • runtime/JSObject.cpp:

(JSC::JSObject::visitButterfly):

  • runtime/JSObject.h:
  • runtime/JSSet.cpp:

(JSC::JSSet::estimatedSize):

  • runtime/JSSet.h:
  • runtime/JSString.cpp:

(JSC::JSString::estimatedSize):

  • runtime/JSString.h:
  • runtime/MapData.h:

(JSC::MapDataImpl::capacityInBytes):

  • runtime/WeakMapData.cpp:

(JSC::WeakMapData::estimatedSize):
(JSC::WeakMapData::visitChildren):

  • runtime/WeakMapData.h:

Implement estimated size following the pattern of reporting
extra visited size, or copy space memory.

  • runtime/RegExp.cpp:

(JSC::RegExp::estimatedSize):

  • runtime/RegExp.h:
  • yarr/YarrInterpreter.h:

(JSC::Yarr::ByteDisjunction::estimatedSizeInBytes):
(JSC::Yarr::BytecodePattern::estimatedSizeInBytes):

  • yarr/YarrJIT.h:

(JSC::Yarr::YarrCodeBlock::size):
Include generated bytecode / JITCode to a RegExp's size.

Location:
trunk/Source/JavaScriptCore/runtime
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/ClassInfo.h

    r194175 r197379  
    106106    typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&);
    107107    DumpToStreamFunctionPtr dumpToStream;
     108
     109    typedef size_t (*EstimatedSizeFunctionPtr)(JSCell*);
     110    EstimatedSizeFunctionPtr estimatedSize;
    108111};
    109112
     
    152155        &ClassName::slowDownAndWasteMemory, \
    153156        &ClassName::getTypedArrayImpl, \
    154         &ClassName::dumpToStream \
     157        &ClassName::dumpToStream, \
     158        &ClassName::estimatedSize \
    155159    }, \
    156160    ClassName::TypedArrayStorageType
  • trunk/Source/JavaScriptCore/runtime/DirectArguments.cpp

    r190896 r197379  
    8484   
    8585    return result;
     86}
     87
     88size_t DirectArguments::estimatedSize(JSCell* cell)
     89{
     90    DirectArguments* thisObject = jsCast<DirectArguments*>(cell);
     91    size_t overridesSize = thisObject->m_overrides ? thisObject->overridesSize() : 0;
     92    return Base::estimatedSize(cell) + overridesSize;
    8693}
    8794
  • trunk/Source/JavaScriptCore/runtime/DirectArguments.h

    r190896 r197379  
    5656    // Creates an arguments object by copying the argumnets from the stack.
    5757    static DirectArguments* createByCopying(ExecState*);
    58    
     58
     59    static size_t estimatedSize(JSCell*);
    5960    static void visitChildren(JSCell*, SlotVisitor&);
    6061    static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
  • trunk/Source/JavaScriptCore/runtime/JSCell.cpp

    r179429 r197379  
    5252}
    5353
     54size_t JSCell::estimatedSizeInBytes() const
     55{
     56    return methodTable()->estimatedSize(const_cast<JSCell*>(this));
     57}
     58
     59size_t JSCell::estimatedSize(JSCell* cell)
     60{
     61    return MarkedBlock::blockFor(cell)->cellSize();
     62}
     63
    5464void JSCell::copyBackingStore(JSCell*, CopyVisitor&, CopyToken)
    5565{
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r190569 r197379  
    135135    void dump(PrintStream&) const;
    136136    JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&);
     137
     138    size_t estimatedSizeInBytes() const;
     139    JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*);
     140
    137141    static void visitChildren(JSCell*, SlotVisitor&);
    138142    JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
  • trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h

    r197192 r197379  
    284284   
    285285    static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    286    
     286
     287    static size_t estimatedSize(JSCell*);
    287288    static void visitChildren(JSCell*, SlotVisitor&);
    288289    static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
  • trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h

    r197192 r197379  
    407407
    408408template<typename Adaptor>
     409size_t JSGenericTypedArrayView<Adaptor>::estimatedSize(JSCell* cell)
     410{
     411    JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
     412
     413    if (thisObject->m_mode == OversizeTypedArray)
     414        return Base::estimatedSize(thisObject) + thisObject->byteSize();
     415    if (thisObject->m_mode == FastTypedArray && thisObject->m_vector)
     416        return Base::estimatedSize(thisObject) + thisObject->byteSize();
     417
     418    return Base::estimatedSize(thisObject);
     419}
     420
     421template<typename Adaptor>
    409422void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor& visitor)
    410423{
  • trunk/Source/JavaScriptCore/runtime/JSMap.cpp

    r190563 r197379  
    4242    JSMap* thisObject = jsCast<JSMap*>(cell);
    4343    thisObject->JSMap::~JSMap();
     44}
     45
     46size_t JSMap::estimatedSize(JSCell* cell)
     47{
     48    JSMap* thisObject = jsCast<JSMap*>(cell);
     49    size_t mapDataSize = thisObject->m_mapData.capacityInBytes();
     50    return Base::estimatedSize(cell) + mapDataSize;
    4451}
    4552
  • trunk/Source/JavaScriptCore/runtime/JSMap.h

    r190896 r197379  
    123123
    124124    static void destroy(JSCell*);
     125    static size_t estimatedSize(JSCell*);
    125126    static void visitChildren(JSCell*, SlotVisitor&);
    126127    static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r197144 r197379  
    196196        break;
    197197    }
     198}
     199
     200size_t JSObject::estimatedSize(JSCell* cell)
     201{
     202    JSObject* thisObject = jsCast<JSObject*>(cell);
     203    size_t butterflyOutOfLineSize = thisObject->m_butterfly ? thisObject->structure()->outOfLineSize() : 0;
     204    return Base::estimatedSize(cell) + butterflyOutOfLineSize;
    198205}
    199206
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r197144 r197379  
    9595public:
    9696    typedef JSCell Base;
    97        
     97
     98    JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*);
    9899    JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
    99100    JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
  • trunk/Source/JavaScriptCore/runtime/JSSet.cpp

    r190563 r197379  
    4444}
    4545
     46size_t JSSet::estimatedSize(JSCell* cell)
     47{
     48    JSSet* thisObject = jsCast<JSSet*>(cell);
     49    size_t setDataSize = thisObject->m_setData.capacityInBytes();
     50    return Base::estimatedSize(cell) + setDataSize;
     51}
     52
    4653void JSSet::visitChildren(JSCell* cell, SlotVisitor& visitor)
    4754{
  • trunk/Source/JavaScriptCore/runtime/JSSet.h

    r190896 r197379  
    118118
    119119    static void destroy(JSCell*);
     120    static size_t estimatedSize(JSCell*);
    120121    static void visitChildren(JSCell*, SlotVisitor&);
    121122    static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
  • trunk/Source/JavaScriptCore/runtime/JSString.cpp

    r196761 r197379  
    7373}
    7474
     75size_t JSString::estimatedSize(JSCell* cell)
     76{
     77    JSString* thisObject = jsCast<JSString*>(cell);
     78    if (thisObject->isRope())
     79        return Base::estimatedSize(cell);
     80    return Base::estimatedSize(cell) + thisObject->m_value.impl()->costDuringGC();
     81}
     82
    7583void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor)
    7684{
  • trunk/Source/JavaScriptCore/runtime/JSString.h

    r196810 r197379  
    182182
    183183    static void dumpToStream(const JSCell*, PrintStream&);
     184    static size_t estimatedSize(JSCell*);
    184185    static void visitChildren(JSCell*, SlotVisitor&);
    185186
  • trunk/Source/JavaScriptCore/runtime/MapData.h

    r196108 r197379  
    112112    void copyBackingStore(CopyVisitor&, CopyToken);
    113113
     114    size_t capacityInBytes() const { return m_capacity * sizeof(Entry); }
     115
    114116private:
    115117    typedef WTF::UnsignedWithZeroKeyHashTraits<int32_t> IndexTraits;
     
    119121    typedef HashMap<StringImpl*, int32_t, typename WTF::DefaultHash<StringImpl*>::Hash, WTF::HashTraits<StringImpl*>, IndexTraits> StringKeyedMap;
    120122    typedef HashMap<SymbolImpl*, int32_t, typename WTF::PtrHash<SymbolImpl*>, WTF::HashTraits<SymbolImpl*>, IndexTraits> SymbolKeyedMap;
    121 
    122     size_t capacityInBytes() { return m_capacity * sizeof(Entry); }
    123123
    124124    ALWAYS_INLINE Entry* find(ExecState*, KeyType);
  • trunk/Source/JavaScriptCore/runtime/RegExp.cpp

    r188394 r197379  
    257257}
    258258
     259size_t RegExp::estimatedSize(JSCell* cell)
     260{
     261    RegExp* thisObject = static_cast<RegExp*>(cell);
     262    size_t regexDataSize = thisObject->m_regExpBytecode ? thisObject->m_regExpBytecode->estimatedSizeInBytes() : 0;
     263#if ENABLE(YARR_JIT)
     264    regexDataSize += thisObject->m_regExpJITCode.size();
     265#endif
     266    return Base::estimatedSize(cell) + regexDataSize;
     267}
     268
    259269RegExp* RegExp::createWithoutCaching(VM& vm, const String& patternString, RegExpFlags flags)
    260270{
  • trunk/Source/JavaScriptCore/runtime/RegExp.h

    r188394 r197379  
    5151    static const bool needsDestruction = true;
    5252    static void destroy(JSCell*);
     53    static size_t estimatedSize(JSCell*);
    5354
    5455    bool global() const { return m_flags & FlagGlobal; }
  • trunk/Source/JavaScriptCore/runtime/WeakMapData.cpp

    r190569 r197379  
    5555}
    5656
     57size_t WeakMapData::estimatedSize(JSCell* cell)
     58{
     59    WeakMapData* thisObj = jsCast<WeakMapData*>(cell);
     60    return Base::estimatedSize(cell) + (thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
     61}
     62
    5763void WeakMapData::visitChildren(JSCell* cell, SlotVisitor& visitor)
    5864{
     
    6470    // Rough approximation of the external storage needed for the hashtable.
    6571    // This isn't exact, but it is close enough, and proportional to the actual
    66     // external mermory usage.
     72    // external memory usage.
    6773    visitor.reportExtraMemoryVisited(thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
    6874}
  • trunk/Source/JavaScriptCore/runtime/WeakMapData.h

    r182747 r197379  
    7171    WeakMapData(VM&);
    7272    static void destroy(JSCell*);
     73    static size_t estimatedSize(JSCell*);
    7374    static void visitChildren(JSCell*, SlotVisitor&);
    7475    void finishCreation(VM&);
Note: See TracChangeset for help on using the changeset viewer.