LCOV - code coverage report
Current view: top level - js/public - MemoryMetrics.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 280 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 63 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef js_MemoryMetrics_h
       8             : #define js_MemoryMetrics_h
       9             : 
      10             : // These declarations are highly likely to change in the future. Depend on them
      11             : // at your own risk.
      12             : 
      13             : #include "mozilla/MemoryReporting.h"
      14             : #include "mozilla/PodOperations.h"
      15             : #include "mozilla/TypeTraits.h"
      16             : 
      17             : #include <string.h>
      18             : 
      19             : #include "jsalloc.h"
      20             : #include "jspubtd.h"
      21             : 
      22             : #include "js/HashTable.h"
      23             : #include "js/TracingAPI.h"
      24             : #include "js/Utility.h"
      25             : #include "js/Vector.h"
      26             : 
      27             : class nsISupports;      // Needed for ObjectPrivateVisitor.
      28             : 
      29             : namespace JS {
      30             : 
      31             : struct TabSizes
      32             : {
      33             :     enum Kind {
      34             :         Objects,
      35             :         Strings,
      36             :         Private,
      37             :         Other
      38             :     };
      39             : 
      40           0 :     TabSizes() { mozilla::PodZero(this); }
      41             : 
      42           0 :     void add(Kind kind, size_t n) {
      43           0 :         switch (kind) {
      44           0 :             case Objects: objects  += n; break;
      45           0 :             case Strings: strings  += n; break;
      46           0 :             case Private: private_ += n; break;
      47           0 :             case Other:   other    += n; break;
      48           0 :             default:      MOZ_CRASH("bad TabSizes kind");
      49             :         }
      50           0 :     }
      51             : 
      52             :     size_t objects;
      53             :     size_t strings;
      54             :     size_t private_;
      55             :     size_t other;
      56             : };
      57             : 
      58             : /** These are the measurements used by Servo. */
      59             : struct ServoSizes
      60             : {
      61             :     enum Kind {
      62             :         GCHeapUsed,
      63             :         GCHeapUnused,
      64             :         GCHeapAdmin,
      65             :         GCHeapDecommitted,
      66             :         MallocHeap,
      67             :         NonHeap,
      68             :         Ignore
      69             :     };
      70             : 
      71             :     ServoSizes() { mozilla::PodZero(this); }
      72             : 
      73           0 :     void add(Kind kind, size_t n) {
      74           0 :         switch (kind) {
      75           0 :             case GCHeapUsed:        gcHeapUsed        += n; break;
      76           0 :             case GCHeapUnused:      gcHeapUnused      += n; break;
      77           0 :             case GCHeapAdmin:       gcHeapAdmin       += n; break;
      78           0 :             case GCHeapDecommitted: gcHeapDecommitted += n; break;
      79           0 :             case MallocHeap:        mallocHeap        += n; break;
      80           0 :             case NonHeap:           nonHeap           += n; break;
      81           0 :             case Ignore:            /* do nothing */        break;
      82           0 :             default:                MOZ_CRASH("bad ServoSizes kind");
      83             :         }
      84           0 :     }
      85             : 
      86             :     size_t gcHeapUsed;
      87             :     size_t gcHeapUnused;
      88             :     size_t gcHeapAdmin;
      89             :     size_t gcHeapDecommitted;
      90             :     size_t mallocHeap;
      91             :     size_t nonHeap;
      92             : };
      93             : 
      94             : } // namespace JS
      95             : 
      96             : namespace js {
      97             : 
      98             : /**
      99             :  * In memory reporting, we have concept of "sundries", line items which are too
     100             :  * small to be worth reporting individually.  Under some circumstances, a memory
     101             :  * reporter gets tossed into the sundries bucket if it's smaller than
     102             :  * MemoryReportingSundriesThreshold() bytes.
     103             :  *
     104             :  * We need to define this value here, rather than in the code which actually
     105             :  * generates the memory reports, because NotableStringInfo uses this value.
     106             :  */
     107             : JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold();
     108             : 
     109             : /**
     110             :  * This hash policy avoids flattening ropes (which perturbs the site being
     111             :  * measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
     112             :  * on every hash and match! Beware.
     113             :  */
     114             : struct InefficientNonFlatteningStringHashPolicy
     115             : {
     116             :     typedef JSString* Lookup;
     117             :     static HashNumber hash(const Lookup& l);
     118             :     static bool match(const JSString* const& k, const Lookup& l);
     119             : };
     120             : 
     121             : struct CStringHashPolicy
     122             : {
     123             :     typedef const char* Lookup;
     124             :     static HashNumber hash(const Lookup& l);
     125             :     static bool match(const char* const& k, const Lookup& l);
     126             : };
     127             : 
     128             : // This file features many classes with numerous size_t fields, and each such
     129             : // class has one or more methods that need to operate on all of these fields.
     130             : // Writing these individually is error-prone -- it's easy to add a new field
     131             : // without updating all the required methods.  So we define a single macro list
     132             : // in each class to name the fields (and notable characteristics of them), and
     133             : // then use the following macros to transform those lists into the required
     134             : // methods.
     135             : //
     136             : // - The |tabKind| value is used when measuring TabSizes.
     137             : //
     138             : // - The |servoKind| value is used when measuring ServoSizes and also for
     139             : //   the various sizeOfLiveGCThings() methods.
     140             : //
     141             : // In some classes, one or more of the macro arguments aren't used.  We use '_'
     142             : // for those.
     143             : //
     144             : #define DECL_SIZE(tabKind, servoKind, mSize)        size_t mSize;
     145             : #define ZERO_SIZE(tabKind, servoKind, mSize)        mSize(0),
     146             : #define COPY_OTHER_SIZE(tabKind, servoKind, mSize)  mSize(other.mSize),
     147             : #define ADD_OTHER_SIZE(tabKind, servoKind, mSize)   mSize += other.mSize;
     148             : #define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \
     149             :     MOZ_ASSERT(mSize >= other.mSize); \
     150             :     mSize -= other.mSize;
     151             : #define ADD_SIZE_TO_N(tabKind, servoKind, mSize)                  n += mSize;
     152             : #define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \
     153             :     /* Avoid self-comparison warnings by comparing enums indirectly. */ \
     154             :     n += (mozilla::IsSame<int[ServoSizes::servoKind], int[ServoSizes::GCHeapUsed]>::value) \
     155             :          ? mSize \
     156             :          : 0;
     157             : #define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize)               sizes->add(JS::TabSizes::tabKind, mSize);
     158             : #define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize)             sizes->add(JS::ServoSizes::servoKind, mSize);
     159             : 
     160             : } // namespace js
     161             : 
     162             : namespace JS {
     163             : 
     164             : struct ClassInfo
     165             : {
     166             : #define FOR_EACH_SIZE(macro) \
     167             :     macro(Objects, GCHeapUsed, objectsGCHeap) \
     168             :     macro(Objects, MallocHeap, objectsMallocHeapSlots) \
     169             :     macro(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
     170             :     macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
     171             :     macro(Objects, MallocHeap, objectsMallocHeapMisc) \
     172             :     macro(Objects, NonHeap,    objectsNonHeapElementsNormal) \
     173             :     macro(Objects, NonHeap,    objectsNonHeapElementsShared) \
     174             :     macro(Objects, NonHeap,    objectsNonHeapElementsWasm) \
     175             :     macro(Objects, NonHeap,    objectsNonHeapCodeWasm)
     176             : 
     177           0 :     ClassInfo()
     178           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     179           0 :         wasmGuardPages(0)
     180           0 :     {}
     181             : 
     182           0 :     void add(const ClassInfo& other) {
     183           0 :         FOR_EACH_SIZE(ADD_OTHER_SIZE)
     184           0 :     }
     185             : 
     186           0 :     void subtract(const ClassInfo& other) {
     187           0 :         FOR_EACH_SIZE(SUB_OTHER_SIZE)
     188           0 :     }
     189             : 
     190           0 :     size_t sizeOfAllThings() const {
     191           0 :         size_t n = 0;
     192           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N)
     193           0 :         return n;
     194             :     }
     195             : 
     196           0 :     bool isNotable() const {
     197             :         static const size_t NotabilityThreshold = 16 * 1024;
     198           0 :         return sizeOfAllThings() >= NotabilityThreshold;
     199             :     }
     200             : 
     201           0 :     size_t sizeOfLiveGCThings() const {
     202           0 :         size_t n = 0;
     203           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
     204           0 :         return n;
     205             :     }
     206             : 
     207           0 :     void addToTabSizes(TabSizes* sizes) const {
     208           0 :         FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
     209           0 :     }
     210             : 
     211           0 :     void addToServoSizes(ServoSizes *sizes) const {
     212           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     213           0 :     }
     214             : 
     215             :     FOR_EACH_SIZE(DECL_SIZE)
     216             :     size_t wasmGuardPages;
     217             : 
     218             : #undef FOR_EACH_SIZE
     219             : };
     220             : 
     221             : struct ShapeInfo
     222             : {
     223             : #define FOR_EACH_SIZE(macro) \
     224             :     macro(Other,   GCHeapUsed, shapesGCHeapTree) \
     225             :     macro(Other,   GCHeapUsed, shapesGCHeapDict) \
     226             :     macro(Other,   GCHeapUsed, shapesGCHeapBase) \
     227             :     macro(Other,   MallocHeap, shapesMallocHeapTreeTables) \
     228             :     macro(Other,   MallocHeap, shapesMallocHeapDictTables) \
     229             :     macro(Other,   MallocHeap, shapesMallocHeapTreeKids)
     230             : 
     231           0 :     ShapeInfo()
     232           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     233           0 :         dummy()
     234           0 :     {}
     235             : 
     236           0 :     void add(const ShapeInfo& other) {
     237           0 :         FOR_EACH_SIZE(ADD_OTHER_SIZE)
     238           0 :     }
     239             : 
     240             :     void subtract(const ShapeInfo& other) {
     241             :         FOR_EACH_SIZE(SUB_OTHER_SIZE)
     242             :     }
     243             : 
     244             :     size_t sizeOfAllThings() const {
     245             :         size_t n = 0;
     246             :         FOR_EACH_SIZE(ADD_SIZE_TO_N)
     247             :         return n;
     248             :     }
     249             : 
     250           0 :     size_t sizeOfLiveGCThings() const {
     251           0 :         size_t n = 0;
     252           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
     253           0 :         return n;
     254             :     }
     255             : 
     256           0 :     void addToTabSizes(TabSizes* sizes) const {
     257           0 :         FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
     258           0 :     }
     259             : 
     260           0 :     void addToServoSizes(ServoSizes *sizes) const {
     261           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     262           0 :     }
     263             : 
     264             :     FOR_EACH_SIZE(DECL_SIZE)
     265             :     int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
     266             : 
     267             : #undef FOR_EACH_SIZE
     268             : };
     269             : 
     270             : /**
     271             :  * Holds data about a notable class (one whose combined object and shape
     272             :  * instances use more than a certain amount of memory) so we can report it
     273             :  * individually.
     274             :  *
     275             :  * The only difference between this class and ClassInfo is that this class
     276             :  * holds a copy of the filename.
     277             :  */
     278             : struct NotableClassInfo : public ClassInfo
     279             : {
     280             :     NotableClassInfo();
     281             :     NotableClassInfo(const char* className, const ClassInfo& info);
     282             :     NotableClassInfo(NotableClassInfo&& info);
     283             :     NotableClassInfo& operator=(NotableClassInfo&& info);
     284             : 
     285           0 :     ~NotableClassInfo() {
     286           0 :         js_free(className_);
     287           0 :     }
     288             : 
     289             :     char* className_;
     290             : 
     291             :   private:
     292             :     NotableClassInfo(const NotableClassInfo& info) = delete;
     293             : };
     294             : 
     295             : /** Data for tracking JIT-code memory usage. */
     296             : struct CodeSizes
     297             : {
     298             : #define FOR_EACH_SIZE(macro) \
     299             :     macro(_, NonHeap, ion) \
     300             :     macro(_, NonHeap, baseline) \
     301             :     macro(_, NonHeap, regexp) \
     302             :     macro(_, NonHeap, other) \
     303             :     macro(_, NonHeap, unused)
     304             : 
     305           0 :     CodeSizes()
     306           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     307           0 :         dummy()
     308           0 :     {}
     309             : 
     310           0 :     void addToServoSizes(ServoSizes *sizes) const {
     311           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     312           0 :     }
     313             : 
     314             :     FOR_EACH_SIZE(DECL_SIZE)
     315             :     int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
     316             : 
     317             : #undef FOR_EACH_SIZE
     318             : };
     319             : 
     320             : /** Data for tracking GC memory usage. */
     321             : struct GCSizes
     322             : {
     323             :     // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted
     324             :     // because we don't consider the nursery to be part of the GC heap.
     325             : #define FOR_EACH_SIZE(macro) \
     326             :     macro(_, MallocHeap, marker) \
     327             :     macro(_, NonHeap,    nurseryCommitted) \
     328             :     macro(_, MallocHeap, nurseryMallocedBuffers) \
     329             :     macro(_, MallocHeap, storeBufferVals) \
     330             :     macro(_, MallocHeap, storeBufferCells) \
     331             :     macro(_, MallocHeap, storeBufferSlots) \
     332             :     macro(_, MallocHeap, storeBufferWholeCells) \
     333             :     macro(_, MallocHeap, storeBufferGenerics)
     334             : 
     335           0 :     GCSizes()
     336           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     337           0 :         dummy()
     338           0 :     {}
     339             : 
     340           0 :     void addToServoSizes(ServoSizes *sizes) const {
     341           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     342           0 :     }
     343             : 
     344             :     FOR_EACH_SIZE(DECL_SIZE)
     345             :     int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
     346             : 
     347             : #undef FOR_EACH_SIZE
     348             : };
     349             : 
     350             : /**
     351             :  * This class holds information about the memory taken up by identical copies of
     352             :  * a particular string.  Multiple JSStrings may have their sizes aggregated
     353             :  * together into one StringInfo object.  Note that two strings with identical
     354             :  * chars will not be aggregated together if one is a short string and the other
     355             :  * is not.
     356             :  */
     357             : struct StringInfo
     358             : {
     359             : #define FOR_EACH_SIZE(macro) \
     360             :     macro(Strings, GCHeapUsed, gcHeapLatin1) \
     361             :     macro(Strings, GCHeapUsed, gcHeapTwoByte) \
     362             :     macro(Strings, MallocHeap, mallocHeapLatin1) \
     363             :     macro(Strings, MallocHeap, mallocHeapTwoByte)
     364             : 
     365           0 :     StringInfo()
     366           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     367           0 :         numCopies(0)
     368           0 :     {}
     369             : 
     370           0 :     void add(const StringInfo& other) {
     371           0 :         FOR_EACH_SIZE(ADD_OTHER_SIZE);
     372           0 :         numCopies++;
     373           0 :     }
     374             : 
     375           0 :     void subtract(const StringInfo& other) {
     376           0 :         FOR_EACH_SIZE(SUB_OTHER_SIZE);
     377           0 :         numCopies--;
     378           0 :     }
     379             : 
     380           0 :     bool isNotable() const {
     381             :         static const size_t NotabilityThreshold = 16 * 1024;
     382           0 :         size_t n = 0;
     383           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N)
     384           0 :         return n >= NotabilityThreshold;
     385             :     }
     386             : 
     387           0 :     size_t sizeOfLiveGCThings() const {
     388           0 :         size_t n = 0;
     389           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
     390           0 :         return n;
     391             :     }
     392             : 
     393           0 :     void addToTabSizes(TabSizes* sizes) const {
     394           0 :         FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
     395           0 :     }
     396             : 
     397           0 :     void addToServoSizes(ServoSizes *sizes) const {
     398           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     399           0 :     }
     400             : 
     401             :     FOR_EACH_SIZE(DECL_SIZE)
     402             :     uint32_t numCopies;     // How many copies of the string have we seen?
     403             : 
     404             : #undef FOR_EACH_SIZE
     405             : };
     406             : 
     407             : /**
     408             :  * Holds data about a notable string (one which, counting all duplicates, uses
     409             :  * more than a certain amount of memory) so we can report it individually.
     410             :  *
     411             :  * The only difference between this class and StringInfo is that
     412             :  * NotableStringInfo holds a copy of some or all of the string's chars.
     413             :  */
     414             : struct NotableStringInfo : public StringInfo
     415             : {
     416             :     static const size_t MAX_SAVED_CHARS = 1024;
     417             : 
     418             :     NotableStringInfo();
     419             :     NotableStringInfo(JSString* str, const StringInfo& info);
     420             :     NotableStringInfo(NotableStringInfo&& info);
     421             :     NotableStringInfo& operator=(NotableStringInfo&& info);
     422             : 
     423           0 :     ~NotableStringInfo() {
     424           0 :         js_free(buffer);
     425           0 :     }
     426             : 
     427             :     char* buffer;
     428             :     size_t length;
     429             : 
     430             :   private:
     431             :     NotableStringInfo(const NotableStringInfo& info) = delete;
     432             : };
     433             : 
     434             : /**
     435             :  * This class holds information about the memory taken up by script sources
     436             :  * from a particular file.
     437             :  */
     438             : struct ScriptSourceInfo
     439             : {
     440             : #define FOR_EACH_SIZE(macro) \
     441             :     macro(_, MallocHeap, misc)
     442             : 
     443           0 :     ScriptSourceInfo()
     444           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     445           0 :         numScripts(0)
     446           0 :     {}
     447             : 
     448           0 :     void add(const ScriptSourceInfo& other) {
     449           0 :         FOR_EACH_SIZE(ADD_OTHER_SIZE)
     450           0 :         numScripts++;
     451           0 :     }
     452             : 
     453           0 :     void subtract(const ScriptSourceInfo& other) {
     454           0 :         FOR_EACH_SIZE(SUB_OTHER_SIZE)
     455           0 :         numScripts--;
     456           0 :     }
     457             : 
     458           0 :     void addToServoSizes(ServoSizes *sizes) const {
     459           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     460           0 :     }
     461             : 
     462           0 :     bool isNotable() const {
     463             :         static const size_t NotabilityThreshold = 16 * 1024;
     464           0 :         size_t n = 0;
     465           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N)
     466           0 :         return n >= NotabilityThreshold;
     467             :     }
     468             : 
     469             :     FOR_EACH_SIZE(DECL_SIZE)
     470             :     uint32_t numScripts;    // How many ScriptSources come from this file? (It
     471             :                             // can be more than one in XML files that have
     472             :                             // multiple scripts in CDATA sections.)
     473             : #undef FOR_EACH_SIZE
     474             : };
     475             : 
     476             : /**
     477             :  * Holds data about a notable script source file (one whose combined
     478             :  * script sources use more than a certain amount of memory) so we can report it
     479             :  * individually.
     480             :  *
     481             :  * The only difference between this class and ScriptSourceInfo is that this
     482             :  * class holds a copy of the filename.
     483             :  */
     484             : struct NotableScriptSourceInfo : public ScriptSourceInfo
     485             : {
     486             :     NotableScriptSourceInfo();
     487             :     NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info);
     488             :     NotableScriptSourceInfo(NotableScriptSourceInfo&& info);
     489             :     NotableScriptSourceInfo& operator=(NotableScriptSourceInfo&& info);
     490             : 
     491           0 :     ~NotableScriptSourceInfo() {
     492           0 :         js_free(filename_);
     493           0 :     }
     494             : 
     495             :     char* filename_;
     496             : 
     497             :   private:
     498             :     NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete;
     499             : };
     500             : 
     501             : /**
     502             :  * These measurements relate directly to the JSRuntime, and not to zones and
     503             :  * compartments within it.
     504             :  */
     505             : struct RuntimeSizes
     506             : {
     507             : #define FOR_EACH_SIZE(macro) \
     508             :     macro(_, MallocHeap, object) \
     509             :     macro(_, MallocHeap, atomsTable) \
     510             :     macro(_, MallocHeap, atomsMarkBitmaps) \
     511             :     macro(_, MallocHeap, contexts) \
     512             :     macro(_, MallocHeap, temporary) \
     513             :     macro(_, MallocHeap, interpreterStack) \
     514             :     macro(_, MallocHeap, mathCache) \
     515             :     macro(_, MallocHeap, sharedImmutableStringsCache) \
     516             :     macro(_, MallocHeap, sharedIntlData) \
     517             :     macro(_, MallocHeap, uncompressedSourceCache) \
     518             :     macro(_, MallocHeap, scriptData) \
     519             :     macro(_, MallocHeap, tracelogger)
     520             : 
     521           0 :     RuntimeSizes()
     522           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     523             :         scriptSourceInfo(),
     524             :         code(),
     525             :         gc(),
     526           0 :         notableScriptSources()
     527             :     {
     528           0 :         allScriptSources = js_new<ScriptSourcesHashMap>();
     529           0 :         if (!allScriptSources || !allScriptSources->init())
     530           0 :             MOZ_CRASH("oom");
     531           0 :     }
     532             : 
     533           0 :     ~RuntimeSizes() {
     534             :         // |allScriptSources| is usually deleted and set to nullptr before this
     535             :         // destructor runs. But there are failure cases due to OOMs that may
     536             :         // prevent that, so it doesn't hurt to try again here.
     537           0 :         js_delete(allScriptSources);
     538           0 :     }
     539             : 
     540           0 :     void addToServoSizes(ServoSizes *sizes) const {
     541           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     542           0 :         scriptSourceInfo.addToServoSizes(sizes);
     543           0 :         code.addToServoSizes(sizes);
     544           0 :         gc.addToServoSizes(sizes);
     545           0 :     }
     546             : 
     547             :     // The script source measurements in |scriptSourceInfo| are initially for
     548             :     // all script sources.  At the end, if the measurement granularity is
     549             :     // FineGrained, we subtract the measurements of the notable script sources
     550             :     // and move them into |notableScriptSources|.
     551             :     FOR_EACH_SIZE(DECL_SIZE)
     552             :     ScriptSourceInfo scriptSourceInfo;
     553             :     CodeSizes code;
     554             :     GCSizes gc;
     555             : 
     556             :     typedef js::HashMap<const char*, ScriptSourceInfo,
     557             :                         js::CStringHashPolicy,
     558             :                         js::SystemAllocPolicy> ScriptSourcesHashMap;
     559             : 
     560             :     // |allScriptSources| is only used transiently.  During the reporting phase
     561             :     // it is filled with info about every script source in the runtime.  It's
     562             :     // then used to fill in |notableScriptSources| (which actually gets
     563             :     // reported), and immediately discarded afterwards.
     564             :     ScriptSourcesHashMap* allScriptSources;
     565             :     js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy> notableScriptSources;
     566             : 
     567             : #undef FOR_EACH_SIZE
     568             : };
     569             : 
     570             : struct UnusedGCThingSizes
     571             : {
     572             : #define FOR_EACH_SIZE(macro) \
     573             :     macro(Other, GCHeapUnused, object) \
     574             :     macro(Other, GCHeapUnused, script) \
     575             :     macro(Other, GCHeapUnused, lazyScript) \
     576             :     macro(Other, GCHeapUnused, shape) \
     577             :     macro(Other, GCHeapUnused, baseShape) \
     578             :     macro(Other, GCHeapUnused, objectGroup) \
     579             :     macro(Other, GCHeapUnused, string) \
     580             :     macro(Other, GCHeapUnused, symbol) \
     581             :     macro(Other, GCHeapUnused, jitcode) \
     582             :     macro(Other, GCHeapUnused, scope) \
     583             :     macro(Other, GCHeapUnused, regExpShared)
     584             : 
     585           0 :     UnusedGCThingSizes()
     586           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     587           0 :         dummy()
     588           0 :     {}
     589             : 
     590           0 :     UnusedGCThingSizes(UnusedGCThingSizes&& other)
     591           0 :       : FOR_EACH_SIZE(COPY_OTHER_SIZE)
     592           0 :         dummy()
     593           0 :     {}
     594             : 
     595           0 :     void addToKind(JS::TraceKind kind, intptr_t n) {
     596           0 :         switch (kind) {
     597           0 :           case JS::TraceKind::Object:       object += n;       break;
     598           0 :           case JS::TraceKind::String:       string += n;       break;
     599           0 :           case JS::TraceKind::Symbol:       symbol += n;       break;
     600           0 :           case JS::TraceKind::Script:       script += n;       break;
     601           0 :           case JS::TraceKind::Shape:        shape += n;        break;
     602           0 :           case JS::TraceKind::BaseShape:    baseShape += n;    break;
     603           0 :           case JS::TraceKind::JitCode:      jitcode += n;      break;
     604           0 :           case JS::TraceKind::LazyScript:   lazyScript += n;   break;
     605           0 :           case JS::TraceKind::ObjectGroup:  objectGroup += n;  break;
     606           0 :           case JS::TraceKind::Scope:        scope += n;        break;
     607           0 :           case JS::TraceKind::RegExpShared: regExpShared += n; break;
     608             :           default:
     609           0 :             MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
     610             :         }
     611           0 :     }
     612             : 
     613           0 :     void addSizes(const UnusedGCThingSizes& other) {
     614           0 :         FOR_EACH_SIZE(ADD_OTHER_SIZE)
     615           0 :     }
     616             : 
     617           0 :     size_t totalSize() const {
     618           0 :         size_t n = 0;
     619           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N)
     620           0 :         return n;
     621             :     }
     622             : 
     623           0 :     void addToTabSizes(JS::TabSizes *sizes) const {
     624           0 :         FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
     625           0 :     }
     626             : 
     627           0 :     void addToServoSizes(JS::ServoSizes *sizes) const {
     628           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     629           0 :     }
     630             : 
     631             :     FOR_EACH_SIZE(DECL_SIZE)
     632             :     int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
     633             : 
     634             : #undef FOR_EACH_SIZE
     635             : };
     636             : 
     637             : struct ZoneStats
     638             : {
     639             : #define FOR_EACH_SIZE(macro) \
     640             :     macro(Other,   GCHeapUsed,  symbolsGCHeap) \
     641             :     macro(Other,   GCHeapAdmin, gcHeapArenaAdmin) \
     642             :     macro(Other,   GCHeapUsed,  lazyScriptsGCHeap) \
     643             :     macro(Other,   MallocHeap,  lazyScriptsMallocHeap) \
     644             :     macro(Other,   GCHeapUsed,  jitCodesGCHeap) \
     645             :     macro(Other,   GCHeapUsed,  objectGroupsGCHeap) \
     646             :     macro(Other,   MallocHeap,  objectGroupsMallocHeap) \
     647             :     macro(Other,   GCHeapUsed,  scopesGCHeap) \
     648             :     macro(Other,   MallocHeap,  scopesMallocHeap) \
     649             :     macro(Other,   GCHeapUsed,  regExpSharedsGCHeap) \
     650             :     macro(Other,   MallocHeap,  regExpSharedsMallocHeap) \
     651             :     macro(Other,   MallocHeap,  typePool) \
     652             :     macro(Other,   MallocHeap,  regexpZone) \
     653             :     macro(Other,   MallocHeap,  jitZone) \
     654             :     macro(Other,   MallocHeap,  baselineStubsOptimized) \
     655             :     macro(Other,   MallocHeap,  cachedCFG) \
     656             :     macro(Other,   MallocHeap,  uniqueIdMap) \
     657             :     macro(Other,   MallocHeap,  shapeTables)
     658             : 
     659           0 :     ZoneStats()
     660           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     661             :         unusedGCThings(),
     662             :         stringInfo(),
     663             :         shapeInfo(),
     664             :         extra(),
     665             :         allStrings(nullptr),
     666             :         notableStrings(),
     667           0 :         isTotals(true)
     668           0 :     {}
     669             : 
     670           0 :     ZoneStats(ZoneStats&& other)
     671           0 :       : FOR_EACH_SIZE(COPY_OTHER_SIZE)
     672           0 :         unusedGCThings(mozilla::Move(other.unusedGCThings)),
     673           0 :         stringInfo(mozilla::Move(other.stringInfo)),
     674           0 :         shapeInfo(mozilla::Move(other.shapeInfo)),
     675           0 :         extra(other.extra),
     676           0 :         allStrings(other.allStrings),
     677           0 :         notableStrings(mozilla::Move(other.notableStrings)),
     678           0 :         isTotals(other.isTotals)
     679             :     {
     680           0 :         other.allStrings = nullptr;
     681           0 :         MOZ_ASSERT(!other.isTotals);
     682           0 :     }
     683             : 
     684           0 :     ~ZoneStats() {
     685             :         // |allStrings| is usually deleted and set to nullptr before this
     686             :         // destructor runs. But there are failure cases due to OOMs that may
     687             :         // prevent that, so it doesn't hurt to try again here.
     688           0 :         js_delete(allStrings);
     689           0 :     }
     690             : 
     691             :     bool initStrings(JSRuntime* rt);
     692             : 
     693           0 :     void addSizes(const ZoneStats& other) {
     694           0 :         MOZ_ASSERT(isTotals);
     695           0 :         FOR_EACH_SIZE(ADD_OTHER_SIZE)
     696           0 :         unusedGCThings.addSizes(other.unusedGCThings);
     697           0 :         stringInfo.add(other.stringInfo);
     698           0 :         shapeInfo.add(other.shapeInfo);
     699           0 :     }
     700             : 
     701           0 :     size_t sizeOfLiveGCThings() const {
     702           0 :         MOZ_ASSERT(isTotals);
     703           0 :         size_t n = 0;
     704           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
     705           0 :         n += stringInfo.sizeOfLiveGCThings();
     706           0 :         n += shapeInfo.sizeOfLiveGCThings();
     707           0 :         return n;
     708             :     }
     709             : 
     710           0 :     void addToTabSizes(JS::TabSizes* sizes) const {
     711           0 :         MOZ_ASSERT(isTotals);
     712           0 :         FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
     713           0 :         unusedGCThings.addToTabSizes(sizes);
     714           0 :         stringInfo.addToTabSizes(sizes);
     715           0 :         shapeInfo.addToTabSizes(sizes);
     716           0 :     }
     717             : 
     718           0 :     void addToServoSizes(JS::ServoSizes *sizes) const {
     719           0 :         MOZ_ASSERT(isTotals);
     720           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     721           0 :         unusedGCThings.addToServoSizes(sizes);
     722           0 :         stringInfo.addToServoSizes(sizes);
     723           0 :         shapeInfo.addToServoSizes(sizes);
     724           0 :     }
     725             : 
     726             :     // These string measurements are initially for all strings.  At the end,
     727             :     // if the measurement granularity is FineGrained, we subtract the
     728             :     // measurements of the notable script sources and move them into
     729             :     // |notableStrings|.
     730             :     FOR_EACH_SIZE(DECL_SIZE)
     731             :     UnusedGCThingSizes unusedGCThings;
     732             :     StringInfo stringInfo;
     733             :     ShapeInfo shapeInfo;
     734             :     void* extra;    // This field can be used by embedders.
     735             : 
     736             :     typedef js::HashMap<JSString*, StringInfo,
     737             :                         js::InefficientNonFlatteningStringHashPolicy,
     738             :                         js::SystemAllocPolicy> StringsHashMap;
     739             : 
     740             :     // |allStrings| is only used transiently.  During the zone traversal it is
     741             :     // filled with info about every string in the zone.  It's then used to fill
     742             :     // in |notableStrings| (which actually gets reported), and immediately
     743             :     // discarded afterwards.
     744             :     StringsHashMap* allStrings;
     745             :     js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings;
     746             :     bool isTotals;
     747             : 
     748             : #undef FOR_EACH_SIZE
     749             : };
     750             : 
     751             : struct CompartmentStats
     752             : {
     753             :     // We assume that |objectsPrivate| is on the malloc heap, but it's not
     754             :     // actually guaranteed. But for Servo, at least, it's a moot point because
     755             :     // it doesn't provide an ObjectPrivateVisitor so the value will always be
     756             :     // zero.
     757             : #define FOR_EACH_SIZE(macro) \
     758             :     macro(Private, MallocHeap, objectsPrivate) \
     759             :     macro(Other,   GCHeapUsed, scriptsGCHeap) \
     760             :     macro(Other,   MallocHeap, scriptsMallocHeapData) \
     761             :     macro(Other,   MallocHeap, baselineData) \
     762             :     macro(Other,   MallocHeap, baselineStubsFallback) \
     763             :     macro(Other,   MallocHeap, ionData) \
     764             :     macro(Other,   MallocHeap, typeInferenceTypeScripts) \
     765             :     macro(Other,   MallocHeap, typeInferenceAllocationSiteTables) \
     766             :     macro(Other,   MallocHeap, typeInferenceArrayTypeTables) \
     767             :     macro(Other,   MallocHeap, typeInferenceObjectTypeTables) \
     768             :     macro(Other,   MallocHeap, compartmentObject) \
     769             :     macro(Other,   MallocHeap, compartmentTables) \
     770             :     macro(Other,   MallocHeap, innerViewsTable) \
     771             :     macro(Other,   MallocHeap, lazyArrayBuffersTable) \
     772             :     macro(Other,   MallocHeap, objectMetadataTable) \
     773             :     macro(Other,   MallocHeap, crossCompartmentWrappersTable) \
     774             :     macro(Other,   MallocHeap, savedStacksSet) \
     775             :     macro(Other,   MallocHeap, varNamesSet) \
     776             :     macro(Other,   MallocHeap, nonSyntacticLexicalScopesTable) \
     777             :     macro(Other,   MallocHeap, templateLiteralMap) \
     778             :     macro(Other,   MallocHeap, jitCompartment) \
     779             :     macro(Other,   MallocHeap, privateData)
     780             : 
     781           0 :     CompartmentStats()
     782           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     783             :         classInfo(),
     784             :         extra(),
     785             :         allClasses(nullptr),
     786             :         notableClasses(),
     787           0 :         isTotals(true)
     788           0 :     {}
     789             : 
     790           0 :     CompartmentStats(CompartmentStats&& other)
     791           0 :       : FOR_EACH_SIZE(COPY_OTHER_SIZE)
     792           0 :         classInfo(mozilla::Move(other.classInfo)),
     793           0 :         extra(other.extra),
     794           0 :         allClasses(other.allClasses),
     795           0 :         notableClasses(mozilla::Move(other.notableClasses)),
     796           0 :         isTotals(other.isTotals)
     797             :     {
     798           0 :         other.allClasses = nullptr;
     799           0 :         MOZ_ASSERT(!other.isTotals);
     800           0 :     }
     801             : 
     802             :     CompartmentStats(const CompartmentStats&) = delete; // disallow copying
     803             : 
     804           0 :     ~CompartmentStats() {
     805             :         // |allClasses| is usually deleted and set to nullptr before this
     806             :         // destructor runs. But there are failure cases due to OOMs that may
     807             :         // prevent that, so it doesn't hurt to try again here.
     808           0 :         js_delete(allClasses);
     809           0 :     }
     810             : 
     811             :     bool initClasses(JSRuntime* rt);
     812             : 
     813           0 :     void addSizes(const CompartmentStats& other) {
     814           0 :         MOZ_ASSERT(isTotals);
     815           0 :         FOR_EACH_SIZE(ADD_OTHER_SIZE)
     816           0 :         classInfo.add(other.classInfo);
     817           0 :     }
     818             : 
     819           0 :     size_t sizeOfLiveGCThings() const {
     820           0 :         MOZ_ASSERT(isTotals);
     821           0 :         size_t n = 0;
     822           0 :         FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
     823           0 :         n += classInfo.sizeOfLiveGCThings();
     824           0 :         return n;
     825             :     }
     826             : 
     827           0 :     void addToTabSizes(TabSizes* sizes) const {
     828           0 :         MOZ_ASSERT(isTotals);
     829           0 :         FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
     830           0 :         classInfo.addToTabSizes(sizes);
     831           0 :     }
     832             : 
     833           0 :     void addToServoSizes(ServoSizes *sizes) const {
     834           0 :         MOZ_ASSERT(isTotals);
     835           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
     836           0 :         classInfo.addToServoSizes(sizes);
     837           0 :     }
     838             : 
     839             :     // The class measurements in |classInfo| are initially for all classes.  At
     840             :     // the end, if the measurement granularity is FineGrained, we subtract the
     841             :     // measurements of the notable classes and move them into |notableClasses|.
     842             :     FOR_EACH_SIZE(DECL_SIZE)
     843             :     ClassInfo classInfo;
     844             :     void* extra;            // This field can be used by embedders.
     845             : 
     846             :     typedef js::HashMap<const char*, ClassInfo,
     847             :                         js::CStringHashPolicy,
     848             :                         js::SystemAllocPolicy> ClassesHashMap;
     849             : 
     850             :     // These are similar to |allStrings| and |notableStrings| in ZoneStats.
     851             :     ClassesHashMap* allClasses;
     852             :     js::Vector<NotableClassInfo, 0, js::SystemAllocPolicy> notableClasses;
     853             :     bool isTotals;
     854             : 
     855             : #undef FOR_EACH_SIZE
     856             : };
     857             : 
     858             : typedef js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> CompartmentStatsVector;
     859             : typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector;
     860             : 
     861           0 : struct RuntimeStats
     862             : {
     863             :     // |gcHeapChunkTotal| is ignored because it's the sum of all the other
     864             :     // values. |gcHeapGCThings| is ignored because it's the sum of some of the
     865             :     // values from the zones and compartments. Both of those values are not
     866             :     // reported directly, but are just present for sanity-checking other
     867             :     // values.
     868             : #define FOR_EACH_SIZE(macro) \
     869             :     macro(_, Ignore,            gcHeapChunkTotal) \
     870             :     macro(_, GCHeapDecommitted, gcHeapDecommittedArenas) \
     871             :     macro(_, GCHeapUnused,      gcHeapUnusedChunks) \
     872             :     macro(_, GCHeapUnused,      gcHeapUnusedArenas) \
     873             :     macro(_, GCHeapAdmin,       gcHeapChunkAdmin) \
     874             :     macro(_, Ignore,            gcHeapGCThings)
     875             : 
     876           0 :     explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
     877           0 :       : FOR_EACH_SIZE(ZERO_SIZE)
     878             :         runtime(),
     879             :         cTotals(),
     880             :         zTotals(),
     881             :         compartmentStatsVector(),
     882             :         zoneStatsVector(),
     883             :         currZoneStats(nullptr),
     884           0 :         mallocSizeOf_(mallocSizeOf)
     885           0 :     {}
     886             : 
     887             :     // Here's a useful breakdown of the GC heap.
     888             :     //
     889             :     // - rtStats.gcHeapChunkTotal
     890             :     //   - decommitted bytes
     891             :     //     - rtStats.gcHeapDecommittedArenas (decommitted arenas in non-empty chunks)
     892             :     //   - unused bytes
     893             :     //     - rtStats.gcHeapUnusedChunks (empty chunks)
     894             :     //     - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
     895             :     //     - rtStats.zTotals.unusedGCThings.totalSize() (empty GC thing slots within non-empty arenas)
     896             :     //   - used bytes
     897             :     //     - rtStats.gcHeapChunkAdmin
     898             :     //     - rtStats.zTotals.gcHeapArenaAdmin
     899             :     //     - rtStats.gcHeapGCThings (in-use GC things)
     900             :     //       == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings()
     901             :     //
     902             :     // It's possible that some arenas in empty chunks may be decommitted, but
     903             :     // we don't count those under rtStats.gcHeapDecommittedArenas because (a)
     904             :     // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
     905             :     // multiple of the chunk size, which is good.
     906             : 
     907           0 :     void addToServoSizes(ServoSizes *sizes) const {
     908           0 :         FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
     909           0 :         runtime.addToServoSizes(sizes);
     910           0 :     }
     911             : 
     912             :     FOR_EACH_SIZE(DECL_SIZE)
     913             : 
     914             :     RuntimeSizes runtime;
     915             : 
     916             :     CompartmentStats cTotals;   // The sum of this runtime's compartments' measurements.
     917             :     ZoneStats zTotals;          // The sum of this runtime's zones' measurements.
     918             : 
     919             :     CompartmentStatsVector compartmentStatsVector;
     920             :     ZoneStatsVector zoneStatsVector;
     921             : 
     922             :     ZoneStats* currZoneStats;
     923             : 
     924             :     mozilla::MallocSizeOf mallocSizeOf_;
     925             : 
     926             :     virtual void initExtraCompartmentStats(JSCompartment* c, CompartmentStats* cstats) = 0;
     927             :     virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0;
     928             : 
     929             : #undef FOR_EACH_SIZE
     930             : };
     931             : 
     932             : class ObjectPrivateVisitor
     933             : {
     934             :   public:
     935             :     // Within CollectRuntimeStats, this method is called for each JS object
     936             :     // that has an nsISupports pointer.
     937             :     virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0;
     938             : 
     939             :     // A callback that gets a JSObject's nsISupports pointer, if it has one.
     940             :     // Note: this function does *not* addref |iface|.
     941             :     typedef bool(*GetISupportsFun)(JSObject* obj, nsISupports** iface);
     942             :     GetISupportsFun getISupports_;
     943             : 
     944           0 :     explicit ObjectPrivateVisitor(GetISupportsFun getISupports)
     945           0 :       : getISupports_(getISupports)
     946           0 :     {}
     947             : };
     948             : 
     949             : extern JS_PUBLIC_API(bool)
     950             : CollectRuntimeStats(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVisitor* opv, bool anonymize);
     951             : 
     952             : extern JS_PUBLIC_API(size_t)
     953             : SystemCompartmentCount(JSContext* cx);
     954             : 
     955             : extern JS_PUBLIC_API(size_t)
     956             : UserCompartmentCount(JSContext* cx);
     957             : 
     958             : extern JS_PUBLIC_API(size_t)
     959             : PeakSizeOfTemporary(const JSContext* cx);
     960             : 
     961             : extern JS_PUBLIC_API(bool)
     962             : AddSizeOfTab(JSContext* cx, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf,
     963             :              ObjectPrivateVisitor* opv, TabSizes* sizes);
     964             : 
     965             : extern JS_PUBLIC_API(bool)
     966             : AddServoSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf,
     967             :                ObjectPrivateVisitor* opv, ServoSizes* sizes);
     968             : 
     969             : extern JS_PUBLIC_API(void)
     970             : CollectTraceLoggerStateStats(RuntimeStats* rtStats);
     971             : 
     972             : } // namespace JS
     973             : 
     974             : #undef DECL_SIZE
     975             : #undef ZERO_SIZE
     976             : #undef COPY_OTHER_SIZE
     977             : #undef ADD_OTHER_SIZE
     978             : #undef SUB_OTHER_SIZE
     979             : #undef ADD_SIZE_TO_N
     980             : #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
     981             : #undef ADD_TO_TAB_SIZES
     982             : 
     983             : #endif /* js_MemoryMetrics_h */

Generated by: LCOV version 1.13