js/src/vm/MemoryMetrics.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #include "js/MemoryMetrics.h"
     9 #include "mozilla/DebugOnly.h"
    11 #include "jsapi.h"
    12 #include "jscompartment.h"
    13 #include "jsgc.h"
    14 #include "jsobj.h"
    15 #include "jsscript.h"
    17 #include "jit/BaselineJIT.h"
    18 #include "jit/Ion.h"
    19 #include "vm/ArrayObject.h"
    20 #include "vm/Runtime.h"
    21 #include "vm/Shape.h"
    22 #include "vm/String.h"
    23 #include "vm/WrapperObject.h"
    25 using mozilla::DebugOnly;
    26 using mozilla::MallocSizeOf;
    27 using mozilla::Move;
    28 using mozilla::PodCopy;
    29 using mozilla::PodEqual;
    31 using namespace js;
    33 using JS::RuntimeStats;
    34 using JS::ObjectPrivateVisitor;
    35 using JS::ZoneStats;
    36 using JS::CompartmentStats;
    38 namespace js {
    40 JS_FRIEND_API(size_t)
    41 MemoryReportingSundriesThreshold()
    42 {
    43     return 8 * 1024;
    44 }
    46 /* static */ HashNumber
    47 InefficientNonFlatteningStringHashPolicy::hash(const Lookup &l)
    48 {
    49     ScopedJSFreePtr<jschar> ownedChars;
    50     const jschar *chars;
    51     if (l->hasPureChars()) {
    52         chars = l->pureChars();
    53     } else {
    54         // Slowest hash function evar!
    55         if (!l->copyNonPureChars(/* tcx */ nullptr, ownedChars))
    56             MOZ_CRASH("oom");
    57         chars = ownedChars;
    58     }
    60     return mozilla::HashString(chars, l->length());
    61 }
    63 /* static */ bool
    64 InefficientNonFlatteningStringHashPolicy::match(const JSString *const &k, const Lookup &l)
    65 {
    66     // We can't use js::EqualStrings, because that flattens our strings.
    67     if (k->length() != l->length())
    68         return false;
    70     const jschar *c1;
    71     ScopedJSFreePtr<jschar> ownedChars1;
    72     if (k->hasPureChars()) {
    73         c1 = k->pureChars();
    74     } else {
    75         if (!k->copyNonPureChars(/* tcx */ nullptr, ownedChars1))
    76             MOZ_CRASH("oom");
    77         c1 = ownedChars1;
    78     }
    80     const jschar *c2;
    81     ScopedJSFreePtr<jschar> ownedChars2;
    82     if (l->hasPureChars()) {
    83         c2 = l->pureChars();
    84     } else {
    85         if (!l->copyNonPureChars(/* tcx */ nullptr, ownedChars2))
    86             MOZ_CRASH("oom");
    87         c2 = ownedChars2;
    88     }
    90     return PodEqual(c1, c2, k->length());
    91 }
    93 /* static */ HashNumber
    94 CStringHashPolicy::hash(const Lookup &l)
    95 {
    96     return mozilla::HashString(l);
    97 }
    99 /* static */ bool
   100 CStringHashPolicy::match(const char *const &k, const Lookup &l)
   101 {
   102     return strcmp(k, l) == 0;
   103 }
   105 } // namespace js
   107 namespace JS {
   109 NotableStringInfo::NotableStringInfo()
   110   : StringInfo(),
   111     buffer(0),
   112     length(0)
   113 {
   114 }
   116 NotableStringInfo::NotableStringInfo(JSString *str, const StringInfo &info)
   117   : StringInfo(info),
   118     length(str->length())
   119 {
   120     size_t bufferSize = Min(str->length() + 1, size_t(MAX_SAVED_CHARS));
   121     buffer = js_pod_malloc<char>(bufferSize);
   122     if (!buffer) {
   123         MOZ_CRASH("oom");
   124     }
   126     const jschar* chars;
   127     ScopedJSFreePtr<jschar> ownedChars;
   128     if (str->hasPureChars()) {
   129         chars = str->pureChars();
   130     } else {
   131         if (!str->copyNonPureChars(/* tcx */ nullptr, ownedChars))
   132             MOZ_CRASH("oom");
   133         chars = ownedChars;
   134     }
   136     // We might truncate |str| even if it's much shorter than 1024 chars, if
   137     // |str| contains unicode chars.  Since this is just for a memory reporter,
   138     // we don't care.
   139     PutEscapedString(buffer, bufferSize, chars, str->length(), /* quote */ 0);
   140 }
   142 NotableStringInfo::NotableStringInfo(NotableStringInfo &&info)
   143   : StringInfo(Move(info)),
   144     length(info.length)
   145 {
   146     buffer = info.buffer;
   147     info.buffer = nullptr;
   148 }
   150 NotableStringInfo &NotableStringInfo::operator=(NotableStringInfo &&info)
   151 {
   152     MOZ_ASSERT(this != &info, "self-move assignment is prohibited");
   153     this->~NotableStringInfo();
   154     new (this) NotableStringInfo(Move(info));
   155     return *this;
   156 }
   158 NotableScriptSourceInfo::NotableScriptSourceInfo()
   159   : ScriptSourceInfo(),
   160     filename_(nullptr)
   161 {
   162 }
   164 NotableScriptSourceInfo::NotableScriptSourceInfo(const char *filename, const ScriptSourceInfo &info)
   165   : ScriptSourceInfo(info)
   166 {
   167     size_t bytes = strlen(filename) + 1;
   168     filename_ = js_pod_malloc<char>(bytes);
   169     if (!filename_)
   170         MOZ_CRASH("oom");
   171     PodCopy(filename_, filename, bytes);
   172 }
   174 NotableScriptSourceInfo::NotableScriptSourceInfo(NotableScriptSourceInfo &&info)
   175   : ScriptSourceInfo(Move(info))
   176 {
   177     filename_ = info.filename_;
   178     info.filename_ = nullptr;
   179 }
   181 NotableScriptSourceInfo &NotableScriptSourceInfo::operator=(NotableScriptSourceInfo &&info)
   182 {
   183     MOZ_ASSERT(this != &info, "self-move assignment is prohibited");
   184     this->~NotableScriptSourceInfo();
   185     new (this) NotableScriptSourceInfo(Move(info));
   186     return *this;
   187 }
   190 } // namespace JS
   192 typedef HashSet<ScriptSource *, DefaultHasher<ScriptSource *>, SystemAllocPolicy> SourceSet;
   194 struct StatsClosure
   195 {
   196     RuntimeStats *rtStats;
   197     ObjectPrivateVisitor *opv;
   198     SourceSet seenSources;
   199     StatsClosure(RuntimeStats *rt, ObjectPrivateVisitor *v) : rtStats(rt), opv(v) {}
   200     bool init() {
   201         return seenSources.init();
   202     }
   203 };
   205 static void
   206 DecommittedArenasChunkCallback(JSRuntime *rt, void *data, gc::Chunk *chunk)
   207 {
   208     // This case is common and fast to check.  Do it first.
   209     if (chunk->decommittedArenas.isAllClear())
   210         return;
   212     size_t n = 0;
   213     for (size_t i = 0; i < gc::ArenasPerChunk; i++) {
   214         if (chunk->decommittedArenas.get(i))
   215             n += gc::ArenaSize;
   216     }
   217     JS_ASSERT(n > 0);
   218     *static_cast<size_t *>(data) += n;
   219 }
   221 static void
   222 StatsZoneCallback(JSRuntime *rt, void *data, Zone *zone)
   223 {
   224     // Append a new CompartmentStats to the vector.
   225     RuntimeStats *rtStats = static_cast<StatsClosure *>(data)->rtStats;
   227     // CollectRuntimeStats reserves enough space.
   228     MOZ_ALWAYS_TRUE(rtStats->zoneStatsVector.growBy(1));
   229     ZoneStats &zStats = rtStats->zoneStatsVector.back();
   230     if (!zStats.initStrings(rt))
   231         MOZ_CRASH("oom");
   232     rtStats->initExtraZoneStats(zone, &zStats);
   233     rtStats->currZoneStats = &zStats;
   235     zone->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
   236                                  &zStats.typePool,
   237                                  &zStats.baselineStubsOptimized);
   238 }
   240 static void
   241 StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
   242 {
   243     // Append a new CompartmentStats to the vector.
   244     RuntimeStats *rtStats = static_cast<StatsClosure *>(data)->rtStats;
   246     // CollectRuntimeStats reserves enough space.
   247     MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
   248     CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
   249     rtStats->initExtraCompartmentStats(compartment, &cStats);
   251     compartment->compartmentStats = &cStats;
   253     // Measure the compartment object itself, and things hanging off it.
   254     compartment->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
   255                                         &cStats.typeInferenceAllocationSiteTables,
   256                                         &cStats.typeInferenceArrayTypeTables,
   257                                         &cStats.typeInferenceObjectTypeTables,
   258                                         &cStats.compartmentObject,
   259                                         &cStats.shapesMallocHeapCompartmentTables,
   260                                         &cStats.crossCompartmentWrappersTable,
   261                                         &cStats.regexpCompartment,
   262                                         &cStats.debuggeesSet,
   263                                         &cStats.savedStacksSet);
   264 }
   266 static void
   267 StatsArenaCallback(JSRuntime *rt, void *data, gc::Arena *arena,
   268                    JSGCTraceKind traceKind, size_t thingSize)
   269 {
   270     RuntimeStats *rtStats = static_cast<StatsClosure *>(data)->rtStats;
   272     // The admin space includes (a) the header and (b) the padding between the
   273     // end of the header and the start of the first GC thing.
   274     size_t allocationSpace = arena->thingsSpan(thingSize);
   275     rtStats->currZoneStats->gcHeapArenaAdmin += gc::ArenaSize - allocationSpace;
   277     // We don't call the callback on unused things.  So we compute the
   278     // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
   279     // We do this by setting arenaUnused to maxArenaUnused here, and then
   280     // subtracting thingSize for every used cell, in StatsCellCallback().
   281     rtStats->currZoneStats->unusedGCThings += allocationSpace;
   282 }
   284 static CompartmentStats *
   285 GetCompartmentStats(JSCompartment *comp)
   286 {
   287     return static_cast<CompartmentStats *>(comp->compartmentStats);
   288 }
   290 enum Granularity {
   291     FineGrained,    // Corresponds to CollectRuntimeStats()
   292     CoarseGrained   // Corresponds to AddSizeOfTab()
   293 };
   295 // The various kinds of hashing are expensive, and the results are unused when
   296 // doing coarse-grained measurements. Skipping them more than doubles the
   297 // profile speed for complex pages such as gmail.com.
   298 template <Granularity granularity>
   299 static void
   300 StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKind,
   301                   size_t thingSize)
   302 {
   303     StatsClosure *closure = static_cast<StatsClosure *>(data);
   304     RuntimeStats *rtStats = closure->rtStats;
   305     ZoneStats *zStats = rtStats->currZoneStats;
   306     switch (traceKind) {
   307       case JSTRACE_OBJECT: {
   308         JSObject *obj = static_cast<JSObject *>(thing);
   309         CompartmentStats *cStats = GetCompartmentStats(obj->compartment());
   310         if (obj->is<JSFunction>())
   311             cStats->objectsGCHeapFunction += thingSize;
   312         else if (obj->is<ArrayObject>())
   313             cStats->objectsGCHeapDenseArray += thingSize;
   314         else if (obj->is<CrossCompartmentWrapperObject>())
   315             cStats->objectsGCHeapCrossCompartmentWrapper += thingSize;
   316         else
   317             cStats->objectsGCHeapOrdinary += thingSize;
   319         obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &cStats->objectsExtra);
   321         if (ObjectPrivateVisitor *opv = closure->opv) {
   322             nsISupports *iface;
   323             if (opv->getISupports_(obj, &iface) && iface)
   324                 cStats->objectsPrivate += opv->sizeOfIncludingThis(iface);
   325         }
   326         break;
   327       }
   329       case JSTRACE_STRING: {
   330         JSString *str = static_cast<JSString *>(thing);
   332         JS::StringInfo info;
   333         info.gcHeap = thingSize;
   334         info.mallocHeap = str->sizeOfExcludingThis(rtStats->mallocSizeOf_);
   335         info.numCopies = 1;
   337         zStats->stringInfo.add(info);
   339         if (granularity == FineGrained) {
   340             ZoneStats::StringsHashMap::AddPtr p = zStats->allStrings->lookupForAdd(str);
   341             if (!p) {
   342                 // Ignore failure -- we just won't record the string as notable.
   343                 (void)zStats->allStrings->add(p, str, info);
   344             } else {
   345                 p->value().add(info);
   346             }
   347         }
   348         break;
   349       }
   351       case JSTRACE_SHAPE: {
   352         Shape *shape = static_cast<Shape *>(thing);
   353         CompartmentStats *cStats = GetCompartmentStats(shape->compartment());
   354         if (shape->inDictionary()) {
   355             cStats->shapesGCHeapDict += thingSize;
   357             // nullptr because kidsSize shouldn't be incremented in this case.
   358             shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_,
   359                                           &cStats->shapesMallocHeapDictTables, nullptr);
   360         } else {
   361             JSObject *parent = shape->base()->getObjectParent();
   362             if (parent && parent->is<GlobalObject>())
   363                 cStats->shapesGCHeapTreeGlobalParented += thingSize;
   364             else
   365                 cStats->shapesGCHeapTreeNonGlobalParented += thingSize;
   367             shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_,
   368                                           &cStats->shapesMallocHeapTreeTables,
   369                                           &cStats->shapesMallocHeapTreeShapeKids);
   370         }
   371         break;
   372       }
   374       case JSTRACE_BASE_SHAPE: {
   375         BaseShape *base = static_cast<BaseShape *>(thing);
   376         CompartmentStats *cStats = GetCompartmentStats(base->compartment());
   377         cStats->shapesGCHeapBase += thingSize;
   378         break;
   379       }
   381       case JSTRACE_SCRIPT: {
   382         JSScript *script = static_cast<JSScript *>(thing);
   383         CompartmentStats *cStats = GetCompartmentStats(script->compartment());
   384         cStats->scriptsGCHeap += thingSize;
   385         cStats->scriptsMallocHeapData += script->sizeOfData(rtStats->mallocSizeOf_);
   386         cStats->typeInferenceTypeScripts += script->sizeOfTypeScript(rtStats->mallocSizeOf_);
   387 #ifdef JS_ION
   388         jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_, &cStats->baselineData,
   389                                    &cStats->baselineStubsFallback);
   390         cStats->ionData += jit::SizeOfIonData(script, rtStats->mallocSizeOf_);
   391 #endif
   393         ScriptSource *ss = script->scriptSource();
   394         SourceSet::AddPtr entry = closure->seenSources.lookupForAdd(ss);
   395         if (!entry) {
   396             (void)closure->seenSources.add(entry, ss); // Not much to be done on failure.
   398             JS::ScriptSourceInfo info;  // This zeroes all the sizes.
   399             ss->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &info);
   400             MOZ_ASSERT(info.compressed == 0 || info.uncompressed == 0);
   402             rtStats->runtime.scriptSourceInfo.add(info);
   404             if (granularity == FineGrained) {
   405                 const char* filename = ss->filename();
   406                 if (!filename)
   407                     filename = "<no filename>";
   409                 JS::RuntimeSizes::ScriptSourcesHashMap::AddPtr p =
   410                     rtStats->runtime.allScriptSources->lookupForAdd(filename);
   411                 if (!p) {
   412                     // Ignore failure -- we just won't record the script source as notable.
   413                     (void)rtStats->runtime.allScriptSources->add(p, filename, info);
   414                 } else {
   415                     p->value().add(info);
   416                 }
   417             }
   418         }
   420         break;
   421       }
   423       case JSTRACE_LAZY_SCRIPT: {
   424         LazyScript *lazy = static_cast<LazyScript *>(thing);
   425         zStats->lazyScriptsGCHeap += thingSize;
   426         zStats->lazyScriptsMallocHeap += lazy->sizeOfExcludingThis(rtStats->mallocSizeOf_);
   427         break;
   428       }
   430       case JSTRACE_JITCODE: {
   431 #ifdef JS_ION
   432         zStats->jitCodesGCHeap += thingSize;
   433         // The code for a script is counted in ExecutableAllocator::sizeOfCode().
   434 #endif
   435         break;
   436       }
   438       case JSTRACE_TYPE_OBJECT: {
   439         types::TypeObject *obj = static_cast<types::TypeObject *>(thing);
   440         zStats->typeObjectsGCHeap += thingSize;
   441         zStats->typeObjectsMallocHeap += obj->sizeOfExcludingThis(rtStats->mallocSizeOf_);
   442         break;
   443       }
   445       default:
   446         MOZ_ASSUME_UNREACHABLE("invalid traceKind");
   447     }
   449     // Yes, this is a subtraction:  see StatsArenaCallback() for details.
   450     zStats->unusedGCThings -= thingSize;
   451 }
   453 static bool
   454 FindNotableStrings(ZoneStats &zStats)
   455 {
   456     using namespace JS;
   458     // We should only run FindNotableStrings once per ZoneStats object.
   459     MOZ_ASSERT(zStats.notableStrings.empty());
   461     for (ZoneStats::StringsHashMap::Range r = zStats.allStrings->all(); !r.empty(); r.popFront()) {
   463         JSString *str = r.front().key();
   464         StringInfo &info = r.front().value();
   466         if (!info.isNotable())
   467             continue;
   469         if (!zStats.notableStrings.growBy(1))
   470             return false;
   472         zStats.notableStrings.back() = NotableStringInfo(str, info);
   474         // We're moving this string from a non-notable to a notable bucket, so
   475         // subtract it out of the non-notable tallies.
   476         zStats.stringInfo.subtract(info);
   477     }
   478     // Delete |allStrings| now, rather than waiting for zStats's destruction,
   479     // to reduce peak memory consumption during reporting.
   480     js_delete(zStats.allStrings);
   481     zStats.allStrings = nullptr;
   482     return true;
   483 }
   485 bool
   486 ZoneStats::initStrings(JSRuntime *rt)
   487 {
   488     isTotals = false;
   489     allStrings = rt->new_<StringsHashMap>();
   490     if (!allStrings)
   491         return false;
   492     if (!allStrings->init()) {
   493         js_delete(allStrings);
   494         allStrings = nullptr;
   495         return false;
   496     }
   497     return true;
   498 }
   500 static bool
   501 FindNotableScriptSources(JS::RuntimeSizes &runtime)
   502 {
   503     using namespace JS;
   505     // We should only run FindNotableScriptSources once per RuntimeSizes.
   506     MOZ_ASSERT(runtime.notableScriptSources.empty());
   508     for (RuntimeSizes::ScriptSourcesHashMap::Range r = runtime.allScriptSources->all();
   509          !r.empty();
   510          r.popFront())
   511     {
   512         const char *filename = r.front().key();
   513         ScriptSourceInfo &info = r.front().value();
   515         if (!info.isNotable())
   516             continue;
   518         if (!runtime.notableScriptSources.growBy(1))
   519             return false;
   521         runtime.notableScriptSources.back() = NotableScriptSourceInfo(filename, info);
   523         // We're moving this script source from a non-notable to a notable
   524         // bucket, so subtract its sizes from the non-notable tallies.
   525         runtime.scriptSourceInfo.subtract(info);
   526     }
   527     // Delete |allScriptSources| now, rather than waiting for zStats's
   528     // destruction, to reduce peak memory consumption during reporting.
   529     js_delete(runtime.allScriptSources);
   530     runtime.allScriptSources = nullptr;
   531     return true;
   532 }
   534 JS_PUBLIC_API(bool)
   535 JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv)
   536 {
   537     if (!rtStats->compartmentStatsVector.reserve(rt->numCompartments))
   538         return false;
   540     if (!rtStats->zoneStatsVector.reserve(rt->zones.length()))
   541         return false;
   543     rtStats->gcHeapChunkTotal =
   544         size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize;
   546     rtStats->gcHeapUnusedChunks =
   547         size_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize;
   549     IterateChunks(rt, &rtStats->gcHeapDecommittedArenas,
   550                   DecommittedArenasChunkCallback);
   552     // Take the per-compartment measurements.
   553     StatsClosure closure(rtStats, opv);
   554     if (!closure.init())
   555         return false;
   556     IterateZonesCompartmentsArenasCells(rt, &closure, StatsZoneCallback, StatsCompartmentCallback,
   557                                         StatsArenaCallback, StatsCellCallback<FineGrained>);
   559     // Take the "explicit/js/runtime/" measurements.
   560     rt->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &rtStats->runtime);
   562     if (!FindNotableScriptSources(rtStats->runtime))
   563         return false;
   565     ZoneStatsVector &zs = rtStats->zoneStatsVector;
   566     ZoneStats &zTotals = rtStats->zTotals;
   568     // We don't look for notable strings for zTotals. So we first sum all the
   569     // zones' measurements to get the totals. Then we find the notable strings
   570     // within each zone.
   571     for (size_t i = 0; i < zs.length(); i++)
   572         zTotals.addSizes(zs[i]);
   574     for (size_t i = 0; i < zs.length(); i++)
   575         if (!FindNotableStrings(zs[i]))
   576             return false;
   578     MOZ_ASSERT(!zTotals.allStrings);
   580     for (size_t i = 0; i < rtStats->compartmentStatsVector.length(); i++) {
   581         CompartmentStats &cStats = rtStats->compartmentStatsVector[i];
   582         rtStats->cTotals.add(cStats);
   583     }
   585     rtStats->gcHeapGCThings = rtStats->zTotals.sizeOfLiveGCThings() +
   586                               rtStats->cTotals.sizeOfLiveGCThings();
   588 #ifdef DEBUG
   589     // Check that the in-arena measurements look ok.
   590     size_t totalArenaSize = rtStats->zTotals.gcHeapArenaAdmin +
   591                             rtStats->zTotals.unusedGCThings +
   592                             rtStats->gcHeapGCThings;
   593     JS_ASSERT(totalArenaSize % gc::ArenaSize == 0);
   594 #endif
   596     for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next())
   597         comp->compartmentStats = nullptr;
   599     size_t numDirtyChunks =
   600         (rtStats->gcHeapChunkTotal - rtStats->gcHeapUnusedChunks) / gc::ChunkSize;
   601     size_t perChunkAdmin =
   602         sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
   603     rtStats->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
   605     // |gcHeapUnusedArenas| is the only thing left.  Compute it in terms of
   606     // all the others.  See the comment in RuntimeStats for explanation.
   607     rtStats->gcHeapUnusedArenas = rtStats->gcHeapChunkTotal -
   608                                   rtStats->gcHeapDecommittedArenas -
   609                                   rtStats->gcHeapUnusedChunks -
   610                                   rtStats->zTotals.unusedGCThings -
   611                                   rtStats->gcHeapChunkAdmin -
   612                                   rtStats->zTotals.gcHeapArenaAdmin -
   613                                   rtStats->gcHeapGCThings;
   614     return true;
   615 }
   617 JS_PUBLIC_API(size_t)
   618 JS::SystemCompartmentCount(JSRuntime *rt)
   619 {
   620     size_t n = 0;
   621     for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) {
   622         if (comp->isSystem)
   623             ++n;
   624     }
   625     return n;
   626 }
   628 JS_PUBLIC_API(size_t)
   629 JS::UserCompartmentCount(JSRuntime *rt)
   630 {
   631     size_t n = 0;
   632     for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) {
   633         if (!comp->isSystem)
   634             ++n;
   635     }
   636     return n;
   637 }
   639 JS_PUBLIC_API(size_t)
   640 JS::PeakSizeOfTemporary(const JSRuntime *rt)
   641 {
   642     return rt->tempLifoAlloc.peakSizeOfExcludingThis();
   643 }
   645 namespace JS {
   647 JS_PUBLIC_API(bool)
   648 AddSizeOfTab(JSRuntime *rt, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectPrivateVisitor *opv,
   649              TabSizes *sizes)
   650 {
   651     class SimpleJSRuntimeStats : public JS::RuntimeStats
   652     {
   653       public:
   654         SimpleJSRuntimeStats(MallocSizeOf mallocSizeOf)
   655           : JS::RuntimeStats(mallocSizeOf)
   656         {}
   658         virtual void initExtraZoneStats(JS::Zone *zone, JS::ZoneStats *zStats)
   659             MOZ_OVERRIDE
   660         {}
   662         virtual void initExtraCompartmentStats(
   663             JSCompartment *c, JS::CompartmentStats *cStats) MOZ_OVERRIDE
   664         {}
   665     };
   667     SimpleJSRuntimeStats rtStats(mallocSizeOf);
   669     JS::Zone *zone = GetObjectZone(obj);
   671     if (!rtStats.compartmentStatsVector.reserve(zone->compartments.length()))
   672         return false;
   674     if (!rtStats.zoneStatsVector.reserve(1))
   675         return false;
   677     // Take the per-compartment measurements.
   678     StatsClosure closure(&rtStats, opv);
   679     if (!closure.init())
   680         return false;
   681     IterateZoneCompartmentsArenasCells(rt, zone, &closure, StatsZoneCallback,
   682                                        StatsCompartmentCallback, StatsArenaCallback,
   683                                        StatsCellCallback<CoarseGrained>);
   685     JS_ASSERT(rtStats.zoneStatsVector.length() == 1);
   686     rtStats.zTotals.addSizes(rtStats.zoneStatsVector[0]);
   688     for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) {
   689         CompartmentStats &cStats = rtStats.compartmentStatsVector[i];
   690         rtStats.cTotals.add(cStats);
   691     }
   693     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
   694         comp->compartmentStats = nullptr;
   696     rtStats.zTotals.addToTabSizes(sizes);
   697     rtStats.cTotals.addToTabSizes(sizes);
   699     return true;
   700 }
   702 } // namespace JS

mercurial