Coverage Report

Created: 2023-11-19 07:23

/src/hermes/include/hermes/VM/GCBase.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#ifndef HERMES_VM_GCBASE_H
9
#define HERMES_VM_GCBASE_H
10
11
#include "hermes/Inst/Inst.h"
12
#include "hermes/Platform/Logging.h"
13
#include "hermes/Public/CrashManager.h"
14
#include "hermes/Public/GCConfig.h"
15
#include "hermes/Public/GCTripwireContext.h"
16
#include "hermes/Support/CheckedMalloc.h"
17
#include "hermes/Support/OSCompat.h"
18
#include "hermes/Support/StatsAccumulator.h"
19
#include "hermes/VM/AllocOptions.h"
20
#include "hermes/VM/BuildMetadata.h"
21
#include "hermes/VM/CellKind.h"
22
#include "hermes/VM/CompressedPointer.h"
23
#include "hermes/VM/GCDecl.h"
24
#include "hermes/VM/GCExecTrace.h"
25
#include "hermes/VM/GCPointer.h"
26
#include "hermes/VM/HeapAlign.h"
27
#include "hermes/VM/HeapSnapshot.h"
28
#include "hermes/VM/HermesValue.h"
29
#include "hermes/VM/SlotAcceptor.h"
30
#include "hermes/VM/SlotVisitor.h"
31
#include "hermes/VM/SmallHermesValue.h"
32
#include "hermes/VM/StackTracesTree-NoRuntime.h"
33
#include "hermes/VM/StorageProvider.h"
34
#include "hermes/VM/StringRefUtils.h"
35
#include "hermes/VM/VTable.h"
36
#include "hermes/VM/WeakRefSlot.h"
37
38
#include "llvh/ADT/ArrayRef.h"
39
#include "llvh/ADT/BitVector.h"
40
#include "llvh/ADT/DenseMap.h"
41
#include "llvh/Support/ErrorHandling.h"
42
43
#include <cassert>
44
#include <chrono>
45
#include <cstdint>
46
#include <cstdlib>
47
#include <cstring>
48
#include <list>
49
#include <random>
50
#include <system_error>
51
#include <vector>
52
#pragma GCC diagnostic push
53
54
#ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32
55
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
56
#endif
57
namespace hermes {
58
namespace vm {
59
60
/// Forward declarations;
61
namespace detail {
62
struct WeakRefKey;
63
}
64
template <CellKind C>
65
class JSWeakMapImpl;
66
using JSWeakMap = JSWeakMapImpl<CellKind::JSWeakMapKind>;
67
68
class GCCell;
69
70
#ifdef HERMESVM_GC_RUNTIME
71
#define RUNTIME_GC_KINDS GC_KIND(HadesGC)
72
#endif
73
74
/// Used by XorPtr to separate encryption keys between uses.
75
enum XorPtrKeyID {
76
  ArrayBufferData,
77
  JSFunctionCodeBlock,
78
  DummyObjectFinalizerCallback,
79
  _NumKeys
80
};
81
82
// A specific GC class extend GCBase, and override its virtual functions.
83
// In addition, it must implement the following methods:
84
85
/// Allocate a new cell of type \p T and size \p size. Instantiate an object of
86
/// type \p T in the newly allocated cell, using \p args as the arguments to its
87
/// constructor. If necessary perform a GC cycle, which may potentially move
88
/// allocated objects. \p fixedSize should indicate whether the allocation is
89
/// for a fixed-size, small object; some GCs may allow optimizations on this
90
/// basis. \p hasFinalizer must be \p HasFinalizer::Yes if cells of the given
91
/// type require a finalizer to be called.
92
/// \pre size must be heap-aligned.
93
///
94
///   template <
95
///     typename T,
96
///     bool fixedSize = true,
97
///     HasFinalizer hasFinalizer = HasFinalizer::No,
98
///     LongLived longLived = LongLived::No,
99
///     class... Args>
100
/// inline T *makeA(uint32_t size, Args &&... args);
101
///
102
/// In some GCs, objects can have associated memory allocated outside the heap,
103
/// and this memory can influence GC initiation and heap sizing heuristics.
104
/// This method tests whether an external memory allocation is too large (e.g.,
105
/// larger than the max size of the heap):
106
///
107
///   bool canAllocExternalMemory(uint32_t size);
108
///
109
/// These APIs inform the GC of this external memory.
110
///
111
///   void creditExternalMemory(GCCell *alloc, uint32_t size);
112
///   void debitExternalMemory(GCCell *alloc, uint32_t size);
113
///
114
/// Force a garbage collection cycle. The provided cause will be used in
115
/// logging.
116
///   void collect(std::string cause);
117
///
118
/// The maximum size of any one allocation allowable by the GC in any state.
119
///   static constexpr uint32_t maxAllocationSizeImpl();
120
///
121
/// Mark a pointer to a GCCell.
122
///   template <class T> void mark(T *&ptr);
123
///
124
/// Returns true if \p p points into the heap.
125
///   bool contains(const void *p) const;
126
///
127
/// Return the lower bound of the heap's virtual address range (inclusive).
128
///   char *lowLim() const;
129
///
130
/// Return the upper bound of the heap's virtual address range (exclusive).
131
///   char *hiLim() const;
132
///
133
/// Iterate over all objects in the heap.
134
///   void forAllObjs(const std::function<void(GCCell *)> &callback);
135
///
136
/// In the "mark" functions below, Name is one of const char*, int,
137
/// unsigned, or const StringPrimitive*:
138
///
139
/// Mark a HermesValue which may or may not be a pointer.
140
///   void mark(HermesValue &hv, Name name);
141
///   void mark(HermesValue &hv);
142
///
143
/// Mark a T* location. This location must be outside the heap.
144
///   void mark(T *&ptr, Name name);
145
///   void mark(T *&ptr);
146
///
147
/// Mark a GCPointer<T>, which must be within the heap.
148
///   void mark(GCPointer<T> &ptr, Name name);
149
///
150
/// Return true if the GC is active and is calling into the VM.
151
/// If true, some objects in the heap may have an invalid VTable pointer.
152
///   bool calledByGC() const;
153
///
154
/// Various forms of write barriers: these can have empty implementations
155
/// for GCs that don't require them:
156
///
157
///   The given value is being written at the given loc (required to
158
///   be in the heap).  If value is a pointer, execute a write barrier.
159
///     void writeBarrier(GCHermesValue *loc, HermesValue value);
160
///     void writeBarrier(
161
///         const GCSmallHermesValue *loc,
162
///         SmallHermesValue value);
163
///
164
///   The given pointer value is being written at the given loc (required to
165
///   be in the heap).  The value is may be null.  Execute a write barrier.
166
///     void writeBarrier(const GCPointerBase *loc, const GCCell *value);
167
///
168
///   The given value/pointer is being written at a previously uninitialized loc
169
///   (required to be in the heap).
170
///     void constructorWriteBarrier(
171
///         const GCHermesValue *loc,
172
///         HermesValue value);
173
///     void constructorWriteBarrier(
174
///         const GCSmallHermesValue *loc,
175
///         SmallHermesValue value);
176
///     void constructorWriteBarrier(
177
///         const GCPointerBase *loc,
178
///         const GCCell *value);
179
///
180
///   A weak ref is about to be read. Executes a read barrier so the GC can
181
///   take action such as extending the lifetime of the reference. The
182
///   HermesValue version does nothing if the value isn't a pointer.
183
///     void weakRefReadBarrier(GCCell *value);
184
///
185
///   We copied HermesValues into the given region.  Note that \p numHVs is
186
///   the number of HermesValues in the the range, not the char length.
187
///   Do any necessary barriers.
188
///     void writeBarrierRange(GCHermesValue* start, uint32_t numHVs);
189
///     void writeBarrierRange(
190
///         const GCSmallHermesValue *start, uint32_t
191
///         numHVs);
192
///     void constructorWriteBarrierRange(
193
///         const GCHermesValue *start,
194
///         uint32_t numHVs);
195
///     void constructorWriteBarrierRange(
196
///         const GCSmallHermesValue *start,
197
///         uint32_t numHVs);
198
///
199
///   The given loc or region is about to be overwritten, but the new value is
200
///   not important. Perform any necessary barriers.
201
///     void snapshotWriteBarrier(const GCHermesValue *loc);
202
///     void snapshotWriteBarrier(const GCSmallHermesValue *loc);
203
///     void snapshotWriteBarrier(const GCPointerBase *loc);
204
///     void snapshotWriteBarrier(const GCSymboldID *symbol);
205
///     void snapshotWriteBarrierRange(
206
///         const GCHermesValue *start,
207
///         uint32_t numHVs);
208
///     void snapshotWriteBarrierRange(
209
///         const GCSmallHermesValue *start,
210
///         uint32_t numHVs);
211
///
212
///   In debug builds: is a write barrier necessary for a write of the given
213
///   GC pointer \p value to the given \p loc?
214
///      bool needsWriteBarrier(void *loc, void *value);
215
///
216
/// This is intended to be called only from within object or root mark
217
/// functions and indicates whether the \c mark() operation, called within
218
/// the current GC phase, is the first such call that guarantees that the
219
/// location passed to mark will contain the final, correct, pointer value
220
/// after the mark call.
221
///   bool isUpdatingPointers() const;
222
///
223
/// It must also have the inner type:
224
///   class Size;
225
/// Which provides at least these functions publicly:
226
///   Constructor from either a GCConfig or the min and max heap size.
227
///     explicit Size(const GCConfig &conf);
228
///     Size(gcheapsize_t min, gcheapsize_t max);
229
///   Return the minimum amount of bytes holdable by this heap.
230
///     gcheapsize_t min() const;
231
///   Return the maximum amount of bytes holdable by this heap.
232
///     gcheapsize_t max() const;
233
///   Return the total amount of bytes of storage this GC will require.
234
///   This will be a multiple of AlignedStorage::size().
235
///     gcheapsize_t storageFootprint() const;
236
///
237
class GCBase {
238
 public:
239
  static const char kNaturalCauseForAnalytics[];
240
  static const char kHandleSanCauseForAnalytics[];
241
242
  /// An interface enabling the garbage collector to mark roots and free
243
  /// symbols.
244
  struct GCCallbacks {
245
    /// Virtual destructor to avoid warnings.
246
    virtual ~GCCallbacks() = 0;
247
248
    /// Callback that will be invoked by the GC to mark all roots in the
249
    /// beginning of every GC by calling "gc->mark()".
250
    /// The \p markLongLived argument indicates whether root data structures
251
    /// that contain only references to long-lived objects (allocated
252
    /// via allocLongLived) are required to be scanned.  A generational
253
    /// collector, for example, might take advantage of this.
254
    virtual void markRoots(
255
        RootAndSlotAcceptorWithNames &acceptor,
256
        bool markLongLived = true) = 0;
257
258
    /// Callback that will be invoked by the GC to mark all weak roots in the
259
    /// beginning of every GC.
260
    virtual void markWeakRoots(
261
        WeakRootAcceptor &weakAcceptor,
262
        bool markLongLived = true) = 0;
263
264
    /// Callback that might be invoked by the GC before it completes marking.
265
    /// Not all GCs will call this. It should be used to mark any roots that
266
    /// might change without executing proper read and write barriers on the GC.
267
    /// An example would be something that skipped weak ref read barriers in a
268
    /// signal handler. If they aren't marked, they would be collected as
269
    /// garbage.
270
    /// While it is possible to implement this just as forwarding to
271
    /// \c markRoots, to be faster it should try to mark only things that would
272
    /// not have been properly doing barriers.
273
    virtual void markRootsForCompleteMarking(
274
        RootAndSlotAcceptorWithNames &acceptor) = 0;
275
276
    /// \return one higher than the largest symbol in the identifier table. This
277
    /// enables the GC to size its internal structures for symbol marking.
278
    /// Optionally invoked at the beginning of a garbage collection.
279
    virtual unsigned getSymbolsEnd() const = 0;
280
281
    /// If any symbols are marked by the IdentifierTable, clear that marking.
282
    /// Optionally invoked at the beginning of some collections.
283
    virtual void unmarkSymbols() = 0;
284
285
    /// Free all symbols which are not marked as \c true in \p markedSymbols.
286
    /// Optionally invoked at the end of a garbage collection.
287
    virtual void freeSymbols(const llvh::BitVector &markedSymbols) = 0;
288
289
    /// Prints any statistics maintained in the Runtime about GC to \p
290
    /// os.  At present, this means the breakdown of markRoots time by
291
    /// "phase" within markRoots.
292
    virtual void printRuntimeGCStats(JSONEmitter &json) const = 0;
293
294
    /// \returns the approximate usage of memory external to the GC such as
295
    /// malloc by the roots of the object graph.
296
    virtual size_t mallocSize() const = 0;
297
298
    /// Visits every entry in the identifier table and calls acceptor with
299
    /// the entry as argument. This is intended to be used only for Snapshots,
300
    /// as it is slow. The function passed as acceptor shouldn't perform any
301
    /// heap operations.
302
    virtual void visitIdentifiers(
303
        const std::function<void(SymbolID, const StringPrimitive *)>
304
            &acceptor) = 0;
305
306
    /// Convert the given symbol into its UTF-8 string representation.
307
    /// \post The implementation of this function must not perform any GC
308
    ///   operations, such as allocations, mutating values in the heap, or
309
    ///   making handles.
310
    virtual std::string convertSymbolToUTF8(SymbolID id) = 0;
311
312
    /// Returns the current stack as a string. This function will not cause
313
    /// any allocs in the GC.
314
    virtual std::string getCallStackNoAlloc() = 0;
315
316
    /// This is called with CollectionStart at the start of each GC, and with
317
    /// CollectionEnd at the end.
318
    /// \param extraInfo contains more detailed extra info for specific GC.
319
    virtual void onGCEvent(GCEventKind kind, const std::string &extraInfo) = 0;
320
321
    /// Return the current VM instruction pointer which can be used to derive
322
    /// the current VM stack-trace. It's "slow" because it's virtual.
323
    virtual const inst::Inst *getCurrentIPSlow() const = 0;
324
325
#ifdef HERMES_MEMORY_INSTRUMENTATION
326
    /// Return a \c StackTracesTreeNode representing the current VM stack-trace
327
    /// at this point.
328
    virtual StackTracesTreeNode *getCurrentStackTracesTreeNode(
329
        const inst::Inst *ip) = 0;
330
331
    /// Get a StackTraceTree which can be used to recover stack-traces from \c
332
    /// StackTraceTreeNode() as returned by \c getCurrentStackTracesTreeNode() .
333
    virtual StackTracesTree *getStackTracesTree() = 0;
334
#endif
335
336
#ifdef HERMES_SLOW_DEBUG
337
    /// \return true if the given symbol is a live entry in the identifier
338
    /// table.
339
    /// NOTE: Used by CheckHeapWellFormedAcceptor to make sure a symbol
340
    /// that is discovered live is marked as live.
341
    virtual bool isSymbolLive(SymbolID id) = 0;
342
343
    /// \return An associated heap cell for the symbol if one exists, null
344
    /// otherwise.
345
    virtual const void *getStringForSymbol(SymbolID id) = 0;
346
#endif
347
  };
348
349
  /// Stats for collections. Time unit, where applicable, is seconds.
350
  struct CumulativeHeapStats {
351
    unsigned numCollections{0};
352
353
    /// Summary statistics for GC wall times. For Hades, this should only track
354
    /// time spent on the mutator.
355
    StatsAccumulator<double> gcWallTime;
356
357
    /// Summary statistics for GC CPU times.
358
    StatsAccumulator<double> gcCPUTime;
359
360
    gcheapsize_t finalHeapSize{0};
361
362
    /// Bytes allocated just before a collection.
363
    StatsAccumulator<gcheapsize_t, uint64_t> usedBefore;
364
365
    /// Bytes alive after a collection.
366
    StatsAccumulator<gcheapsize_t, uint64_t> usedAfter;
367
  };
368
369
  struct HeapInfo {
370
    /// Number of garbage collections (of any kind) since creation.
371
    unsigned numCollections{0};
372
    /// Total (cumulative) bytes allocated within the JS heap since creation.
373
    uint64_t totalAllocatedBytes{0};
374
    /// Number of currently allocated bytes within the JS heap. Some may be
375
    /// in unreachable objects (unless a full collection just occurred).
376
    uint64_t allocatedBytes{0};
377
    /// Current capacity of the JS heap, in bytes.
378
    uint64_t heapSize{0};
379
    /// Estimate of amount of current malloc space used by the runtime and any
380
    /// auxiliary allocations owned by heap objects. (Calculated by querying
381
    /// each finalizable object to report its malloc usage.)
382
    unsigned mallocSizeEstimate{0};
383
    /// The total amount of Virtual Address space (VA) that the GC is using.
384
    uint64_t va{0};
385
    /// Number of bytes retained by objects as external memory on the C++ heap.
386
    /// This is typically associated with allocations that are modified
387
    /// infrequently, and can therefore be stored in a counter in the GC, making
388
    /// them cheaper to query. This is a subset of mallocSizeEstimate.
389
    uint64_t externalBytes{0};
390
    /// Cumulative number of mark stack overflows in full collections
391
    /// (zero if non-generational GC).
392
    unsigned numMarkStackOverflows{0};
393
    /// Stats for full collections (zeroes if non-generational GC).
394
    CumulativeHeapStats fullStats;
395
    /// Stats for collections in the young generation (zeroes if
396
    /// non-generational GC).
397
    CumulativeHeapStats youngGenStats;
398
  };
399
400
#ifndef NDEBUG
401
  struct DebugHeapInfo {
402
    /// Number of currently allocated objects present in the heap. Some may be
403
    /// unreachable.
404
    unsigned numAllocatedObjects{0};
405
    /// Number of reachable objects in the last collection.
406
    unsigned numReachableObjects{0};
407
    /// Number of collected objects in the last collection.
408
    unsigned numCollectedObjects{0};
409
    /// Number of finalized objects in the last collection.
410
    unsigned numFinalizedObjects{0};
411
    /// Number of marked symbols.
412
    unsigned numMarkedSymbols{0};
413
    /// Number of hidden classes alive after the last collection.
414
    unsigned numHiddenClasses{0};
415
    /// Number of "leaf" hidden classes alive after the last collection.
416
    unsigned numLeafHiddenClasses{0};
417
418
    // Assert any invariants that should hold among the fields of the
419
    // DebugHeapInfo.
420
    void assertInvariants() const;
421
  };
422
#endif
423
424
#ifdef HERMES_MEMORY_INSTRUMENTATION
425
  /// When enabled, every allocation gets an attached stack-trace and an
426
  /// object ID. When disabled old allocations continue to be tracked but
427
  /// no new allocations get a stack-trace.
428
  struct AllocationLocationTracker final {
429
    explicit AllocationLocationTracker(GCBase *gc);
430
431
    /// Returns true if tracking is enabled for new allocations.
432
    bool isEnabled() const;
433
    /// Must be called by GC implementations whenever a new allocation is made.
434
    void newAlloc(const GCCell *ptr, uint32_t sz);
435
436
    /// If an object's size changes, update the entry here.
437
    void updateSize(const GCCell *ptr, uint32_t oldSize, uint32_t newSize);
438
439
    /// Must be called by GC implementations whenever an allocation is freed.
440
    void freeAlloc(const GCCell *ptr, uint32_t sz);
441
    /// Returns data needed to reconstruct the JS stack used to create the
442
    /// specified allocation.
443
    StackTracesTreeNode *getStackTracesTreeNodeForAlloc(
444
        HeapSnapshot::NodeID id) const;
445
446
    /// A Fragment is a time bound for when objects are allocated. Any
447
    /// allocations that occur before the lastSeenObjectID_ are in this
448
    /// fragment. Allocations increment the numObjects_ and numBytes_. Free'd
449
    /// cells from this fragment decrement numObjects_ and numBytes_.
450
    struct Fragment {
451
      HeapSnapshot::NodeID lastSeenObjectID_;
452
      std::chrono::microseconds timestamp_;
453
      /// Number of objects still alive in this fragment. Incremented when
454
      /// objects are created, decremented when objects are destroyed.
455
      uint64_t numObjects_;
456
      /// Total size of objects still alive in this fragment.
457
      uint64_t numBytes_;
458
      /// If true, one of numObjects or numBytes changed since the last flush.
459
      bool touchedSinceLastFlush_;
460
    };
461
462
    /// This must match the definition in jsi::Instrumentation to avoid
463
    /// unnecessary copying.
464
    using HeapStatsUpdate = std::tuple<uint64_t, uint64_t, uint64_t>;
465
466
    /// Enable location tracking.
467
    void enable(std::function<void(
468
                    uint64_t,
469
                    std::chrono::microseconds,
470
                    std::vector<HeapStatsUpdate>)> callback);
471
472
    /// Disable location tracking - turns \c newAlloc() into a no-op. Existing
473
    /// allocations continue to be tracked.
474
    void disable();
475
476
    /// Flush the current fragment and write all flushed fragments to \p snap.
477
    void addSamplesToSnapshot(HeapSnapshot &snap);
478
479
   private:
480
    /// Flush out heap profiler data to the callback after a new kFlushThreshold
481
    /// bytes are allocated.
482
    static constexpr uint64_t kFlushThreshold = 128 * (1 << 10);
483
    /// This mutex protects stackMap_ and fragments_. Specifically does not
484
    /// protect enabled_, because enabled_ should only be changed while the GC
485
    /// isn't running anyway.
486
    Mutex mtx_;
487
    /// Associates allocations at their current location with their stack trace
488
    /// data.
489
    llvh::DenseMap<HeapSnapshot::NodeID, StackTracesTreeNode *> stackMap_;
490
    /// We need access to the GCBase to collect the current stack when nodes are
491
    /// allocated.
492
    GCBase *gc_;
493
    /// Indicates if tracking of new allocations is enabled.
494
    bool enabled_{false};
495
    /// Time when the profiler was started.
496
    std::chrono::steady_clock::time_point startTime_;
497
    /// This should be called periodically whenever the last seen object ID is
498
    /// updated.
499
    std::function<
500
        void(uint64_t, std::chrono::microseconds, std::vector<HeapStatsUpdate>)>
501
        fragmentCallback_;
502
    /// All samples that have been flushed. Only needs the last object ID to be
503
    /// written to the file.
504
    std::vector<Fragment> fragments_;
505
506
    /// Updates the last fragment to have the current last ID and timestamp,
507
    /// then calls fragmentCallback_ with both the new fragment and any changed
508
    /// fragments from freeAlloc.
509
    void flushCallback();
510
511
    /// Find the fragment corresponding to the given id.
512
    /// \return fragments_.back() if none exists (it's the currently active
513
    ///   fragment).
514
    Fragment &findFragmentForID(HeapSnapshot::NodeID id);
515
  };
516
517
  class SamplingAllocationLocationTracker final {
518
   public:
519
105
    explicit inline SamplingAllocationLocationTracker(GCBase *gc) : gc_(gc) {}
520
521
    /// Returns true if tracking is enabled for new allocations.
522
621k
    bool isEnabled() const {
523
621k
      return !!dist_;
524
621k
    }
525
526
    /// Must be called by GC implementations whenever a new allocation is made.
527
    void newAlloc(const GCCell *ptr, uint32_t sz);
528
529
    /// Must be called by GC implementations whenever an allocation is freed.
530
    void freeAlloc(const GCCell *ptr, uint32_t sz);
531
532
    /// If an object's size changes, update the entry here.
533
    void updateSize(const GCCell *ptr, uint32_t oldSize, uint32_t newSize);
534
535
    /// Turn the sampling memory profiler on. About once every
536
    /// \p samplingInterval bytes are allocated, sample the allocation by
537
    /// recording its stack.
538
    /// \param seed If non-negative, use as the seed for the random sampling
539
    ///   mechanism, giving deterministic output.
540
    void enable(size_t samplingInterval, int64_t seed);
541
542
    void disable(llvh::raw_ostream &os);
543
544
   private:
545
    struct Sample final {
546
      size_t size;
547
      StackTracesTreeNode *node;
548
      /// This is the auto-incremented sample ID, not the ID of the object
549
      /// associated with the sample.
550
      uint64_t id;
551
    };
552
553
    /// This mutex protects stackMap_ and samples_. Not needed for enabling and
554
    /// disabling because those only happen while the world is stopped.
555
    Mutex mtx_;
556
557
    GCBase *gc_;
558
559
    /// Subtract from this each allocation. If it would underflow below zero,
560
    /// take a sample.
561
    size_t limit_{0};
562
563
    /// Track all samples that have been taken.
564
    llvh::DenseMap<HeapSnapshot::NodeID, Sample> samples_;
565
566
    /// Use a poisson distribution to decide when to take the next sample.
567
    std::minstd_rand randomEngine_;
568
    std::unique_ptr<std::poisson_distribution<>> dist_;
569
570
    /// An auto-incrementing integer representing a unique ID for a sample.
571
    /// Used for ordering samples.
572
    uint64_t nextSampleID_{1};
573
574
    /// \return How many bytes should be waited until the next sample.
575
    size_t nextSample();
576
  };
577
#endif
578
579
  class IDTracker final {
580
   public:
581
    /// These are IDs that are reserved for special objects.
582
    enum class ReservedObjectID : HeapSnapshot::NodeID {
583
      // The ID for the super root object.
584
      SuperRoot,
585
      // The ID for the (GC roots) object.
586
      GCRoots,
587
#define ROOT_SECTION(name) name,
588
#include "hermes/VM/RootSections.def"
589
      IdentifierTableLookupVector,
590
      IdentifierTableHashTable,
591
      IdentifierTableMarkedSymbols,
592
      JSIHermesValueList,
593
      JSIWeakHermesValueList,
594
      WeakRefSlotStorage,
595
      Undefined,
596
      Null,
597
      True,
598
      False,
599
      FirstNonReservedID,
600
    };
601
602
    // 0 is guaranteed to never be a valid node ID.
603
    static constexpr HeapSnapshot::NodeID kInvalidNode = 0;
604
605
105
    static constexpr HeapSnapshot::NodeID reserved(ReservedObjectID id) {
606
      // All reserved IDs should be odd numbers to signify that they're JS
607
      // objects and not native objects. This follows v8's output.
608
105
      return static_cast<std::underlying_type<ReservedObjectID>::type>(id) * 2 +
609
105
          1;
610
105
    }
611
612
    /// A comparator for doubles that allows NaN.
613
    struct DoubleComparator {
614
0
      static double getEmptyKey() {
615
        // Use a non-canonical NaN value as an empty value, which should never
616
        // occur naturally.
617
        // NOTE: HermesValue uses NaN tagging internally so we can use that to
618
        // get the encoding.
619
0
        return llvh::BitsToDouble(HermesValue::encodeUndefinedValue().getRaw());
620
0
      }
621
0
      static double getTombstoneKey() {
622
        // Use a non-canonical NaN value as the tombstone, which should never
623
        // occur naturally.
624
        // NOTE: HermesValue uses NaN tagging internally so we can use that to
625
        // get the encoding.
626
0
        return llvh::BitsToDouble(HermesValue::encodeNullValue().getRaw());
627
0
      }
628
0
      static unsigned getHashValue(double val) {
629
0
        return std::hash<uint64_t>{}(llvh::DoubleToBits(val));
630
0
      }
631
0
      static bool isEqual(double LHS, double RHS) {
632
0
        return llvh::DoubleToBits(LHS) == llvh::DoubleToBits(RHS);
633
0
      }
634
    };
635
636
    explicit IDTracker();
637
638
    /// Return true if IDs are being tracked.
639
    bool isTrackingIDs();
640
641
    /// Get the unique object id of the given object.
642
    /// If one does not yet exist, start tracking it.
643
    HeapSnapshot::NodeID getObjectID(CompressedPointer cell);
644
645
    /// \return true if the cell has an object ID associated with it, false if
646
    ///   there is none.
647
    bool hasObjectID(CompressedPointer cell);
648
649
    /// Same as \c getObjectID, except it asserts if the cell doesn't have an
650
    /// ID.
651
    HeapSnapshot::NodeID getObjectIDMustExist(CompressedPointer cell);
652
653
    /// Get the unique object id of the symbol with the given symbol \p sym. If
654
    /// one does not yet exist, start tracking it.
655
    HeapSnapshot::NodeID getObjectID(SymbolID sym);
656
657
    /// Get the unique object id of the given native memory (non-JS-heap).
658
    /// If one does not yet exist, start tracking it.
659
    HeapSnapshot::NodeID getNativeID(const void *mem);
660
661
    /// Get a list of IDs for native memory attached to the given node.
662
    /// List will be empty if nothing is attached yet. Then push onto the end
663
    /// with nextNativeID().
664
    /// When the NodeID that these are attached to is untracked, so are the
665
    /// attached native NodeIDs.
666
    llvh::SmallVector<HeapSnapshot::NodeID, 1> &getExtraNativeIDs(
667
        HeapSnapshot::NodeID node);
668
669
    /// Assign a unique ID to a literal number value that occurs in the heap.
670
    /// Can be used to make fake nodes that will display their numeric value.
671
    HeapSnapshot::NodeID getNumberID(double num);
672
673
    /// Get the object pointer for the given ID. This is the inverse of \c
674
    /// getObjectID.
675
    /// Returns none if there is no object for that ID.
676
    llvh::Optional<CompressedPointer> getObjectForID(HeapSnapshot::NodeID id);
677
678
    /// Tell the tracker that an object has moved locations.
679
    /// This must be called in a safe order, if A moves to B, and C moves to A,
680
    /// the first move must be recorded before the second.
681
    void moveObject(
682
        CompressedPointer oldLocation,
683
        CompressedPointer newLocation);
684
685
    /// Remove the object from being tracked. This should be done to keep the
686
    /// tracking working set small.
687
    void untrackObject(CompressedPointer cell);
688
689
    /// Remove the symbol from being tracked. This needs to be done to allow
690
    /// symbols to be re-used.
691
    void untrackSymbol(uint32_t symIdx);
692
693
    /// Remove the native memory from being tracked. This should be done to keep
694
    /// the tracking working set small. It is also required to be done when
695
    /// malloc'ed memory is freed, since addresses can be re-used by future
696
    /// allocations.
697
    void untrackNative(const void *mem);
698
699
    /// \return True if this is tracking any native IDs, false if there are no
700
    ///   native IDs being tracked.
701
    bool hasNativeIDs();
702
703
    /// Get the current last ID. All other existing IDs are less than or equal
704
    /// to this one.
705
    HeapSnapshot::NodeID lastID() const;
706
707
    /// Get the next unique native ID for a chunk of native memory.
708
    /// NOTE: public to get assigned native ids without needing to reserve in
709
    /// advance.
710
    HeapSnapshot::NodeID nextNativeID();
711
712
   private:
713
    /// Get the next unique object ID for a newly created object.
714
    HeapSnapshot::NodeID nextObjectID();
715
    /// Get the next unique number ID for a number.
716
    HeapSnapshot::NodeID nextNumberID();
717
718
    /// JS heap nodes are represented by odd-numbered IDs, while native nodes
719
    /// are represented with even-numbered IDs. This requirement is enforced by
720
    /// the Chrome snapshot viewer.
721
    static constexpr HeapSnapshot::NodeID kIDStep = 2;
722
723
    /// This mutex protects objectIDMap_, symbolIDMap_, and numberIDMap_.
724
    /// Specifically does not protect lastID_, since there's only one allocator
725
    /// at a time, and only new allocations affect lastID_.
726
    Mutex mtx_;
727
728
    /// The last ID assigned to a non-native object. Object IDs are not
729
    /// recycled so that snapshots don't confuse two objects with each other.
730
    /// NOTE: Reserved guarantees that this is an odd number.
731
    HeapSnapshot::NodeID lastID_{
732
        reserved(ReservedObjectID::FirstNonReservedID)};
733
734
    /// Map of object pointers to IDs. Only populated once the first heap
735
    /// snapshot is requested, or the first time the memory profiler is turned
736
    /// on, or if JSI tracing is in effect.
737
    /// This map's size is O(number of cells in the heap), which can grow quite
738
    /// large. Using compressed pointers keeps the size small.
739
    llvh::DenseMap<CompressedPointer::RawType, HeapSnapshot::NodeID>
740
        objectIDMap_;
741
742
    /// The inverse of \c objectIDMap_. Only used for debugging views on heap
743
    /// snapshots. To avoid wasting memory in the case where the debugger hasn't
744
    /// requested any, it is populated lazily as each entry is requested. We
745
    /// expect the vast majority of objects aren't inspected in the snapshot.
746
    llvh::DenseMap<HeapSnapshot::NodeID, CompressedPointer::RawType>
747
        idObjectMap_;
748
749
    /// Map of native pointers to IDs. Populated according to
750
    /// the same rules as the objectIDMap_.
751
    llvh::DenseMap<const void *, HeapSnapshot::NodeID> nativeIDMap_;
752
753
    /// Map from a JS heap object ID to additional lazily created IDs for
754
    /// objects. Most useful for native IDs that are attached to a heap object
755
    /// but don't have a stable pointer to use (such as std::vector and
756
    /// llvh::DenseMap).
757
    llvh::DenseMap<
758
        HeapSnapshot::NodeID,
759
        llvh::SmallVector<HeapSnapshot::NodeID, 1>>
760
        extraNativeIDs_;
761
762
    /// Map from symbol indices to unique IDs.  Populated according to
763
    /// the same rules as the objectIDMap_.
764
    llvh::DenseMap<uint32_t, HeapSnapshot::NodeID> symbolIDMap_;
765
766
    /// Map of numeric values to IDs. Used to give numbers in the heap a unique
767
    /// node.
768
    llvh::DenseMap<double, HeapSnapshot::NodeID, DoubleComparator> numberIDMap_;
769
  };
770
771
  enum class HeapKind { HadesGC, MallocGC };
772
773
  GCBase(
774
      GCCallbacks &gcCallbacks,
775
      PointerBase &pointerBase,
776
      const GCConfig &gcConfig,
777
      std::shared_ptr<CrashManager> crashMgr,
778
      HeapKind kind);
779
780
105
  virtual ~GCBase() {}
781
782
  /// Create a fixed size object of type T.
783
  /// \return a pointer to the newly created object in the GC heap.
784
  template <
785
      typename T,
786
      HasFinalizer hasFinalizer = HasFinalizer::No,
787
      LongLived longLived = LongLived::No,
788
      class... Args>
789
  T *makeAFixed(Args &&...args);
790
791
  /// Create a variable size object of type T and size \p size.
792
  /// \return a pointer to the newly created object in the GC heap.
793
  template <
794
      typename T,
795
      HasFinalizer hasFinalizer = HasFinalizer::No,
796
      LongLived longLived = LongLived::No,
797
      class... Args>
798
  T *makeAVariable(uint32_t size, Args &&...args);
799
800
  template <
801
      typename T,
802
      bool fixedSize = true,
803
      HasFinalizer hasFinalizer = HasFinalizer::No,
804
      LongLived longLived = LongLived::No,
805
      class... Args>
806
  T *makeA(uint32_t size, Args &&...args);
807
808
  /// Name to identify this heap in logs.
809
979
  const std::string &getName() const {
810
979
    return name_;
811
979
  }
812
813
  /// \return the base of pointers in the heap.
814
  /// NOTE: This normally should not be needed, Runtime provides it.
815
  /// However in some scenarios there is only a GC available, not a
816
  /// Runtime. In those cases use this function.
817
12.7M
  PointerBase &getPointerBase() const {
818
12.7M
    return pointerBase_;
819
12.7M
  }
820
821
18.3M
  GCCallbacks &getCallbacks() const {
822
18.3M
    return gcCallbacks_;
823
18.3M
  }
824
825
  /// Forwards to the GC callback \p convertSymbolToUTF8, see documentation
826
  /// for that function.
827
0
  std::string convertSymbolToUTF8(SymbolID id) {
828
0
    return gcCallbacks_.convertSymbolToUTF8(id);
829
0
  }
830
831
  /// Called by the Runtime to inform the GC that it is about to execute JS for
832
  /// the first time.
833
  void runtimeWillExecute();
834
835
  /// Inform the GC that TTI has been reached.  (In case, for example,
836
  /// behavior should change at that point.  Default behavior is to do
837
  /// nothing.)
838
0
  virtual void ttiReached() {}
839
840
  /// Do anything necessary to record the current number of allocated
841
  /// objects in numAllocatedObjects_.  Default is to do nothing.
842
0
  virtual void recordNumAllocatedObjects() {}
843
844
  /// Print any and all collected statistics to the give output stream, \p os.
845
  void printAllCollectedStats(llvh::raw_ostream &os);
846
847
  /// Total number of collections of any kind.
848
0
  unsigned getNumGCs() const {
849
0
    return cumStats_.numCollections;
850
0
  }
851
852
  /// Total wall time in seconds of all pauses due to collections so far.
853
0
  double getGCTime() const {
854
0
    return cumStats_.gcWallTime.sum();
855
0
  }
856
857
  /// Total CPU time in seconds of all pauses due to collections so far.
858
0
  double getGCCPUTime() const {
859
0
    return cumStats_.gcCPUTime.sum();
860
0
  }
861
862
0
  GCCallbacks &getGCCallbacks() const {
863
0
    return gcCallbacks_;
864
0
  }
865
866
  /// Cumulative stats over time so far.
867
0
  virtual size_t getPeakAllocatedBytes() const {
868
0
    return cumStats_.usedBefore.max();
869
0
  }
870
0
  virtual size_t getPeakLiveAfterGC() const {
871
0
    return cumStats_.usedAfter.max();
872
0
  }
873
874
  /// Populate \p info with information about the heap.
875
  virtual void getHeapInfo(HeapInfo &info);
876
  /// Same as \c getHeapInfo, and it adds the amount of malloc memory in use.
877
  virtual void getHeapInfoWithMallocSize(HeapInfo &info);
878
879
  /// Return a reference to the GCExecTrace object, which is used if
880
  /// we're keeping track of information about GCs, for tracing, for example.
881
  const GCExecTrace &getGCExecTrace() const;
882
883
  /// Populate \p info with crash manager information about the heap
884
  virtual void getCrashManagerHeapInfo(CrashManager::HeapInformation &info) = 0;
885
886
#ifndef NDEBUG
887
  /// Populate \p info with more detailed information about the heap that is
888
  /// too expensive to know during production builds.
889
  virtual void getDebugHeapInfo(DebugHeapInfo &info);
890
891
  /// \return Number of weak ref slots currently in use.
892
  /// Inefficient. For testing/debugging.
893
  size_t countUsedWeakRefs() const;
894
895
  /// Return true if \p ptr is currently pointing at valid accessable memory,
896
  /// allocated to an object.
897
  virtual bool validPointer(const void *ptr) const = 0;
898
#endif
899
900
#ifdef HERMESVM_GC_RUNTIME
901
  inline static constexpr uint32_t minAllocationSizeImpl();
902
903
  inline static constexpr uint32_t maxAllocationSizeImpl();
904
#endif
905
906
  inline static constexpr uint32_t minAllocationSize();
907
908
  inline static constexpr uint32_t maxAllocationSize();
909
910
  /// Dump detailed heap contents to the given output stream, \p os.
911
  virtual void dump(llvh::raw_ostream &os, bool verbose = false);
912
913
  /// Run the finalizers for all heap objects.
914
  virtual void finalizeAll() = 0;
915
916
  /// Force a garbage collection cycle. The provided cause will be used in
917
  /// logging.
918
  virtual void collect(std::string cause, bool canEffectiveOOM = false) = 0;
919
920
  /// Iterate over all objects in the heap, and call \p callback on them.
921
  /// \param callback A function to call on each found object.
922
  virtual void forAllObjs(const std::function<void(GCCell *)> &callback) = 0;
923
924
  /// \return true if the pointer lives in the young generation.
925
0
  virtual bool inYoungGen(const void *p) const {
926
0
    return false;
927
0
  }
928
929
  /// Returns whether an external allocation of the given \p size fits
930
  /// within the maximum heap size. (Note that this does not guarantee that the
931
  /// allocation will "succeed" -- the size plus the used() of the heap may
932
  /// still exceed the max heap size. But if it fails, the allocation can never
933
  /// succeed.)
934
0
  virtual bool canAllocExternalMemory(uint32_t size) {
935
0
    return true;
936
0
  }
937
938
  WeakRefSlot *allocWeakSlot(CompressedPointer ptr);
939
940
#ifndef NDEBUG
941
  /// \name Debug APIs
942
  /// \{
943
0
  virtual bool calledByBackgroundThread() const {
944
0
    return false;
945
0
  }
946
0
  virtual bool calledByGC() const {
947
0
    return true;
948
0
  }
949
  virtual bool dbgContains(const void *ptr) const = 0;
950
0
  virtual void trackReachable(CellKind kind, unsigned sz) {}
951
  virtual bool needsWriteBarrier(void *loc, GCCell *value) = 0;
952
  /// \}
953
#endif
954
955
  /// Do any logging of info about the heap that is useful, then dies with a
956
  /// fatal out-of-memory error.
957
  LLVM_ATTRIBUTE_NORETURN void oom(std::error_code reason);
958
959
#ifdef HERMES_MEMORY_INSTRUMENTATION
960
  /// Creates a snapshot of the heap and writes it to the given \p fileName.
961
  /// \return An error code on failure, else an empty error code.
962
  std::error_code createSnapshotToFile(const std::string &fileName);
963
964
  /// Creates a snapshot of the heap, which includes information about what
965
  /// objects exist, their sizes, and what they point to.
966
  virtual void createSnapshot(llvh::raw_ostream &os) = 0;
967
  void createSnapshot(GC &gc, llvh::raw_ostream &os);
968
969
  /// Subclasses can override and add more specific native memory usage.
970
  virtual void snapshotAddGCNativeNodes(HeapSnapshot &snap);
971
972
  /// Subclasses can override and add more specific edges.
973
  virtual void snapshotAddGCNativeEdges(HeapSnapshot &snap);
974
975
  /// Turn on the heap profiler, which will track when allocations are made and
976
  /// the stack trace of when they were created.
977
  virtual void enableHeapProfiler(
978
      std::function<void(
979
          uint64_t,
980
          std::chrono::microseconds,
981
          std::vector<GCBase::AllocationLocationTracker::HeapStatsUpdate>)>
982
          fragmentCallback);
983
984
  /// Turn off the heap profiler, which will stop tracking new allocations and
985
  /// not record any stack traces.
986
  /// Disabling will not forget any objects that are still alive. This way
987
  /// re-enabling later will still remember earlier objects.
988
  virtual void disableHeapProfiler();
989
990
  /// Turn the sampling memory profiler on. About once every
991
  /// \p samplingInterval bytes are allocated, sample the allocation by
992
  /// recording its stack.
993
  /// \param seed If non-negative, use as the seed for the random sampling
994
  ///   mechanism, giving deterministic output.
995
  virtual void enableSamplingHeapProfiler(
996
      size_t samplingInterval,
997
      int64_t seed);
998
999
  /// Turn off the sampling heap profiler, which will stop tracking new
1000
  /// allocations and not record any stack traces. Write out the results of the
1001
  /// trace to \p os. After this call, any remembered data about sampled objects
1002
  /// will be gone.
1003
  virtual void disableSamplingHeapProfiler(llvh::raw_ostream &os);
1004
#endif // HERMES_MEMORY_INSTRUMENTATION
1005
1006
  /// Inform the GC about external memory retained by objects.
1007
  virtual void creditExternalMemory(GCCell *alloc, uint32_t size) = 0;
1008
  virtual void debitExternalMemory(GCCell *alloc, uint32_t size) = 0;
1009
1010
#ifdef HERMESVM_GC_RUNTIME
1011
  /// Default implementations for read and write barriers: do nothing.
1012
  void writeBarrier(const GCHermesValue *loc, HermesValue value);
1013
  void writeBarrier(const GCSmallHermesValue *loc, SmallHermesValue value);
1014
  void writeBarrier(const GCPointerBase *loc, const GCCell *value);
1015
  void constructorWriteBarrier(const GCHermesValue *loc, HermesValue value);
1016
  void constructorWriteBarrier(
1017
      const GCSmallHermesValue *loc,
1018
      SmallHermesValue value);
1019
  void constructorWriteBarrier(const GCPointerBase *loc, const GCCell *value);
1020
  void writeBarrierRange(const GCHermesValue *start, uint32_t numHVs);
1021
  void writeBarrierRange(const GCSmallHermesValue *start, uint32_t numHVs);
1022
  void constructorWriteBarrierRange(
1023
      const GCHermesValue *start,
1024
      uint32_t numHVs);
1025
  void constructorWriteBarrierRange(
1026
      const GCSmallHermesValue *start,
1027
      uint32_t numHVs);
1028
  void snapshotWriteBarrier(const GCHermesValue *loc);
1029
  void snapshotWriteBarrier(const GCSmallHermesValue *loc);
1030
  void snapshotWriteBarrier(const GCPointerBase *loc);
1031
  void snapshotWriteBarrier(const GCSymbolID *symbol);
1032
  void snapshotWriteBarrierRange(const GCHermesValue *start, uint32_t numHVs);
1033
  void snapshotWriteBarrierRange(
1034
      const GCSmallHermesValue *start,
1035
      uint32_t numHVs);
1036
  void weakRefReadBarrier(GCCell *value);
1037
#endif
1038
1039
  /// @name Marking APIs
1040
  /// @{
1041
1042
  /// Marks a cell by its metadata.
1043
  /// \p cell The heap object to mark.
1044
  /// \p acceptor The action to perform on each slot in the cell.
1045
  template <typename Acceptor>
1046
  inline void markCell(GCCell *cell, Acceptor &acceptor);
1047
1048
  /// Same as the normal \c markCell, but for cells that don't have a valid
1049
  /// CellKind.
1050
  template <typename Acceptor>
1051
  inline void markCell(GCCell *cell, CellKind kind, Acceptor &acceptor);
1052
1053
  /// Same as the normal \c markCell, but takes a visitor instead.
1054
  template <typename Acceptor>
1055
  inline void
1056
  markCell(SlotVisitor<Acceptor> &visitor, GCCell *cell, CellKind kind);
1057
1058
  /// Marks a cell by its metadata, but only for the slots that point between
1059
  /// [begin, end).
1060
  template <typename Acceptor>
1061
  inline void markCellWithinRange(
1062
      SlotVisitor<Acceptor> &visitor,
1063
      GCCell *cell,
1064
      CellKind kind,
1065
      const char *begin,
1066
      const char *end);
1067
1068
  /// Marks a cell by its metadata, and outputs the names of the slots.
1069
  /// Meant to be used by heap snapshots.
1070
  template <typename Acceptor>
1071
  inline void markCellWithNames(
1072
      SlotVisitorWithNames<Acceptor> &visitor,
1073
      GCCell *cell);
1074
1075
  /// Utilities for WeakMap marking.
1076
1077
  /// \return a list of pointers to all the WeakRefKeys in \p weakMap.
1078
  /// The \p gc argument is passed to methods that verify they're only
1079
  /// called during GC.
1080
  static std::vector<detail::WeakRefKey *> buildKeyList(
1081
      GC &gc,
1082
      JSWeakMap *weakMap);
1083
1084
  /// For all non-null keys in \p weakMap that are unreachable, clear
1085
  /// the key (clear the pointer in the WeakRefSlot) and value (set it
1086
  /// to undefined).
1087
  template <typename KeyReachableFunc>
1088
  static void clearEntriesWithUnreachableKeys(
1089
      GC &gc,
1090
      JSWeakMap *weakMap,
1091
      KeyReachableFunc keyReachable);
1092
1093
  /// For all reachable keys in \p weakMap, mark from the
1094
  /// corresponding value using the given \p acceptor, reaching a
1095
  /// transitive closure.  The acceptor is required to have a property
1096
  /// we don't normally require: it must be idempotent.  I.e., it must
1097
  /// function properly when applied multiple times to the same
1098
  /// pointer slot during a collection.  "Mark-in-place" acceptors
1099
  /// will generally have this property.  Uses \p objIsMarked to
1100
  /// determine whether an object is marked, and, for entries whose
1101
  /// keys are marked, invokes \p markFromVal on the corresponding value.
1102
  /// These have the following specs:
1103
  ///
1104
  ///  * objIsMarked: (GCCell*) ==> bool
1105
  ///    Returns whether a GCCell is marked.
1106
  ///
1107
  ///  * markFromVal: GCCell *cell, GCHermesValue &cellRef) ==> bool
1108
  ///    If the argument is unmarked, mark it, schedule for scanning.
1109
  ///    Returns whether the object was newly marked.
1110
  ///
1111
  /// If the \p unreachableKeys map has an entry for \p weakMap, assumes the
1112
  /// list of WeakRefKeys contains all possibly-unreachable keys; any
1113
  /// other keys are assumed to have already been found reachable.
1114
  /// Ensures that \p unreachableKeys has an accurate value for \p
1115
  /// weakMap before return.  \return whether any previously-unmarked
1116
  /// values were marked.
1117
  template <
1118
      typename Acceptor,
1119
      typename ObjIsMarkedFunc,
1120
      typename MarkFromValFunc>
1121
  static bool markFromReachableWeakMapKeys(
1122
      GC &gc,
1123
      JSWeakMap *weakMap,
1124
      Acceptor &acceptor,
1125
      llvh::DenseMap<JSWeakMap *, std::vector<detail::WeakRefKey *>>
1126
          *unreachableKeys,
1127
      ObjIsMarkedFunc objIsMarked,
1128
      MarkFromValFunc markFromVal);
1129
1130
  /// \return A reference to the mutex that controls accessing any WeakRef.
1131
  ///   This mutex must be held if a WeakRef is created or modified.
1132
1.71M
  WeakRefMutex &weakRefMutex() {
1133
1.71M
    return weakRefMutex_;
1134
1.71M
  }
1135
1136
  /// Assumes that all known reachable WeakMaps have been collected in
1137
  /// \p reachableWeakMaps.  For all these WeakMaps, find all
1138
  /// reachable keys and mark from the corresponding value using the given \p
1139
  /// acceptor, reaching a transitive closure.
1140
  /// Do this until no newly reachable objects are found in a
1141
  /// traversal of the WeakMaps.  We assume that WeakMaps found newly
1142
  /// reachable are added to \p reachableWeakMaps, and do not assume
1143
  /// we've reached transitive closure until all maps are scanned.
1144
  /// Uses \p objIsMarked to determine whether an object is marked,
1145
  /// and, for entries whose keys are marked, invokes \p
1146
  /// checkValIsMarked on the corresponding value.  Used \p
1147
  /// drainMarkStack to ensure that the transitive closure of what's
1148
  /// currently on the mark stack is marked.  Requires \p acceptor
1149
  /// to be idempotent: it must be legal to apply the acceptor
1150
  /// multiple times to the same slot.  The function arguments have
1151
  /// the following specs:
1152
  ///
1153
  ///  * objIsMarked: (GCCell *) ==> bool
1154
  ///    Returns whether a GCCell is marked.
1155
  ///
1156
  ///  * markFromVal: (GCCell *cell, HermesValue &cellRef) ==> bool
1157
  ///    Requires that \p cell is non-null, and the value of \p
1158
  ///    cellRef.  If the argument is unmarked, ensure that its
1159
  ///    transitive closure is marked.  Returns whether the object was
1160
  ///    newly marked.
1161
  ///
1162
  ///  * drainMarkStack: (Acceptor &acceptor) ==> void
1163
  ///    Ensures that the mark stack used by the collector is empty;
1164
  ///    the transitive closure of the original contents is marked.
1165
  ///
1166
  ///  * checkMarkStackOverflow: () ==> bool
1167
  ///    Returns whether mark stack overflow has occurred.
1168
  ///
1169
  /// Some collectors compute the allocated bytes during GC.  If this
1170
  /// is done in \p drainMarkStack, that will cover all objects except
1171
  /// WeakWaps, which are never pushed on the mark stack.  Thus:
1172
  /// \return the total size of reachable WeakMaps.
1173
  template <
1174
      typename Acceptor,
1175
      typename ObjIsMarkedFunc,
1176
      typename MarkFromValFunc,
1177
      typename DrainMarkStackFunc,
1178
      typename CheckMarkStackOverflowFunc>
1179
  static gcheapsize_t completeWeakMapMarking(
1180
      GC &gc,
1181
      Acceptor &acceptor,
1182
      std::vector<JSWeakMap *> &reachableWeakMaps,
1183
      ObjIsMarkedFunc objIsMarked,
1184
      MarkFromValFunc markFromVal,
1185
      DrainMarkStackFunc drainMarkStack,
1186
      CheckMarkStackOverflowFunc checkMarkStackOverflow);
1187
1188
  /// @}
1189
1190
  /// If false, all reachable objects in the heap will have a dereference-able
1191
  /// VTable pointer which describes its type and size. If true, both reachable
1192
  /// objects and unreachable objects may not have dereference-able VTable
1193
  /// pointers, and any reads from JS heap memory may give strange results.
1194
312k
  bool inGC() const {
1195
312k
    return inGC_;
1196
312k
  }
1197
1198
0
  HeapKind getKind() const {
1199
0
    return heapKind_;
1200
0
  }
1201
1202
  /// \return A string representation of the kind of GC.
1203
  virtual std::string getKindAsStr() const = 0;
1204
1205
1.22k
  bool isTrackingIDs() {
1206
1.22k
#ifdef HERMES_MEMORY_INSTRUMENTATION
1207
1.22k
    return getIDTracker().isTrackingIDs() ||
1208
1.22k
        getAllocationLocationTracker().isEnabled() ||
1209
1.22k
        getSamplingAllocationTracker().isEnabled();
1210
#else
1211
    return getIDTracker().isTrackingIDs();
1212
#endif
1213
1.22k
  }
1214
1215
7.92k
  IDTracker &getIDTracker() {
1216
7.92k
    return idTracker_;
1217
7.92k
  }
1218
1219
#ifdef HERMES_MEMORY_INSTRUMENTATION
1220
1.22k
  AllocationLocationTracker &getAllocationLocationTracker() {
1221
1.22k
    return allocationLocationTracker_;
1222
1.22k
  }
1223
1224
1.22k
  SamplingAllocationLocationTracker &getSamplingAllocationTracker() {
1225
1.22k
    return samplingAllocationTracker_;
1226
1.22k
  }
1227
#endif
1228
1229
  /// \name Snapshot ID methods
1230
  /// \{
1231
  // This set of methods are all mirrors of IDTracker, except with pointer
1232
  // compression done automatically.
1233
  HeapSnapshot::NodeID getObjectID(const GCCell *cell);
1234
  HeapSnapshot::NodeID getObjectIDMustExist(const GCCell *cell);
1235
  HeapSnapshot::NodeID getObjectID(CompressedPointer cell);
1236
  HeapSnapshot::NodeID getObjectID(SymbolID sym);
1237
  HeapSnapshot::NodeID getNativeID(const void *mem);
1238
  /// \return The ID for the given value. If the value cannot be represented
1239
  ///   with an ID, returns None.
1240
  llvh::Optional<HeapSnapshot::NodeID> getSnapshotID(HermesValue val);
1241
1242
  /// \return The object pointer for the given \p id. This is quite slow.
1243
  ///   If there is no such object this returns nullptr.
1244
  void *getObjectForID(HeapSnapshot::NodeID id);
1245
1246
  /// \return True if the given cell has an ID associated with it.
1247
  bool hasObjectID(const GCCell *cell);
1248
  /// Records that a new allocation has occurred.
1249
  void newAlloc(const GCCell *ptr, uint32_t sz);
1250
  /// Moves an object to a new address and a new size for all trackers.
1251
  void moveObject(
1252
      const GCCell *oldPtr,
1253
      uint32_t oldSize,
1254
      const GCCell *newPtr,
1255
      uint32_t newSize);
1256
  /// Untracks a freed object from all trackers.
1257
  void untrackObject(const GCCell *cell, uint32_t sz);
1258
  /// \}
1259
1260
#ifndef NDEBUG
1261
  /// \return The next debug allocation ID for embedding directly into a GCCell.
1262
  /// NOTE: This is not the same ID as is used for stable lifetime tracking, use
1263
  /// \p getObjectID for that.
1264
  uint64_t nextObjectID();
1265
#endif
1266
1267
// Mangling scheme used by MSVC encode public/private into the name.
1268
// As a result, vanilla "ifdef public" trick leads to link errors.
1269
#if defined(UNIT_TEST) || defined(_MSC_VER)
1270
 public:
1271
#else
1272
 protected:
1273
#endif
1274
1275
  /// dataSize is the live data in bytes, now is the current time point. The
1276
  /// function checks these parameters against the limits set at initialisation.
1277
  /// If the conditions are met, the tripwire is triggered and tripwireCallback_
1278
  /// is called.
1279
  void checkTripwire(size_t dataSize);
1280
1281
  // Visibility here is public for unit_tests and protected otherwise
1282
1283
 protected:
1284
  /// An RAII-style object used to denote regions when a GC cycle is considered
1285
  /// active.
1286
  class GCCycle final {
1287
   public:
1288
    explicit GCCycle(GCBase &gc, std::string extraInfo = "");
1289
    ~GCCycle();
1290
1291
0
    const std::string &extraInfo() {
1292
0
      return extraInfo_;
1293
0
    }
1294
1295
   private:
1296
    GCBase &gc_;
1297
    std::string extraInfo_;
1298
    bool previousInGC_;
1299
  };
1300
1301
  /// Returns the number of bytes allocated allocated since the last GC.
1302
  /// TODO: Implement this for heaps other than GenGC
1303
  /// (at which point this can become an abstract function).
1304
0
  virtual gcheapsize_t bytesAllocatedSinceLastGC() const {
1305
0
    return 0;
1306
0
  }
1307
1308
  /// Convenience method to invoke the mark roots function provided at
1309
  /// initialization, using the context provided then (on this heap).
1310
  /// The \p markLongLived argument indicates whether root data structures
1311
  /// containing only pointers to objects allocated via allocLongLived
1312
  /// are required to be marked.  In this collector, such objects will
1313
  /// be allocated in the old gen, and references to them need not be
1314
  /// marked during young-gen collection.
1315
1.96k
  void markRoots(RootAndSlotAcceptorWithNames &acceptor, bool markLongLived) {
1316
1.96k
    gcCallbacks_.markRoots(acceptor, markLongLived);
1317
1.96k
  }
1318
1319
  /// Convenience method to invoke the mark weak roots function provided at
1320
  /// initialization, using the context provided then (on this heap).
1321
1.96k
  void markWeakRoots(WeakRootAcceptor &acceptor, bool markLongLived) {
1322
1.96k
    gcCallbacks_.markWeakRoots(acceptor, markLongLived);
1323
1.96k
    acceptor.beginRootSection(RootAcceptor::Section::WeakRefSlots);
1324
1.32M
    for (auto &slot : weakSlots_) {
1325
1.32M
      slot.markWeakRoots(acceptor);
1326
1.32M
    }
1327
1.96k
    acceptor.endRootSection();
1328
1.96k
  }
1329
1330
  /// Frees the weak slot, so it can be re-used by future WeakRef allocations.
1331
3.00k
  void freeWeakSlot(WeakRefSlot *slot) {
1332
3.00k
    slot->free(firstFreeWeak_);
1333
3.00k
    firstFreeWeak_ = slot;
1334
3.00k
  }
1335
1336
  /// Print the cumulative statistics.
1337
  virtual void printStats(JSONEmitter &json);
1338
1339
  /// Record statistics from a single GC, which are specified in the given
1340
  /// \p event, in the overall cumulative stats struct.
1341
  void recordGCStats(const GCAnalyticsEvent &event, bool onMutator);
1342
1343
  /// Record statistics from a single GC, which are specified in the given
1344
  /// \p event, in the given cumulative stats struct.
1345
  void recordGCStats(
1346
      const GCAnalyticsEvent &event,
1347
      CumulativeHeapStats *stats,
1348
      bool onMutator);
1349
1350
  /// Print detailed stats of the breakdown of the roots and heap in terms of
1351
  /// the number of pointers, symbols, HermesValues, etc.
1352
  void sizeDiagnosticCensus(size_t allocatedBytes);
1353
1354
  /// Do any additional GC-specific logging that is useful before dying with
1355
  /// out-of-memory. Takes a char buffer to avoid dynamic allocations.
1356
  virtual void oomDetail(
1357
      llvh::MutableArrayRef<char> detailBuffer,
1358
      std::error_code reason);
1359
1360
  /// If a cell has any weak references to mark, and the acceptor supports
1361
  /// marking them, mark those weak references.
1362
  template <typename Acceptor>
1363
  void markWeakRefsIfNecessary(GCCell *cell, CellKind kind, Acceptor &acceptor);
1364
1365
  /// Overload of \p markWeakRefsIfNecessary for acceptors that support marking
1366
  /// weak references.
1367
  /// Don't call this directly, use the three-argument variant instead.
1368
  template <typename Acceptor>
1369
  void markWeakRefsIfNecessary(
1370
      GCCell *cell,
1371
      CellKind kind,
1372
      Acceptor &acceptor,
1373
4.51M
      std::true_type) {
1374
    // In C++17, we could implement this via "constexpr if" rather than
1375
    // overloads with std::true_type.
1376
    // Once C++17 is available, switch to using that.
1377
4.51M
    if (auto *cb = VTable::getVTable(kind)->getMarkWeakCallback()) {
1378
883k
      std::lock_guard<Mutex> wrLk{weakRefMutex()};
1379
883k
      cb(cell, acceptor);
1380
883k
    }
1381
4.51M
  }
void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::HadesGC::MarkAcceptor>(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::HadesGC::MarkAcceptor&, std::__1::integral_constant<bool, true>)
Line
Count
Source
1373
734k
      std::true_type) {
1374
    // In C++17, we could implement this via "constexpr if" rather than
1375
    // overloads with std::true_type.
1376
    // Once C++17 is available, switch to using that.
1377
734k
    if (auto *cb = VTable::getVTable(kind)->getMarkWeakCallback()) {
1378
145k
      std::lock_guard<Mutex> wrLk{weakRefMutex()};
1379
145k
      cb(cell, acceptor);
1380
145k
    }
1381
734k
  }
void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::CheckHeapWellFormedAcceptor>(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::CheckHeapWellFormedAcceptor&, std::__1::integral_constant<bool, true>)
Line
Count
Source
1373
3.77M
      std::true_type) {
1374
    // In C++17, we could implement this via "constexpr if" rather than
1375
    // overloads with std::true_type.
1376
    // Once C++17 is available, switch to using that.
1377
3.77M
    if (auto *cb = VTable::getVTable(kind)->getMarkWeakCallback()) {
1378
738k
      std::lock_guard<Mutex> wrLk{weakRefMutex()};
1379
738k
      cb(cell, acceptor);
1380
738k
    }
1381
3.77M
  }
1382
1383
  /// Overload of \p markWeakRefsIfNecessary for acceptors that do not support
1384
  /// marking weak references.
1385
  /// Don't call this directly, use the three-argument variant instead.
1386
  template <typename Acceptor>
1387
  static void markWeakRefsIfNecessary(
1388
      GCCell *,
1389
      CellKind kind,
1390
      Acceptor &,
1391
3.08M
      std::false_type) {}
Unexecuted instantiation: GCBase.cpp:void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::(anonymous namespace)::PrimitiveNodeAcceptor>(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::(anonymous namespace)::PrimitiveNodeAcceptor&, std::__1::integral_constant<bool, false>)
Unexecuted instantiation: GCBase.cpp:void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::(anonymous namespace)::EdgeAddingAcceptor>(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::(anonymous namespace)::EdgeAddingAcceptor&, std::__1::integral_constant<bool, false>)
Unexecuted instantiation: GCBase.cpp:void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::GCBase::sizeDiagnosticCensus(unsigned long)::HeapSizeDiagnosticAcceptor>(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::GCBase::sizeDiagnosticCensus(unsigned long)::HeapSizeDiagnosticAcceptor&, std::__1::integral_constant<bool, false>)
Unexecuted instantiation: void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::HadesGC::EvacAcceptor<true> >(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::HadesGC::EvacAcceptor<true>&, std::__1::integral_constant<bool, false>)
void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::HadesGC::EvacAcceptor<false> >(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::HadesGC::EvacAcceptor<false>&, std::__1::integral_constant<bool, false>)
Line
Count
Source
1391
45.6k
      std::false_type) {}
