[SM91] Update to Spidermonkey 91.1.3 APIs
[0ad.git] / libraries / source / spidermonkey / include-win32-release / js / MemoryMetrics.h
blob20fe9bb67126606a53cffe2ca08fc89cdda285e9
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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 #ifndef js_MemoryMetrics_h
8 #define js_MemoryMetrics_h
10 // These declarations are highly likely to change in the future. Depend on them
11 // at your own risk.
13 #include "mozilla/Maybe.h"
14 #include "mozilla/MemoryReporting.h"
16 #include <string.h>
17 #include <type_traits>
19 #include "jstypes.h"
21 #include "js/AllocPolicy.h"
22 #include "js/HashTable.h"
23 #include "js/TraceKind.h"
24 #include "js/TypeDecls.h"
25 #include "js/Utility.h"
26 #include "js/Vector.h"
28 class nsISupports; // Needed for ObjectPrivateVisitor.
30 namespace js {
31 class SystemAllocPolicy;
34 namespace mozilla {
35 struct CStringHasher;
38 namespace JS {
39 class JS_PUBLIC_API AutoRequireNoGC;
41 struct TabSizes {
42 TabSizes() = default;
44 enum Kind { Objects, Strings, Private, Other };
46 void add(Kind kind, size_t n) {
47 switch (kind) {
48 case Objects:
49 objects_ += n;
50 break;
51 case Strings:
52 strings_ += n;
53 break;
54 case Private:
55 private_ += n;
56 break;
57 case Other:
58 other_ += n;
59 break;
60 default:
61 MOZ_CRASH("bad TabSizes kind");
65 size_t objects_ = 0;
66 size_t strings_ = 0;
67 size_t private_ = 0;
68 size_t other_ = 0;
71 /** These are the measurements used by Servo. */
72 struct ServoSizes {
73 ServoSizes() = default;
75 enum Kind {
76 GCHeapUsed,
77 GCHeapUnused,
78 GCHeapAdmin,
79 GCHeapDecommitted,
80 MallocHeap,
81 NonHeap,
82 Ignore
85 void add(Kind kind, size_t n) {
86 switch (kind) {
87 case GCHeapUsed:
88 gcHeapUsed += n;
89 break;
90 case GCHeapUnused:
91 gcHeapUnused += n;
92 break;
93 case GCHeapAdmin:
94 gcHeapAdmin += n;
95 break;
96 case GCHeapDecommitted:
97 gcHeapDecommitted += n;
98 break;
99 case MallocHeap:
100 mallocHeap += n;
101 break;
102 case NonHeap:
103 nonHeap += n;
104 break;
105 case Ignore: /* do nothing */
106 break;
107 default:
108 MOZ_CRASH("bad ServoSizes kind");
112 size_t gcHeapUsed = 0;
113 size_t gcHeapUnused = 0;
114 size_t gcHeapAdmin = 0;
115 size_t gcHeapDecommitted = 0;
116 size_t mallocHeap = 0;
117 size_t nonHeap = 0;
120 } // namespace JS
122 namespace js {
125 * In memory reporting, we have concept of "sundries", line items which are too
126 * small to be worth reporting individually. Under some circumstances, a memory
127 * reporter gets tossed into the sundries bucket if it's smaller than
128 * MemoryReportingSundriesThreshold() bytes.
130 * We need to define this value here, rather than in the code which actually
131 * generates the memory reports, because NotableStringInfo uses this value.
133 JS_PUBLIC_API size_t MemoryReportingSundriesThreshold();
136 * This hash policy avoids flattening ropes (which perturbs the site being
137 * measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
138 * on every hash and match! Beware.
140 struct InefficientNonFlatteningStringHashPolicy {
141 typedef JSString* Lookup;
142 static HashNumber hash(const Lookup& l);
143 static bool match(const JSString* const& k, const Lookup& l);
146 // This file features many classes with numerous size_t fields, and each such
147 // class has one or more methods that need to operate on all of these fields.
148 // Writing these individually is error-prone -- it's easy to add a new field
149 // without updating all the required methods. So we define a single macro list
150 // in each class to name the fields (and notable characteristics of them), and
151 // then use the following macros to transform those lists into the required
152 // methods.
154 // - The |tabKind| value is used when measuring TabSizes.
156 // - The |servoKind| value is used when measuring ServoSizes and also for
157 // the various sizeOfLiveGCThings() methods.
159 // In some classes, one or more of the macro arguments aren't used. We use '_'
160 // for those.
162 #define DECL_SIZE_ZERO(tabKind, servoKind, mSize) size_t mSize = 0;
163 #define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize;
164 #define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \
165 MOZ_ASSERT(mSize >= other.mSize); \
166 mSize -= other.mSize;
167 #define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize;
168 #define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \
169 /* Avoid self-comparison warnings by comparing enums indirectly. */ \
170 n += (std::is_same_v<int[ServoSizes::servoKind], \
171 int[ServoSizes::GCHeapUsed]>) \
172 ? mSize \
173 : 0;
174 #define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) \
175 sizes->add(JS::TabSizes::tabKind, mSize);
176 #define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) \
177 sizes->add(JS::ServoSizes::servoKind, mSize);
179 } // namespace js
181 namespace JS {
183 struct ClassInfo {
184 #define FOR_EACH_SIZE(MACRO) \
185 MACRO(Objects, GCHeapUsed, objectsGCHeap) \
186 MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \
187 MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
188 MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
189 MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \
190 MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
191 MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \
192 MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \
193 MACRO(Objects, NonHeap, objectsNonHeapCodeWasm)
195 ClassInfo() = default;
197 void add(const ClassInfo& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE); }
199 void subtract(const ClassInfo& other) { FOR_EACH_SIZE(SUB_OTHER_SIZE); }
201 size_t sizeOfAllThings() const {
202 size_t n = 0;
203 FOR_EACH_SIZE(ADD_SIZE_TO_N);
204 return n;
207 bool isNotable() const {
208 static const size_t NotabilityThreshold = 16 * 1024;
209 return sizeOfAllThings() >= NotabilityThreshold;
212 size_t sizeOfLiveGCThings() const {
213 size_t n = 0;
214 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
215 return n;
218 void addToTabSizes(TabSizes* sizes) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES); }
220 void addToServoSizes(ServoSizes* sizes) const {
221 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
224 FOR_EACH_SIZE(DECL_SIZE_ZERO);
226 size_t wasmGuardPages = 0;
228 #undef FOR_EACH_SIZE
231 struct ShapeInfo {
232 #define FOR_EACH_SIZE(MACRO) \
233 MACRO(Other, GCHeapUsed, shapesGCHeapShared) \
234 MACRO(Other, GCHeapUsed, shapesGCHeapDict) \
235 MACRO(Other, GCHeapUsed, shapesGCHeapBase) \
236 MACRO(Other, MallocHeap, shapesMallocHeapCache)
238 ShapeInfo() = default;
240 void add(const ShapeInfo& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE); }
242 void subtract(const ShapeInfo& other) { FOR_EACH_SIZE(SUB_OTHER_SIZE); }
244 size_t sizeOfAllThings() const {
245 size_t n = 0;
246 FOR_EACH_SIZE(ADD_SIZE_TO_N);
247 return n;
250 size_t sizeOfLiveGCThings() const {
251 size_t n = 0;
252 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
253 return n;
256 void addToTabSizes(TabSizes* sizes) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES); }
258 void addToServoSizes(ServoSizes* sizes) const {
259 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
262 FOR_EACH_SIZE(DECL_SIZE_ZERO);
264 #undef FOR_EACH_SIZE
268 * Holds data about a notable class (one whose combined object and shape
269 * instances use more than a certain amount of memory) so we can report it
270 * individually.
272 * The only difference between this class and ClassInfo is that this class
273 * holds a copy of the filename.
275 struct NotableClassInfo : public ClassInfo {
276 NotableClassInfo() = default;
277 NotableClassInfo(NotableClassInfo&&) = default;
278 NotableClassInfo(const NotableClassInfo& info) = delete;
280 NotableClassInfo(const char* className, const ClassInfo& info);
282 UniqueChars className_ = nullptr;
285 /** Data for tracking JIT-code memory usage. */
286 struct CodeSizes {
287 #define FOR_EACH_SIZE(MACRO) \
288 MACRO(_, NonHeap, ion) \
289 MACRO(_, NonHeap, baseline) \
290 MACRO(_, NonHeap, regexp) \
291 MACRO(_, NonHeap, other) \
292 MACRO(_, NonHeap, unused)
294 CodeSizes() = default;
296 void addToServoSizes(ServoSizes* sizes) const {
297 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
300 FOR_EACH_SIZE(DECL_SIZE_ZERO);
302 #undef FOR_EACH_SIZE
305 /** Data for tracking GC memory usage. */
306 struct GCSizes {
307 // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted
308 // because we don't consider the nursery to be part of the GC heap.
309 #define FOR_EACH_SIZE(MACRO) \
310 MACRO(_, MallocHeap, marker) \
311 MACRO(_, NonHeap, nurseryCommitted) \
312 MACRO(_, MallocHeap, nurseryMallocedBuffers) \
313 MACRO(_, MallocHeap, storeBufferVals) \
314 MACRO(_, MallocHeap, storeBufferCells) \
315 MACRO(_, MallocHeap, storeBufferSlots) \
316 MACRO(_, MallocHeap, storeBufferWholeCells) \
317 MACRO(_, MallocHeap, storeBufferGenerics)
319 GCSizes() = default;
321 void addToServoSizes(ServoSizes* sizes) const {
322 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
325 FOR_EACH_SIZE(DECL_SIZE_ZERO);
327 #undef FOR_EACH_SIZE
331 * This class holds information about the memory taken up by identical copies of
332 * a particular string. Multiple JSStrings may have their sizes aggregated
333 * together into one StringInfo object. Note that two strings with identical
334 * chars will not be aggregated together if one is a short string and the other
335 * is not.
337 struct StringInfo {
338 #define FOR_EACH_SIZE(MACRO) \
339 MACRO(Strings, GCHeapUsed, gcHeapLatin1) \
340 MACRO(Strings, GCHeapUsed, gcHeapTwoByte) \
341 MACRO(Strings, MallocHeap, mallocHeapLatin1) \
342 MACRO(Strings, MallocHeap, mallocHeapTwoByte)
344 StringInfo() = default;
346 void add(const StringInfo& other) {
347 FOR_EACH_SIZE(ADD_OTHER_SIZE);
348 numCopies++;
351 void subtract(const StringInfo& other) {
352 FOR_EACH_SIZE(SUB_OTHER_SIZE);
353 numCopies--;
356 bool isNotable() const {
357 static const size_t NotabilityThreshold = 16 * 1024;
358 size_t n = 0;
359 FOR_EACH_SIZE(ADD_SIZE_TO_N);
360 return n >= NotabilityThreshold;
363 size_t sizeOfLiveGCThings() const {
364 size_t n = 0;
365 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
366 return n;
369 void addToTabSizes(TabSizes* sizes) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES); }
371 void addToServoSizes(ServoSizes* sizes) const {
372 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
375 FOR_EACH_SIZE(DECL_SIZE_ZERO);
377 uint32_t numCopies = 0; // How many copies of the string have we seen?
379 #undef FOR_EACH_SIZE
383 * Holds data about a notable string (one which, counting all duplicates, uses
384 * more than a certain amount of memory) so we can report it individually.
386 * The only difference between this class and StringInfo is that
387 * NotableStringInfo holds a copy of some or all of the string's chars.
389 struct NotableStringInfo : public StringInfo {
390 static const size_t MAX_SAVED_CHARS = 1024;
392 NotableStringInfo() = default;
393 NotableStringInfo(NotableStringInfo&&) = default;
394 NotableStringInfo(const NotableStringInfo&) = delete;
396 NotableStringInfo(JSString* str, const StringInfo& info);
398 UniqueChars buffer = nullptr;
399 size_t length = 0;
403 * This class holds information about the memory taken up by script sources
404 * from a particular file.
406 struct ScriptSourceInfo {
407 #define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, misc)
409 ScriptSourceInfo() = default;
411 void add(const ScriptSourceInfo& other) {
412 FOR_EACH_SIZE(ADD_OTHER_SIZE);
413 numScripts++;
416 void subtract(const ScriptSourceInfo& other) {
417 FOR_EACH_SIZE(SUB_OTHER_SIZE);
418 numScripts--;
421 void addToServoSizes(ServoSizes* sizes) const {
422 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
425 bool isNotable() const {
426 static const size_t NotabilityThreshold = 16 * 1024;
427 size_t n = 0;
428 FOR_EACH_SIZE(ADD_SIZE_TO_N);
429 return n >= NotabilityThreshold;
432 FOR_EACH_SIZE(DECL_SIZE_ZERO);
434 uint32_t numScripts = 0; // How many ScriptSources come from this file? (It
435 // can be more than one in XML files that have
436 // multiple scripts in CDATA sections.)
437 #undef FOR_EACH_SIZE
441 * Holds data about a notable script source file (one whose combined
442 * script sources use more than a certain amount of memory) so we can report it
443 * individually.
445 * The only difference between this class and ScriptSourceInfo is that this
446 * class holds a copy of the filename.
448 struct NotableScriptSourceInfo : public ScriptSourceInfo {
449 NotableScriptSourceInfo() = default;
450 NotableScriptSourceInfo(NotableScriptSourceInfo&&) = default;
451 NotableScriptSourceInfo(const NotableScriptSourceInfo&) = delete;
453 NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info);
455 UniqueChars filename_ = nullptr;
458 struct HelperThreadStats {
459 #define FOR_EACH_SIZE(MACRO) \
460 MACRO(_, MallocHeap, stateData) \
461 MACRO(_, MallocHeap, parseTask) \
462 MACRO(_, MallocHeap, ionCompileTask) \
463 MACRO(_, MallocHeap, wasmCompile) \
464 MACRO(_, MallocHeap, contexts)
466 HelperThreadStats() = default;
468 FOR_EACH_SIZE(DECL_SIZE_ZERO);
470 unsigned idleThreadCount = 0;
471 unsigned activeThreadCount = 0;
473 #undef FOR_EACH_SIZE
477 * Measurements that not associated with any individual runtime.
479 struct GlobalStats {
480 #define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, tracelogger)
482 explicit GlobalStats(mozilla::MallocSizeOf mallocSizeOf)
483 : mallocSizeOf_(mallocSizeOf) {}
485 FOR_EACH_SIZE(DECL_SIZE_ZERO);
487 HelperThreadStats helperThread;
489 mozilla::MallocSizeOf mallocSizeOf_;
491 #undef FOR_EACH_SIZE
495 * These measurements relate directly to the JSRuntime, and not to zones,
496 * compartments, and realms within it.
498 struct RuntimeSizes {
499 #define FOR_EACH_SIZE(MACRO) \
500 MACRO(_, MallocHeap, object) \
501 MACRO(_, MallocHeap, atomsTable) \
502 MACRO(_, MallocHeap, atomsMarkBitmaps) \
503 MACRO(_, MallocHeap, contexts) \
504 MACRO(_, MallocHeap, temporary) \
505 MACRO(_, MallocHeap, interpreterStack) \
506 MACRO(_, MallocHeap, sharedImmutableStringsCache) \
507 MACRO(_, MallocHeap, sharedIntlData) \
508 MACRO(_, MallocHeap, uncompressedSourceCache) \
509 MACRO(_, MallocHeap, scriptData) \
510 MACRO(_, MallocHeap, tracelogger) \
511 MACRO(_, MallocHeap, wasmRuntime) \
512 MACRO(_, MallocHeap, jitLazyLink)
514 RuntimeSizes() { allScriptSources.emplace(); }
516 void addToServoSizes(ServoSizes* sizes) const {
517 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
518 scriptSourceInfo.addToServoSizes(sizes);
519 gc.addToServoSizes(sizes);
522 FOR_EACH_SIZE(DECL_SIZE_ZERO);
524 // The script source measurements in |scriptSourceInfo| are initially for
525 // all script sources. At the end, if the measurement granularity is
526 // FineGrained, we subtract the measurements of the notable script sources
527 // and move them into |notableScriptSources|.
528 ScriptSourceInfo scriptSourceInfo;
529 GCSizes gc;
531 typedef js::HashMap<const char*, ScriptSourceInfo, mozilla::CStringHasher,
532 js::SystemAllocPolicy>
533 ScriptSourcesHashMap;
535 // |allScriptSources| is only used transiently. During the reporting phase
536 // it is filled with info about every script source in the runtime. It's
537 // then used to fill in |notableScriptSources| (which actually gets
538 // reported), and immediately discarded afterwards.
539 mozilla::Maybe<ScriptSourcesHashMap> allScriptSources;
540 js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy>
541 notableScriptSources;
543 #undef FOR_EACH_SIZE
546 struct UnusedGCThingSizes {
547 #define FOR_EACH_SIZE(MACRO) \
548 MACRO(Other, GCHeapUnused, object) \
549 MACRO(Other, GCHeapUnused, script) \
550 MACRO(Other, GCHeapUnused, shape) \
551 MACRO(Other, GCHeapUnused, baseShape) \
552 MACRO(Other, GCHeapUnused, getterSetter) \
553 MACRO(Other, GCHeapUnused, propMap) \
554 MACRO(Other, GCHeapUnused, string) \
555 MACRO(Other, GCHeapUnused, symbol) \
556 MACRO(Other, GCHeapUnused, bigInt) \
557 MACRO(Other, GCHeapUnused, jitcode) \
558 MACRO(Other, GCHeapUnused, scope) \
559 MACRO(Other, GCHeapUnused, regExpShared)
561 UnusedGCThingSizes() = default;
562 UnusedGCThingSizes(UnusedGCThingSizes&& other) = default;
564 void addToKind(JS::TraceKind kind, intptr_t n) {
565 switch (kind) {
566 case JS::TraceKind::Object:
567 object += n;
568 break;
569 case JS::TraceKind::String:
570 string += n;
571 break;
572 case JS::TraceKind::Symbol:
573 symbol += n;
574 break;
575 case JS::TraceKind::BigInt:
576 bigInt += n;
577 break;
578 case JS::TraceKind::Script:
579 script += n;
580 break;
581 case JS::TraceKind::Shape:
582 shape += n;
583 break;
584 case JS::TraceKind::BaseShape:
585 baseShape += n;
586 break;
587 case JS::TraceKind::GetterSetter:
588 getterSetter += n;
589 break;
590 case JS::TraceKind::PropMap:
591 propMap += n;
592 break;
593 case JS::TraceKind::JitCode:
594 jitcode += n;
595 break;
596 case JS::TraceKind::Scope:
597 scope += n;
598 break;
599 case JS::TraceKind::RegExpShared:
600 regExpShared += n;
601 break;
602 default:
603 MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
607 void addSizes(const UnusedGCThingSizes& other) {
608 FOR_EACH_SIZE(ADD_OTHER_SIZE);
611 size_t totalSize() const {
612 size_t n = 0;
613 FOR_EACH_SIZE(ADD_SIZE_TO_N);
614 return n;
617 void addToTabSizes(JS::TabSizes* sizes) const {
618 FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
621 void addToServoSizes(JS::ServoSizes* sizes) const {
622 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
625 FOR_EACH_SIZE(DECL_SIZE_ZERO);
627 #undef FOR_EACH_SIZE
630 struct ZoneStats {
631 #define FOR_EACH_SIZE(MACRO) \
632 MACRO(Other, GCHeapUsed, symbolsGCHeap) \
633 MACRO(Other, GCHeapUsed, bigIntsGCHeap) \
634 MACRO(Other, MallocHeap, bigIntsMallocHeap) \
635 MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \
636 MACRO(Other, GCHeapUsed, jitCodesGCHeap) \
637 MACRO(Other, GCHeapUsed, getterSettersGCHeap) \
638 MACRO(Other, GCHeapUsed, compactPropMapsGCHeap) \
639 MACRO(Other, GCHeapUsed, normalPropMapsGCHeap) \
640 MACRO(Other, GCHeapUsed, dictPropMapsGCHeap) \
641 MACRO(Other, MallocHeap, propMapChildren) \
642 MACRO(Other, MallocHeap, propMapTables) \
643 MACRO(Other, GCHeapUsed, scopesGCHeap) \
644 MACRO(Other, MallocHeap, scopesMallocHeap) \
645 MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
646 MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
647 MACRO(Other, MallocHeap, regexpZone) \
648 MACRO(Other, MallocHeap, jitZone) \
649 MACRO(Other, MallocHeap, baselineStubsOptimized) \
650 MACRO(Other, MallocHeap, uniqueIdMap) \
651 MACRO(Other, MallocHeap, initialPropMapTable) \
652 MACRO(Other, MallocHeap, shapeTables) \
653 MACRO(Other, MallocHeap, compartmentObjects) \
654 MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \
655 MACRO(Other, MallocHeap, compartmentsPrivateData) \
656 MACRO(Other, MallocHeap, scriptCountsMap)
658 ZoneStats() = default;
659 ZoneStats(ZoneStats&& other) = default;
661 void initStrings();
663 void addSizes(const ZoneStats& other) {
664 MOZ_ASSERT(isTotals);
665 FOR_EACH_SIZE(ADD_OTHER_SIZE);
666 unusedGCThings.addSizes(other.unusedGCThings);
667 stringInfo.add(other.stringInfo);
668 shapeInfo.add(other.shapeInfo);
671 size_t sizeOfLiveGCThings() const {
672 MOZ_ASSERT(isTotals);
673 size_t n = 0;
674 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
675 n += stringInfo.sizeOfLiveGCThings();
676 n += shapeInfo.sizeOfLiveGCThings();
677 return n;
680 void addToTabSizes(JS::TabSizes* sizes) const {
681 MOZ_ASSERT(isTotals);
682 FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
683 unusedGCThings.addToTabSizes(sizes);
684 stringInfo.addToTabSizes(sizes);
685 shapeInfo.addToTabSizes(sizes);
688 void addToServoSizes(JS::ServoSizes* sizes) const {
689 MOZ_ASSERT(isTotals);
690 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
691 unusedGCThings.addToServoSizes(sizes);
692 stringInfo.addToServoSizes(sizes);
693 shapeInfo.addToServoSizes(sizes);
694 code.addToServoSizes(sizes);
697 FOR_EACH_SIZE(DECL_SIZE_ZERO);
699 // These string measurements are initially for all strings. At the end,
700 // if the measurement granularity is FineGrained, we subtract the
701 // measurements of the notable script sources and move them into
702 // |notableStrings|.
703 UnusedGCThingSizes unusedGCThings;
704 StringInfo stringInfo;
705 ShapeInfo shapeInfo;
706 CodeSizes code;
707 void* extra = nullptr; // This field can be used by embedders.
709 typedef js::HashMap<JSString*, StringInfo,
710 js::InefficientNonFlatteningStringHashPolicy,
711 js::SystemAllocPolicy>
712 StringsHashMap;
714 // |allStrings| is only used transiently. During the zone traversal it is
715 // filled with info about every string in the zone. It's then used to fill
716 // in |notableStrings| (which actually gets reported), and immediately
717 // discarded afterwards.
718 mozilla::Maybe<StringsHashMap> allStrings;
719 js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings;
720 bool isTotals = true;
722 #undef FOR_EACH_SIZE
725 struct RealmStats {
726 // We assume that |objectsPrivate| is on the malloc heap, but it's not
727 // actually guaranteed. But for Servo, at least, it's a moot point because
728 // it doesn't provide an ObjectPrivateVisitor so the value will always be
729 // zero.
730 #define FOR_EACH_SIZE(MACRO) \
731 MACRO(Private, MallocHeap, objectsPrivate) \
732 MACRO(Other, GCHeapUsed, scriptsGCHeap) \
733 MACRO(Other, MallocHeap, scriptsMallocHeapData) \
734 MACRO(Other, MallocHeap, baselineData) \
735 MACRO(Other, MallocHeap, baselineStubsFallback) \
736 MACRO(Other, MallocHeap, ionData) \
737 MACRO(Other, MallocHeap, jitScripts) \
738 MACRO(Other, MallocHeap, realmObject) \
739 MACRO(Other, MallocHeap, realmTables) \
740 MACRO(Other, MallocHeap, innerViewsTable) \
741 MACRO(Other, MallocHeap, objectMetadataTable) \
742 MACRO(Other, MallocHeap, savedStacksSet) \
743 MACRO(Other, MallocHeap, varNamesSet) \
744 MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
745 MACRO(Other, MallocHeap, jitRealm)
747 RealmStats() = default;
748 RealmStats(RealmStats&& other) = default;
750 RealmStats(const RealmStats&) = delete; // disallow copying
752 void initClasses();
754 void addSizes(const RealmStats& other) {
755 MOZ_ASSERT(isTotals);
756 FOR_EACH_SIZE(ADD_OTHER_SIZE);
757 classInfo.add(other.classInfo);
760 size_t sizeOfLiveGCThings() const {
761 MOZ_ASSERT(isTotals);
762 size_t n = 0;
763 FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING);
764 n += classInfo.sizeOfLiveGCThings();
765 return n;
768 void addToTabSizes(TabSizes* sizes) const {
769 MOZ_ASSERT(isTotals);
770 FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
771 classInfo.addToTabSizes(sizes);
774 void addToServoSizes(ServoSizes* sizes) const {
775 MOZ_ASSERT(isTotals);
776 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
777 classInfo.addToServoSizes(sizes);
780 FOR_EACH_SIZE(DECL_SIZE_ZERO);
782 // The class measurements in |classInfo| are initially for all classes. At
783 // the end, if the measurement granularity is FineGrained, we subtract the
784 // measurements of the notable classes and move them into |notableClasses|.
785 ClassInfo classInfo;
786 void* extra = nullptr; // This field can be used by embedders.
788 typedef js::HashMap<const char*, ClassInfo, mozilla::CStringHasher,
789 js::SystemAllocPolicy>
790 ClassesHashMap;
792 // These are similar to |allStrings| and |notableStrings| in ZoneStats.
793 mozilla::Maybe<ClassesHashMap> allClasses;
794 js::Vector<NotableClassInfo, 0, js::SystemAllocPolicy> notableClasses;
795 bool isTotals = true;
797 #undef FOR_EACH_SIZE
800 typedef js::Vector<RealmStats, 0, js::SystemAllocPolicy> RealmStatsVector;
801 typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector;
803 struct RuntimeStats {
804 // |gcHeapChunkTotal| is ignored because it's the sum of all the other
805 // values. |gcHeapGCThings| is ignored because it's the sum of some of the
806 // values from the zones and compartments. Both of those values are not
807 // reported directly, but are just present for sanity-checking other
808 // values.
809 #define FOR_EACH_SIZE(MACRO) \
810 MACRO(_, Ignore, gcHeapChunkTotal) \
811 MACRO(_, GCHeapDecommitted, gcHeapDecommittedPages) \
812 MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \
813 MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \
814 MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \
815 MACRO(_, Ignore, gcHeapGCThings)
817 explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
818 : mallocSizeOf_(mallocSizeOf) {}
820 // Here's a useful breakdown of the GC heap.
822 // - rtStats.gcHeapChunkTotal
823 // - decommitted bytes
824 // - rtStats.gcHeapDecommittedPages
825 // (decommitted pages in non-empty chunks)
826 // - unused bytes
827 // - rtStats.gcHeapUnusedChunks (empty chunks)
828 // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
829 // - rtStats.zTotals.unusedGCThings.totalSize()
830 // (empty GC thing slots within non-empty arenas)
831 // - used bytes
832 // - rtStats.gcHeapChunkAdmin
833 // - rtStats.zTotals.gcHeapArenaAdmin
834 // - rtStats.gcHeapGCThings (in-use GC things)
835 // == (rtStats.zTotals.sizeOfLiveGCThings() +
836 // rtStats.cTotals.sizeOfLiveGCThings())
838 // It's possible that some pages in empty chunks may be decommitted, but
839 // we don't count those under rtStats.gcHeapDecommittedPages because (a)
840 // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
841 // multiple of the chunk size, which is good.
843 void addToServoSizes(ServoSizes* sizes) const {
844 FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
845 runtime.addToServoSizes(sizes);
848 FOR_EACH_SIZE(DECL_SIZE_ZERO);
850 RuntimeSizes runtime;
852 RealmStats realmTotals; // The sum of this runtime's realms' measurements.
853 ZoneStats zTotals; // The sum of this runtime's zones' measurements.
855 RealmStatsVector realmStatsVector;
856 ZoneStatsVector zoneStatsVector;
858 ZoneStats* currZoneStats = nullptr;
860 mozilla::MallocSizeOf mallocSizeOf_;
862 virtual void initExtraRealmStats(JS::Realm* realm, RealmStats* rstats,
863 const JS::AutoRequireNoGC& nogc) = 0;
864 virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats,
865 const JS::AutoRequireNoGC& nogc) = 0;
867 #undef FOR_EACH_SIZE
870 class ObjectPrivateVisitor {
871 public:
872 // Within CollectRuntimeStats, this method is called for each JS object
873 // that has an nsISupports pointer.
874 virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0;
876 // A callback that gets a JSObject's nsISupports pointer, if it has one.
877 // Note: this function does *not* addref |iface|.
878 typedef bool (*GetISupportsFun)(JSObject* obj, nsISupports** iface);
879 GetISupportsFun getISupports_;
881 explicit ObjectPrivateVisitor(GetISupportsFun getISupports)
882 : getISupports_(getISupports) {}
885 extern JS_PUBLIC_API bool CollectGlobalStats(GlobalStats* gStats);
887 extern JS_PUBLIC_API bool CollectRuntimeStats(JSContext* cx,
888 RuntimeStats* rtStats,
889 ObjectPrivateVisitor* opv,
890 bool anonymize);
892 extern JS_PUBLIC_API size_t SystemCompartmentCount(JSContext* cx);
893 extern JS_PUBLIC_API size_t UserCompartmentCount(JSContext* cx);
895 extern JS_PUBLIC_API size_t SystemRealmCount(JSContext* cx);
896 extern JS_PUBLIC_API size_t UserRealmCount(JSContext* cx);
898 extern JS_PUBLIC_API size_t PeakSizeOfTemporary(const JSContext* cx);
900 extern JS_PUBLIC_API bool AddSizeOfTab(JSContext* cx, JS::HandleObject obj,
901 mozilla::MallocSizeOf mallocSizeOf,
902 ObjectPrivateVisitor* opv,
903 TabSizes* sizes);
905 extern JS_PUBLIC_API bool AddServoSizeOf(JSContext* cx,
906 mozilla::MallocSizeOf mallocSizeOf,
907 ObjectPrivateVisitor* opv,
908 ServoSizes* sizes);
910 } // namespace JS
912 #undef DECL_SIZE_ZERO
913 #undef ADD_OTHER_SIZE
914 #undef SUB_OTHER_SIZE
915 #undef ADD_SIZE_TO_N
916 #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
917 #undef ADD_TO_TAB_SIZES
919 #endif /* js_MemoryMetrics_h */