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