Unexecuted instantiation: void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::SkipWeakRefsAcceptor<hermes::vm::HadesGC::MarkAcceptor> >(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::SkipWeakRefsAcceptor<hermes::vm::HadesGC::MarkAcceptor>&, std::__1::integral_constant<bool, false>)
HadesGC.cpp:void hermes::vm::GCBase::markWeakRefsIfNecessary<hermes::vm::HadesGC::verifyCardTable()::VerifyCardDirtyAcceptor>(hermes::vm::GCCell*, hermes::vm::CellKind, hermes::vm::HadesGC::verifyCardTable()::VerifyCardDirtyAcceptor&, std::__1::integral_constant<bool, false>)
Line
Count
Source
1391
3.03M
      std::false_type) {}
1392
1393
  template <typename T, class... Args>
1394
647k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
647k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
647k
    constexpr auto kind = T::getCellKind();
1397
647k
    cell->setKindAndSize({kind, size});
1398
647k
    return cell;
1399
647k
  }
Unexecuted instantiation: hermes::vm::BigIntPrimitive* hermes::vm::GCBase::constructCell<hermes::vm::BigIntPrimitive, unsigned int&>(void*, unsigned int, unsigned int&)
hermes::vm::BoxedDouble* hermes::vm::GCBase::constructCell<hermes::vm::BoxedDouble, double&>(void*, unsigned int, double&)
Line
Count
Source
1394
2.76k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
2.76k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
2.76k
    constexpr auto kind = T::getCellKind();
1397
2.76k
    cell->setKindAndSize({kind, size});
1398
2.76k
    return cell;
1399
2.76k
  }
hermes::vm::ArrayStorageBase<hermes::vm::HermesValue32>* hermes::vm::GCBase::constructCell<hermes::vm::ArrayStorageBase<hermes::vm::HermesValue32>>(void*, unsigned int)
Line
Count
Source
1394
58.8k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
58.8k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
58.8k
    constexpr auto kind = T::getCellKind();
1397
58.8k
    cell->setKindAndSize({kind, size});
1398
58.8k
    return cell;
1399
58.8k
  }
hermes::vm::Environment* hermes::vm::GCBase::constructCell<hermes::vm::Environment, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Environment>&, unsigned int&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Environment>&, unsigned int&)
Line
Count
Source
1394
493
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
493
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
493
    constexpr auto kind = T::getCellKind();
1397
493
    cell->setKindAndSize({kind, size});
1398
493
    return cell;
1399
493
  }
hermes::vm::NativeConstructor* hermes::vm::GCBase::constructCell<hermes::vm::NativeConstructor, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs), hermes::vm::CallResult<hermes::vm::PseudoHandle<hermes::vm::JSObject>, (hermes::vm::detail::CallResultSpecialize)6> (*&)(hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, void*), hermes::vm::CellKind&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs), hermes::vm::CallResult<hermes::vm::PseudoHandle<hermes::vm::JSObject>, (hermes::vm::detail::CallResultSpecialize)6> (*&)(hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, void*), hermes::vm::CellKind&)
Line
Count
Source
1394
4.30k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
4.30k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
4.30k
    constexpr auto kind = T::getCellKind();
1397
4.30k
    cell->setKindAndSize({kind, size});
1398
4.30k
    return cell;
1399
4.30k
  }
Unexecuted instantiation: hermes::vm::NativeConstructor* hermes::vm::GCBase::constructCell<hermes::vm::NativeConstructor, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::Environment>&, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs), hermes::vm::CallResult<hermes::vm::PseudoHandle<hermes::vm::JSObject>, (hermes::vm::detail::CallResultSpecialize)6> (*&)(hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, void*), hermes::vm::CellKind&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::Environment>&, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs), hermes::vm::CallResult<hermes::vm::PseudoHandle<hermes::vm::JSObject>, (hermes::vm::detail::CallResultSpecialize)6> (*&)(hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, void*), hermes::vm::CellKind&)
hermes::vm::ArrayStorageBase<hermes::vm::HermesValue>* hermes::vm::GCBase::constructCell<hermes::vm::ArrayStorageBase<hermes::vm::HermesValue>>(void*, unsigned int)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
hermes::vm::BoundFunction* hermes::vm::GCBase::constructCell<hermes::vm::BoundFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::Callable>&, hermes::vm::MutableHandle<hermes::vm::ArrayStorageBase<hermes::vm::HermesValue> >&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::Callable>&, hermes::vm::MutableHandle<hermes::vm::ArrayStorageBase<hermes::vm::HermesValue> >&)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
hermes::vm::NativeFunction* hermes::vm::GCBase::constructCell<hermes::vm::NativeFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs)>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs))
Line
Count
Source
1394
45.2k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
45.2k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
45.2k
    constexpr auto kind = T::getCellKind();
1397
45.2k
    cell->setKindAndSize({kind, size});
1398
45.2k
    return cell;
1399
45.2k
  }
Unexecuted instantiation: hermes::vm::NativeFunction* hermes::vm::GCBase::constructCell<hermes::vm::NativeFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::Environment>&, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs)>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::Environment>&, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs))
hermes::vm::JSFunction* hermes::vm::GCBase::constructCell<hermes::vm::JSFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&)
Line
Count
Source
1394
4.00k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
4.00k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
4.00k
    constexpr auto kind = T::getCellKind();
1397
4.00k
    cell->setKindAndSize({kind, size});
1398
4.00k
    return cell;
1399
4.00k
  }
Unexecuted instantiation: hermes::vm::JSAsyncFunction* hermes::vm::GCBase::constructCell<hermes::vm::JSAsyncFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&)
Unexecuted instantiation: hermes::vm::JSGeneratorFunction* hermes::vm::GCBase::constructCell<hermes::vm::JSGeneratorFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&)
Unexecuted instantiation: hermes::vm::GeneratorInnerFunction* hermes::vm::GCBase::constructCell<hermes::vm::GeneratorInnerFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&, unsigned int>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Domain>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::Environment>&, hermes::vm::CodeBlock*&, unsigned int&&)
hermes::vm::Domain* hermes::vm::GCBase::constructCell<hermes::vm::Domain>(void*, unsigned int)
Line
Count
Source
1394
283
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
283
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
283
    constexpr auto kind = T::getCellKind();
1397
283
    cell->setKindAndSize({kind, size});
1398
283
    return cell;
1399
283
  }
Unexecuted instantiation: hermes::vm::RequireContext* hermes::vm::GCBase::constructCell<hermes::vm::RequireContext, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
hermes::vm::HiddenClass* hermes::vm::GCBase::constructCell<hermes::vm::HiddenClass, hermes::vm::Runtime&, hermes::vm::ClassFlags&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::SymbolID&, hermes::vm::PropertyFlags&, unsigned int&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::ClassFlags&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::SymbolID&, hermes::vm::PropertyFlags&, unsigned int&)
Line
Count
Source
1394
63.0k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
63.0k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
63.0k
    constexpr auto kind = T::getCellKind();
1397
63.0k
    cell->setKindAndSize({kind, size});
1398
63.0k
    return cell;
1399
63.0k
  }
hermes::vm::DynamicStringPrimitive<char, true>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char, true>, unsigned long&>(void*, unsigned int, unsigned long&)
Line
Count
Source
1394
86.3k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
86.3k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
86.3k
    constexpr auto kind = T::getCellKind();
1397
86.3k
    cell->setKindAndSize({kind, size});
1398
86.3k
    return cell;
1399
86.3k
  }
hermes::vm::DynamicStringPrimitive<char16_t, true>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char16_t, true>, unsigned long&>(void*, unsigned int, unsigned long&)
Line
Count
Source
1394
159
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
159
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
159
    constexpr auto kind = T::getCellKind();
1397
159
    cell->setKindAndSize({kind, size});
1398
159
    return cell;
1399
159
  }
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char, false>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char, false>, unsigned long&>(void*, unsigned int, unsigned long&)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char16_t, false>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char16_t, false>, unsigned long&>(void*, unsigned int, unsigned long&)
Unexecuted instantiation: hermes::vm::Arguments* hermes::vm::GCBase::constructCell<hermes::vm::Arguments, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, hermes::vm::Handle<hermes::vm::HiddenClass>&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&&, hermes::vm::Handle<hermes::vm::HiddenClass>&)
hermes::vm::JSArray* hermes::vm::GCBase::constructCell<hermes::vm::JSArray, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::GCPointerBase::NoBarriers>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::GCPointerBase::NoBarriers&&)
Line
Count
Source
1394
14.9k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
14.9k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
14.9k
    constexpr auto kind = T::getCellKind();
1397
14.9k
    cell->setKindAndSize({kind, size});
1398
14.9k
    return cell;
1399
14.9k
  }
Unexecuted instantiation: hermes::vm::JSArrayIterator* hermes::vm::GCBase::constructCell<hermes::vm::JSArrayIterator, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::IterationKind&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::IterationKind&)
Unexecuted instantiation: hermes::vm::JSArrayBuffer* hermes::vm::GCBase::constructCell<hermes::vm::JSArrayBuffer, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSDataView* hermes::vm::GCBase::constructCell<hermes::vm::JSDataView, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSDate* hermes::vm::GCBase::constructCell<hermes::vm::JSDate, hermes::vm::Runtime&, double&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, double&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
hermes::vm::JSError* hermes::vm::GCBase::constructCell<hermes::vm::JSError, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, bool&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, bool&)
Line
Count
Source
1394
32
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
32
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
32
    constexpr auto kind = T::getCellKind();
1397
32
    cell->setKindAndSize({kind, size});
1398
32
    return cell;
1399
32
  }
Unexecuted instantiation: hermes::vm::JSGenerator* hermes::vm::GCBase::constructCell<hermes::vm::JSGenerator, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
hermes::vm::JSObject* hermes::vm::GCBase::constructCell<hermes::vm::JSObject, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::GCPointerBase::NoBarriers>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::GCPointerBase::NoBarriers&&)
Line
Count
Source
1394
6.24k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
6.24k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
6.24k
    constexpr auto kind = T::getCellKind();
1397
6.24k
    cell->setKindAndSize({kind, size});
1398
6.24k
    return cell;
1399
6.24k
  }
Unexecuted instantiation: hermes::vm::JSProxy* hermes::vm::GCBase::constructCell<hermes::vm::JSProxy, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
hermes::vm::JSRegExp* hermes::vm::GCBase::constructCell<hermes::vm::JSRegExp, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Line
Count
Source
1394
77
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
77
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
77
    constexpr auto kind = T::getCellKind();
1397
77
    cell->setKindAndSize({kind, size});
1398
77
    return cell;
1399
77
  }
Unexecuted instantiation: hermes::vm::JSMapImpl<(hermes::vm::CellKind)47>* hermes::vm::GCBase::constructCell<hermes::vm::JSMapImpl<(hermes::vm::CellKind)47>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSMapImpl<(hermes::vm::CellKind)48>* hermes::vm::GCBase::constructCell<hermes::vm::JSMapImpl<(hermes::vm::CellKind)48>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSMapIteratorImpl<(hermes::vm::CellKind)50>* hermes::vm::GCBase::constructCell<hermes::vm::JSMapIteratorImpl<(hermes::vm::CellKind)50>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSMapIteratorImpl<(hermes::vm::CellKind)49>* hermes::vm::GCBase::constructCell<hermes::vm::JSMapIteratorImpl<(hermes::vm::CellKind)49>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<signed char, (hermes::vm::CellKind)35>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<signed char, (hermes::vm::CellKind)35>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<short, (hermes::vm::CellKind)36>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<short, (hermes::vm::CellKind)36>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<int, (hermes::vm::CellKind)37>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<int, (hermes::vm::CellKind)37>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<unsigned char, (hermes::vm::CellKind)38>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<unsigned char, (hermes::vm::CellKind)38>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<unsigned char, (hermes::vm::CellKind)39>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<unsigned char, (hermes::vm::CellKind)39>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<unsigned short, (hermes::vm::CellKind)40>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<unsigned short, (hermes::vm::CellKind)40>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<unsigned int, (hermes::vm::CellKind)41>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<unsigned int, (hermes::vm::CellKind)41>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<float, (hermes::vm::CellKind)42>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<float, (hermes::vm::CellKind)42>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<double, (hermes::vm::CellKind)43>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<double, (hermes::vm::CellKind)43>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<long, (hermes::vm::CellKind)44>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<long, (hermes::vm::CellKind)44>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSTypedArray<unsigned long, (hermes::vm::CellKind)45>* hermes::vm::GCBase::constructCell<hermes::vm::JSTypedArray<unsigned long, (hermes::vm::CellKind)45>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSWeakMapImpl<(hermes::vm::CellKind)51>* hermes::vm::GCBase::constructCell<hermes::vm::JSWeakMapImpl<(hermes::vm::CellKind)51>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue> >&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue> >&)
Unexecuted instantiation: hermes::vm::JSWeakMapImpl<(hermes::vm::CellKind)52>* hermes::vm::GCBase::constructCell<hermes::vm::JSWeakMapImpl<(hermes::vm::CellKind)52>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue> >&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue> >&)
Unexecuted instantiation: hermes::vm::JSWeakRef* hermes::vm::GCBase::constructCell<hermes::vm::JSWeakRef, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::DecoratedObject* hermes::vm::GCBase::constructCell<hermes::vm::DecoratedObject, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, std::__1::unique_ptr<hermes::vm::DecoratedObject::Decoration, std::__1::default_delete<hermes::vm::DecoratedObject::Decoration> > >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, std::__1::unique_ptr<hermes::vm::DecoratedObject::Decoration, std::__1::default_delete<hermes::vm::DecoratedObject::Decoration> >&&)
Unexecuted instantiation: hermes::vm::FinalizableNativeFunction* hermes::vm::GCBase::constructCell<hermes::vm::FinalizableNativeFunction, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs), void (*&)(void*)>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, void*&, hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> (*&)(void*, hermes::vm::Runtime&, hermes::vm::NativeArgs), void (*&)(void*))
hermes::vm::HostObject* hermes::vm::GCBase::constructCell<hermes::vm::HostObject, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, std::__1::unique_ptr<hermes::vm::HostObjectProxy, std::__1::default_delete<hermes::vm::HostObjectProxy> > >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, std::__1::unique_ptr<hermes::vm::HostObjectProxy, std::__1::default_delete<hermes::vm::HostObjectProxy> >&&)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
Unexecuted instantiation: hermes::vm::NativeState* hermes::vm::GCBase::constructCell<hermes::vm::NativeState, void*&, void (*&)(void*)>(void*, unsigned int, void*&, void (*&)(void*))
hermes::vm::JSString* hermes::vm::GCBase::constructCell<hermes::vm::JSString, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::StringPrimitive>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::StringPrimitive>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
Unexecuted instantiation: hermes::vm::JSStringIterator* hermes::vm::GCBase::constructCell<hermes::vm::JSStringIterator, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::Handle<hermes::vm::StringPrimitive>&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&, hermes::vm::Handle<hermes::vm::StringPrimitive>&)
Unexecuted instantiation: hermes::vm::JSBigInt* hermes::vm::GCBase::constructCell<hermes::vm::JSBigInt, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::BigIntPrimitive>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::BigIntPrimitive>&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&)
hermes::vm::JSNumber* hermes::vm::GCBase::constructCell<hermes::vm::JSNumber, hermes::vm::Runtime&, double&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&>(void*, unsigned int, hermes::vm::Runtime&, double&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&)
Line
Count
Source
1394
108
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
108
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
108
    constexpr auto kind = T::getCellKind();
1397
108
    cell->setKindAndSize({kind, size});
1398
108
    return cell;
1399
108
  }
hermes::vm::JSBoolean* hermes::vm::GCBase::constructCell<hermes::vm::JSBoolean, hermes::vm::Runtime&, bool&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&>(void*, unsigned int, hermes::vm::Runtime&, bool&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
Unexecuted instantiation: hermes::vm::JSSymbol* hermes::vm::GCBase::constructCell<hermes::vm::JSSymbol, hermes::vm::Runtime&, hermes::vm::SymbolID&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::SymbolID&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&)
hermes::vm::PropertyAccessor* hermes::vm::GCBase::constructCell<hermes::vm::PropertyAccessor, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Callable>&, hermes::vm::Handle<hermes::vm::Callable>&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::Callable>&, hermes::vm::Handle<hermes::vm::Callable>&)
Line
Count
Source
1394
4.64k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
4.64k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
4.64k
    constexpr auto kind = T::getCellKind();
1397
4.64k
    cell->setKindAndSize({kind, size});
1398
4.64k
    return cell;
1399
4.64k
  }
hermes::vm::FillerCell* hermes::vm::GCBase::constructCell<hermes::vm::FillerCell>(void*, unsigned int)
Line
Count
Source
1394
274
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
274
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
274
    constexpr auto kind = T::getCellKind();
1397
274
    cell->setKindAndSize({kind, size});
1398
274
    return cell;
1399
274
  }
Unexecuted instantiation: hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue>::Segment* hermes::vm::GCBase::constructCell<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue>::Segment>(void*, unsigned int)
hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue>* hermes::vm::GCBase::constructCell<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue>>(void*, unsigned int)
Line
Count
Source
1394
1
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
1
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
1
    constexpr auto kind = T::getCellKind();
1397
1
    cell->setKindAndSize({kind, size});
1398
1
    return cell;
1399
1
  }
hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue32>::Segment* hermes::vm::GCBase::constructCell<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue32>::Segment>(void*, unsigned int)
Line
Count
Source
1394
868
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
868
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
868
    constexpr auto kind = T::getCellKind();
1397
868
    cell->setKindAndSize({kind, size});
1398
868
    return cell;
1399
868
  }
hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue32>* hermes::vm::GCBase::constructCell<hermes::vm::SegmentedArrayBase<hermes::vm::HermesValue32>>(void*, unsigned int)
Line
Count
Source
1394
2.49k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
2.49k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
2.49k
    constexpr auto kind = T::getCellKind();
1397
2.49k
    cell->setKindAndSize({kind, size});
1398
2.49k
    return cell;
1399
2.49k
  }
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char16_t, true>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char16_t, true>, llvh::ArrayRef<char16_t>&>(void*, unsigned int, llvh::ArrayRef<char16_t>&)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char16_t, true>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char16_t, true>, unsigned int&>(void*, unsigned int, unsigned int&)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char, true>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char, true>, llvh::ArrayRef<char>&>(void*, unsigned int, llvh::ArrayRef<char>&)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char, true>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char, true>, unsigned int&>(void*, unsigned int, unsigned int&)
hermes::vm::DynamicStringPrimitive<char16_t, false>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char16_t, false>, llvh::ArrayRef<char16_t>&>(void*, unsigned int, llvh::ArrayRef<char16_t>&)
Line
Count
Source
1394
13.4k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
13.4k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
13.4k
    constexpr auto kind = T::getCellKind();
1397
13.4k
    cell->setKindAndSize({kind, size});
1398
13.4k
    return cell;
1399
13.4k
  }
hermes::vm::DynamicStringPrimitive<char16_t, false>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char16_t, false>, unsigned int&>(void*, unsigned int, unsigned int&)
Line
Count
Source
1394
31.8k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
31.8k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
31.8k
    constexpr auto kind = T::getCellKind();
1397
31.8k
    cell->setKindAndSize({kind, size});
1398
31.8k
    return cell;
1399
31.8k
  }
hermes::vm::DynamicStringPrimitive<char, false>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char, false>, llvh::ArrayRef<char>&>(void*, unsigned int, llvh::ArrayRef<char>&)
Line
Count
Source
1394
224k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
224k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
224k
    constexpr auto kind = T::getCellKind();
1397
224k
    cell->setKindAndSize({kind, size});
1398
224k
    return cell;
1399
224k
  }
hermes::vm::DynamicStringPrimitive<char, false>* hermes::vm::GCBase::constructCell<hermes::vm::DynamicStringPrimitive<char, false>, unsigned int&>(void*, unsigned int, unsigned int&)
Line
Count
Source
1394
516
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
516
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
516
    constexpr auto kind = T::getCellKind();
1397
516
    cell->setKindAndSize({kind, size});
1398
516
    return cell;
1399
516
  }
hermes::vm::ExternalStringPrimitive<char16_t>* hermes::vm::GCBase::constructCell<hermes::vm::ExternalStringPrimitive<char16_t>, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> > >(void*, unsigned int, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >&&)
Line
Count
Source
1394
109
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
109
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
109
    constexpr auto kind = T::getCellKind();
1397
109
    cell->setKindAndSize({kind, size});
1398
109
    return cell;
1399
109
  }
hermes::vm::ExternalStringPrimitive<char>* hermes::vm::GCBase::constructCell<hermes::vm::ExternalStringPrimitive<char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(void*, unsigned int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
Line
Count
Source
1394
9
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
9
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
9
    constexpr auto kind = T::getCellKind();
1397
9
    cell->setKindAndSize({kind, size});
1398
9
    return cell;
1399
9
  }
hermes::vm::BufferedStringPrimitive<char16_t>* hermes::vm::GCBase::constructCell<hermes::vm::BufferedStringPrimitive<char16_t>, hermes::vm::Runtime&, unsigned int&, hermes::vm::Handle<hermes::vm::ExternalStringPrimitive<char16_t> >&>(void*, unsigned int, hermes::vm::Runtime&, unsigned int&, hermes::vm::Handle<hermes::vm::ExternalStringPrimitive<char16_t> >&)
Line
Count
Source
1394
64
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
64
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
64
    constexpr auto kind = T::getCellKind();
1397
64
    cell->setKindAndSize({kind, size});
1398
64
    return cell;
1399
64
  }
hermes::vm::BufferedStringPrimitive<char>* hermes::vm::GCBase::constructCell<hermes::vm::BufferedStringPrimitive<char>, hermes::vm::Runtime&, unsigned int&, hermes::vm::Handle<hermes::vm::ExternalStringPrimitive<char> >&>(void*, unsigned int, hermes::vm::Runtime&, unsigned int&, hermes::vm::Handle<hermes::vm::ExternalStringPrimitive<char> >&)
Line
Count
Source
1394
30.3k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
30.3k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
30.3k
    constexpr auto kind = T::getCellKind();
1397
30.3k
    cell->setKindAndSize({kind, size});
1398
30.3k
    return cell;
1399
30.3k
  }
hermes::vm::SingleObject<(hermes::vm::CellKind)60>* hermes::vm::GCBase::constructCell<hermes::vm::SingleObject<(hermes::vm::CellKind)60>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
hermes::vm::SingleObject<(hermes::vm::CellKind)59>* hermes::vm::GCBase::constructCell<hermes::vm::SingleObject<(hermes::vm::CellKind)59>, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
hermes::vm::HadesGC::OldGen::FreelistCell* hermes::vm::GCBase::constructCell<hermes::vm::HadesGC::OldGen::FreelistCell>(void*, unsigned int)
Line
Count
Source
1394
27.1k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
27.1k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
27.1k
    constexpr auto kind = T::getCellKind();
1397
27.1k
    cell->setKindAndSize({kind, size});
1398
27.1k
    return cell;
1399
27.1k
  }
hermes::vm::DictPropertyMap* hermes::vm::GCBase::constructCell<hermes::vm::DictPropertyMap, unsigned int&, unsigned int&>(void*, unsigned int, unsigned int&, unsigned int&)
Line
Count
Source
1394
23.8k
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
23.8k
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
23.8k
    constexpr auto kind = T::getCellKind();
1397
23.8k
    cell->setKindAndSize({kind, size});
1398
23.8k
    return cell;
1399
23.8k
  }
Unexecuted instantiation: hermes::vm::testhelpers::DummyObject* hermes::vm::GCBase::constructCell<hermes::vm::testhelpers::DummyObject, hermes::vm::HadesGC&>(void*, unsigned int, hermes::vm::HadesGC&)
Unexecuted instantiation: hermes::vm::HashMapEntry* hermes::vm::GCBase::constructCell<hermes::vm::HashMapEntry>(void*, unsigned int)
hermes::vm::OrderedHashMap* hermes::vm::GCBase::constructCell<hermes::vm::OrderedHashMap, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::ArrayStorageBase<hermes::vm::HermesValue32> >&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::ArrayStorageBase<hermes::vm::HermesValue32> >&)
Line
Count
Source
1394
105
  static T *constructCell(void *ptr, uint32_t size, Args &&...args) {
1395
105
    auto *cell = new (ptr) T(std::forward<Args>(args)...);
1396
105
    constexpr auto kind = T::getCellKind();
1397
105
    cell->setKindAndSize({kind, size});
1398
105
    return cell;
1399
105
  }
Unexecuted instantiation: hermes::vm::JSCallSite* hermes::vm::GCBase::constructCell<hermes::vm::JSCallSite, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::JSError>&, unsigned int&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::JSError>&, unsigned int&)
Unexecuted instantiation: hermes::vm::JSCallableProxy* hermes::vm::GCBase::constructCell<hermes::vm::JSCallableProxy, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>, hermes::vm::Handle<hermes::vm::HiddenClass> >(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&&, hermes::vm::Handle<hermes::vm::HiddenClass>&&)
Unexecuted instantiation: hermes::vm::JSRegExpStringIterator* hermes::vm::GCBase::constructCell<hermes::vm::JSRegExpStringIterator, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::StringPrimitive>&, bool&, bool&>(void*, unsigned int, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::HiddenClass>&&, hermes::vm::Handle<hermes::vm::JSObject>&, hermes::vm::Handle<hermes::vm::StringPrimitive>&, bool&, bool&)
1400
1401
  /// Number of finalized objects in the last collection.
1402
  unsigned numFinalizedObjects_{0};
1403
1404
  /// The total number of bytes allocated in the execution.
1405
  uint64_t totalAllocatedBytes_{0};
1406
1407
  /// A trace of GC execution.
1408
  GCExecTrace execTrace_;
1409
1410
/// These fields are not available in optimized builds.
1411
#ifndef NDEBUG
1412
  /// Number of currently allocated objects present in the heap before the start
1413
  /// of the last collection.  Some may be unreachable.
1414
  unsigned numAllocatedObjects_{0};
1415
  /// Number of reachable objects in the last collection.  (More properly, this
1416
  /// is the number not known to be unreachable: if a GC does not consider
1417
  /// determine the reachability of some subset of objects, for example, an old
1418
  /// generation in a generational collection, those objects should be included
1419
  /// in this count.)
1420
  unsigned numReachableObjects_{0};
1421
  /// Number of collected objects in the last collection.  Equal to
1422
  /// numAllocatedObjects_ (at the start of the last collection),
1423
  /// minus numReachableObjects_ found in that collection.
1424
  unsigned numCollectedObjects_{0};
1425
  /// Number of marked symbols.
1426
  unsigned numMarkedSymbols_{0};
1427
  /// Number of hidden classes alive after the last collection.
1428
  unsigned numHiddenClasses_{0};
1429
  /// Number of "leaf" hidden classes alive after the last collection.
1430
  unsigned numLeafHiddenClasses_{0};
1431
1432
  /// Associate a semi-unique (until it overflows) id with every allocation
1433
  /// for easier identification when debugging.
1434
  uint64_t debugAllocationCounter_{0};
1435
#endif
1436
1437
  /// User-supplied callbacks invoked by the GC to query information or perform
1438
  /// tasks.
1439
  GCCallbacks &gcCallbacks_;
1440
1441
  /// Base of all pointers in compressed pointers implementation.
1442
  PointerBase &pointerBase_;
1443
1444
  /// A place to log crash data if a crash is about to occur.
1445
  std::shared_ptr<CrashManager> crashMgr_;
1446
1447
  HeapKind heapKind_;
1448
1449
  /// Callback called once for each GC event that wants to be logged. Can be
1450
  /// null if no analytics are requested.
1451
  std::function<void(const GCAnalyticsEvent &)> analyticsCallback_;
1452
1453
  /// Capture all analytics events to print stats at the end.
1454
  std::vector<GCAnalyticsEvent> analyticsEvents_;
1455
1456
  /// Whether to output GC statistics at the end of execution.
1457
  bool recordGcStats_{false};
1458
1459
  /// Whether or not a GC cycle is currently occurring.
1460
  bool inGC_{false};
1461
1462
  /// Whether the GC has OOMed. Currently only useful for understanding crash
1463
  /// dumps, particularly when HERMESVM_EXCEPTION_ON_OOM is set.
1464
  bool hasOOMed_{false};
1465
1466
  /// The block of fields below records values of various metrics at
1467
  /// the start of execution, so that we can get the values at the end
1468
  /// and subtract.  The "runtimeWillExecute" method is called at
1469
  /// first bytecode execution, but also when executing the bodies of
1470
  /// other bundles.  We want to record these at the first such call.
1471
  /// This field tells whether these values have been recorded yet.
1472
  bool execStartTimeRecorded_{false};
1473
1474
  /// Time at which execution of the Hermes VM began.
1475
  std::chrono::time_point<std::chrono::steady_clock> execStartTime_;
1476
  std::chrono::microseconds execStartCPUTime_;
1477
  /// Number of context switches before execution of the Hermes VM began.
1478
  long startNumVoluntaryContextSwitches_{0};
1479
  long startNumInvoluntaryContextSwitches_{0};
1480
1481
  // The cumulative GC stats.
1482
  CumulativeHeapStats cumStats_;
1483
1484
  /// Name to identify this heap in logs.
1485
  std::string name_;
1486
1487
  /// weakSlots_ is a list of all the weak pointers in the system. They are
1488
  /// invalidated if they point to an object that is dead, and do not count
1489
  /// towards whether an object is live or dead.
1490
  /// The state enum of a WeakRefSlot that is not free may be modified
1491
  /// concurrently, those values are protected by the weakRefMutex_.
1492
  std::deque<WeakRefSlot> weakSlots_;
1493
1494
  /// Pointer to the first free weak reference slot. Free weak refs are chained
1495
  /// together in a linked list.
1496
  WeakRefSlot *firstFreeWeak_{nullptr};
1497
1498
  /// Any thread that modifies a WeakRefSlot or a data structure containing
1499
  /// WeakRefs that the GC will mark must hold this mutex. The GC will hold this
1500
  /// mutex while scanning any weak references.
1501
  WeakRefMutex weakRefMutex_;
1502
1503
  /// Tracks what objects need a stable identity for features such as heap
1504
  /// snapshots and the memory profiler.
1505
  IDTracker idTracker_;
1506
1507
#ifdef HERMES_MEMORY_INSTRUMENTATION
1508
  /// Attaches stack-traces to objects when enabled.
1509
  AllocationLocationTracker allocationLocationTracker_;
1510
1511
  /// Attaches stack-traces to objects when enabled.
1512
  SamplingAllocationLocationTracker samplingAllocationTracker_;
1513
#endif
1514
1515
#ifndef NDEBUG
1516
  /// The number of reasons why no allocation is allowed in this heap right
1517
  /// now.
1518
  uint32_t noAllocLevel_{0};
1519
1520
  friend class NoAllocScope;
1521
#endif
1522
1523
#ifdef HERMESVM_SANITIZE_HANDLES
1524
  /// \return true if we should run handle sanitization and the coin flip with
1525
  /// probability sanitizeRate_ has passed.
1526
  bool shouldSanitizeHandles();
1527
1528
  /// Whether to keep moving the heap around to detect unsanitary GC handles.
1529
  double sanitizeRate_{1.0};
1530
1531
  /// PRNG for sanitizing at a less than 1.0 rate.
1532
  std::minstd_rand randomEngine_;
1533
#else
1534
  /// Sanitize handles is completely disabled (and ignored at runtime) without
1535
  /// a special build mode.
1536
  static constexpr double sanitizeRate_{0.0};
1537
1538
0
  static constexpr bool shouldSanitizeHandles() {
1539
0
    return false;
1540
0
  }
1541
#endif
1542
1543
 private:
1544
#ifdef HERMESVM_GC_RUNTIME
1545
  /// Use the kind tag of the GC to statically call a function with one of the
1546
  /// available runtime GCs.
1547
  template <typename Func>
1548
  auto runtimeGCDispatch(Func f) {
1549
    switch (getKind()) {
1550
#define GC_KIND(kind)          \
1551
  case GCBase::HeapKind::kind: \
1552
    return f(llvh::cast<kind>(this));
1553
      RUNTIME_GC_KINDS
1554
#undef GC_KIND
1555
      default:
1556
        llvm_unreachable("No other valid GC for RuntimeGC");
1557
    }
1558
  }
1559
#endif
1560
1561
  template <typename T, XorPtrKeyID K>
1562
  friend class XorPtr;
1563
1564
  /// Randomly generated key used to obfuscate pointers in XorPtr.
1565
  uintptr_t pointerEncryptionKey_[XorPtrKeyID::_NumKeys];
1566
1567
  /// Callback called if it's not null when the Live Data Tripwire is
1568
  /// triggered.
1569
  std::function<void(GCTripwireContext &)> tripwireCallback_;
1570
1571
  /// Maximum size limit before the heap size tripwire will trigger.
1572
  gcheapsize_t tripwireLimit_;
1573
1574
  /// True if the tripwire has already been called on this heap.
1575
  bool tripwireCalled_{false};
1576
};
1577
1578
// Utilities for formatting time durations and memory sizes.
1579
1580
/// An object that, written to an ostream, formats the given # of
1581
/// secs in appropriate units (down to microseconds).
1582
struct DurationFormatObj {
1583
  double secs;
1584
};
1585
llvh::raw_ostream &operator<<(
1586
    llvh::raw_ostream &os,
1587
    const DurationFormatObj &dfo);
1588
0
inline DurationFormatObj formatSecs(double secs) {
1589
0
  return {secs};
1590
0
}
1591
1592
/// An object that, written to an ostream, formats the given # of
1593
/// bytes in appropriate units (bytes to GiB).
1594
struct SizeFormatObj {
1595
  uint64_t bytes;
1596
};
1597
llvh::raw_ostream &operator<<(llvh::raw_ostream &os, const SizeFormatObj &sfo);
1598
0
inline SizeFormatObj formatSize(uint64_t size) {
1599
0
  return {size};
1600
0
}
1601
1602
} // namespace vm
1603
} // namespace hermes
1604
#pragma GCC diagnostic pop
1605
1606
#endif // HERMES_VM_GCBASE_H