1// Copyright 2010 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_V8_PROFILER_H_
6#define V8_V8_PROFILER_H_
7
8#include <limits.h>
9
10#include <memory>
11#include <unordered_set>
12#include <vector>
13
14#include "v8-local-handle.h"       // NOLINT(build/include_directory)
15#include "v8-message.h"            // NOLINT(build/include_directory)
16#include "v8-persistent-handle.h"  // NOLINT(build/include_directory)
17
18/**
19 * Profiler support for the V8 JavaScript engine.
20 */
21namespace v8 {
22
23enum class EmbedderStateTag : uint8_t;
24class HeapGraphNode;
25struct HeapStatsUpdate;
26class Object;
27enum StateTag : uint16_t;
28
29using NativeObject = void*;
30using SnapshotObjectId = uint32_t;
31using ProfilerId = uint32_t;
32
33struct CpuProfileDeoptFrame {
34  int script_id;
35  size_t position;
36};
37
38namespace internal {
39class CpuProfile;
40}  // namespace internal
41
42}  // namespace v8
43
44#ifdef V8_OS_WIN
45template class V8_EXPORT std::vector<v8::CpuProfileDeoptFrame>;
46#endif
47
48namespace v8 {
49
50struct V8_EXPORT CpuProfileDeoptInfo {
51  /** A pointer to a static string owned by v8. */
52  const char* deopt_reason;
53  std::vector<CpuProfileDeoptFrame> stack;
54};
55
56}  // namespace v8
57
58#ifdef V8_OS_WIN
59template class V8_EXPORT std::vector<v8::CpuProfileDeoptInfo>;
60#endif
61
62namespace v8 {
63
64/**
65 * CpuProfileNode represents a node in a call graph.
66 */
67class V8_EXPORT CpuProfileNode {
68 public:
69  struct LineTick {
70    /** The 1-based number of the source line where the function originates. */
71    int line;
72
73    /** The count of samples associated with the source line. */
74    unsigned int hit_count;
75  };
76
77  // An annotation hinting at the source of a CpuProfileNode.
78  enum SourceType {
79    // User-supplied script with associated resource information.
80    kScript = 0,
81    // Native scripts and provided builtins.
82    kBuiltin = 1,
83    // Callbacks into native code.
84    kCallback = 2,
85    // VM-internal functions or state.
86    kInternal = 3,
87    // A node that failed to symbolize.
88    kUnresolved = 4,
89  };
90
91  /** Returns function name (empty string for anonymous functions.) */
92  Local<String> GetFunctionName() const;
93
94  /**
95   * Returns function name (empty string for anonymous functions.)
96   * The string ownership is *not* passed to the caller. It stays valid until
97   * profile is deleted. The function is thread safe.
98   */
99  const char* GetFunctionNameStr() const;
100
101  /** Returns id of the script where function is located. */
102  int GetScriptId() const;
103
104  /** Returns resource name for script from where the function originates. */
105  Local<String> GetScriptResourceName() const;
106
107  /**
108   * Returns resource name for script from where the function originates.
109   * The string ownership is *not* passed to the caller. It stays valid until
110   * profile is deleted. The function is thread safe.
111   */
112  const char* GetScriptResourceNameStr() const;
113
114  /**
115   * Return true if the script from where the function originates is flagged as
116   * being shared cross-origin.
117   */
118  bool IsScriptSharedCrossOrigin() const;
119
120  /**
121   * Returns the number, 1-based, of the line where the function originates.
122   * kNoLineNumberInfo if no line number information is available.
123   */
124  int GetLineNumber() const;
125
126  /**
127   * Returns 1-based number of the column where the function originates.
128   * kNoColumnNumberInfo if no column number information is available.
129   */
130  int GetColumnNumber() const;
131
132  /**
133   * Returns the number of the function's source lines that collect the samples.
134   */
135  unsigned int GetHitLineCount() const;
136
137  /** Returns the set of source lines that collect the samples.
138   *  The caller allocates buffer and responsible for releasing it.
139   *  True if all available entries are copied, otherwise false.
140   *  The function copies nothing if buffer is not large enough.
141   */
142  bool GetLineTicks(LineTick* entries, unsigned int length) const;
143
144  /** Returns bailout reason for the function
145    * if the optimization was disabled for it.
146    */
147  const char* GetBailoutReason() const;
148
149  /**
150    * Returns the count of samples where the function was currently executing.
151    */
152  unsigned GetHitCount() const;
153
154  /** Returns id of the node. The id is unique within the tree */
155  unsigned GetNodeId() const;
156
157  /**
158   * Gets the type of the source which the node was captured from.
159   */
160  SourceType GetSourceType() const;
161
162  /** Returns child nodes count of the node. */
163  int GetChildrenCount() const;
164
165  /** Retrieves a child node by index. */
166  const CpuProfileNode* GetChild(int index) const;
167
168  /** Retrieves the ancestor node, or null if the root. */
169  const CpuProfileNode* GetParent() const;
170
171  /** Retrieves deopt infos for the node. */
172  const std::vector<CpuProfileDeoptInfo>& GetDeoptInfos() const;
173
174  static const int kNoLineNumberInfo = Message::kNoLineNumberInfo;
175  static const int kNoColumnNumberInfo = Message::kNoColumnInfo;
176};
177
178/**
179 * An interface for exporting data from V8, using "push" model.
180 */
181class V8_EXPORT OutputStream {
182 public:
183  enum WriteResult { kContinue = 0, kAbort = 1 };
184  virtual ~OutputStream() = default;
185  /** Notify about the end of stream. */
186  virtual void EndOfStream() = 0;
187  /** Get preferred output chunk size. Called only once. */
188  virtual int GetChunkSize() { return 1024; }
189  /**
190   * Writes the next chunk of snapshot data into the stream. Writing
191   * can be stopped by returning kAbort as function result. EndOfStream
192   * will not be called in case writing was aborted.
193   */
194  virtual WriteResult WriteAsciiChunk(char* data, int size) = 0;
195  /**
196   * Writes the next chunk of heap stats data into the stream. Writing
197   * can be stopped by returning kAbort as function result. EndOfStream
198   * will not be called in case writing was aborted.
199   */
200  virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate* data, int count) {
201    return kAbort;
202  }
203};
204
205/**
206 * CpuProfile contains a CPU profile in a form of top-down call tree
207 * (from main() down to functions that do all the work).
208 */
209class V8_EXPORT CpuProfile {
210 public:
211  enum SerializationFormat {
212    kJSON = 0  // See format description near 'Serialize' method.
213  };
214  /** Returns CPU profile title. */
215  Local<String> GetTitle() const;
216
217  /** Returns the root node of the top down call tree. */
218  const CpuProfileNode* GetTopDownRoot() const;
219
220  /**
221   * Returns number of samples recorded. The samples are not recorded unless
222   * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true.
223   */
224  int GetSamplesCount() const;
225
226  /**
227   * Returns profile node corresponding to the top frame the sample at
228   * the given index.
229   */
230  const CpuProfileNode* GetSample(int index) const;
231
232  /**
233   * Returns the timestamp of the sample. The timestamp is the number of
234   * microseconds since some unspecified starting point.
235   * The point is equal to the starting point used by GetStartTime.
236   */
237  int64_t GetSampleTimestamp(int index) const;
238
239  /**
240   * Returns time when the profile recording was started (in microseconds)
241   * since some unspecified starting point.
242   */
243  int64_t GetStartTime() const;
244
245  /**
246   * Returns state of the vm when sample was captured.
247   */
248  StateTag GetSampleState(int index) const;
249
250  /**
251   * Returns state of the embedder when sample was captured.
252   */
253  EmbedderStateTag GetSampleEmbedderState(int index) const;
254
255  /**
256   * Returns time when the profile recording was stopped (in microseconds)
257   * since some unspecified starting point.
258   * The point is equal to the starting point used by GetStartTime.
259   */
260  int64_t GetEndTime() const;
261
262  /**
263   * Deletes the profile and removes it from CpuProfiler's list.
264   * All pointers to nodes previously returned become invalid.
265   */
266  void Delete();
267
268  /**
269   * Prepare a serialized representation of the profile. The result
270   * is written into the stream provided in chunks of specified size.
271   *
272   * For the JSON format, heap contents are represented as an object
273   * with the following structure:
274   *
275   *  {
276   *    nodes: [nodes array],
277   *    startTime: number,
278   *    endTime: number
279   *    samples: [strings array]
280   *    timeDeltas: [numbers array]
281   *  }
282   *
283   */
284  void Serialize(OutputStream* stream,
285                 SerializationFormat format = kJSON) const;
286};
287
288enum CpuProfilingMode {
289  // In the resulting CpuProfile tree, intermediate nodes in a stack trace
290  // (from the root to a leaf) will have line numbers that point to the start
291  // line of the function, rather than the line of the callsite of the child.
292  kLeafNodeLineNumbers,
293  // In the resulting CpuProfile tree, nodes are separated based on the line
294  // number of their callsite in their parent.
295  kCallerLineNumbers,
296};
297
298// Determines how names are derived for functions sampled.
299enum CpuProfilingNamingMode {
300  // Use the immediate name of functions at compilation time.
301  kStandardNaming,
302  // Use more verbose naming for functions without names, inferred from scope
303  // where possible.
304  kDebugNaming,
305};
306
307enum CpuProfilingLoggingMode {
308  // Enables logging when a profile is active, and disables logging when all
309  // profiles are detached.
310  kLazyLogging,
311  // Enables logging for the lifetime of the CpuProfiler. Calls to
312  // StartRecording are faster, at the expense of runtime overhead.
313  kEagerLogging,
314};
315
316// Enum for returning profiling status. Once StartProfiling is called,
317// we want to return to clients whether the profiling was able to start
318// correctly, or return a descriptive error.
319enum class CpuProfilingStatus {
320  kStarted,
321  kAlreadyStarted,
322  kErrorTooManyProfilers
323};
324
325/**
326 * Result from StartProfiling returning the Profiling Status, and
327 * id of the started profiler, or 0 if profiler is not started
328 */
329struct CpuProfilingResult {
330  const ProfilerId id;
331  const CpuProfilingStatus status;
332};
333
334/**
335 * Delegate for when max samples reached and samples are discarded.
336 */
337class V8_EXPORT DiscardedSamplesDelegate {
338 public:
339  DiscardedSamplesDelegate() = default;
340
341  virtual ~DiscardedSamplesDelegate() = default;
342  virtual void Notify() = 0;
343
344  ProfilerId GetId() const { return profiler_id_; }
345
346 private:
347  friend internal::CpuProfile;
348
349  void SetId(ProfilerId id) { profiler_id_ = id; }
350
351  ProfilerId profiler_id_;
352};
353
354/**
355 * Optional profiling attributes.
356 */
357class V8_EXPORT CpuProfilingOptions {
358 public:
359  // Indicates that the sample buffer size should not be explicitly limited.
360  static const unsigned kNoSampleLimit = UINT_MAX;
361
362  /**
363   * \param mode Type of computation of stack frame line numbers.
364   * \param max_samples The maximum number of samples that should be recorded by
365   *                    the profiler. Samples obtained after this limit will be
366   *                    discarded.
367   * \param sampling_interval_us controls the profile-specific target
368   *                             sampling interval. The provided sampling
369   *                             interval will be snapped to the next lowest
370   *                             non-zero multiple of the profiler's sampling
371   *                             interval, set via SetSamplingInterval(). If
372   *                             zero, the sampling interval will be equal to
373   *                             the profiler's sampling interval.
374   * \param filter_context If specified, profiles will only contain frames
375   *                       using this context. Other frames will be elided.
376   */
377  CpuProfilingOptions(
378      CpuProfilingMode mode = kLeafNodeLineNumbers,
379      unsigned max_samples = kNoSampleLimit, int sampling_interval_us = 0,
380      MaybeLocal<Context> filter_context = MaybeLocal<Context>());
381
382  CpuProfilingOptions(CpuProfilingOptions&&) = default;
383  CpuProfilingOptions& operator=(CpuProfilingOptions&&) = default;
384
385  CpuProfilingMode mode() const { return mode_; }
386  unsigned max_samples() const { return max_samples_; }
387  int sampling_interval_us() const { return sampling_interval_us_; }
388
389 private:
390  friend class internal::CpuProfile;
391
392  bool has_filter_context() const { return !filter_context_.IsEmpty(); }
393  void* raw_filter_context() const;
394
395  CpuProfilingMode mode_;
396  unsigned max_samples_;
397  int sampling_interval_us_;
398  Global<Context> filter_context_;
399};
400
401/**
402 * Interface for controlling CPU profiling. Instance of the
403 * profiler can be created using v8::CpuProfiler::New method.
404 */
405class V8_EXPORT CpuProfiler {
406 public:
407  /**
408   * Creates a new CPU profiler for the |isolate|. The isolate must be
409   * initialized. The profiler object must be disposed after use by calling
410   * |Dispose| method.
411   */
412  static CpuProfiler* New(Isolate* isolate,
413                          CpuProfilingNamingMode = kDebugNaming,
414                          CpuProfilingLoggingMode = kLazyLogging);
415
416  /**
417   * Synchronously collect current stack sample in all profilers attached to
418   * the |isolate|. The call does not affect number of ticks recorded for
419   * the current top node.
420   */
421  static void CollectSample(Isolate* isolate);
422
423  /**
424   * Disposes the CPU profiler object.
425   */
426  void Dispose();
427
428  /**
429   * Changes default CPU profiler sampling interval to the specified number
430   * of microseconds. Default interval is 1000us. This method must be called
431   * when there are no profiles being recorded.
432   */
433  void SetSamplingInterval(int us);
434
435  /**
436   * Sets whether or not the profiler should prioritize consistency of sample
437   * periodicity on Windows. Disabling this can greatly reduce CPU usage, but
438   * may result in greater variance in sample timings from the platform's
439   * scheduler. Defaults to enabled. This method must be called when there are
440   * no profiles being recorded.
441   */
442  void SetUsePreciseSampling(bool);
443
444  /**
445   * Starts collecting a CPU profile. Several profiles may be collected at once.
446   * Generates an anonymous profiler, without a String identifier.
447   */
448  CpuProfilingResult Start(
449      CpuProfilingOptions options,
450      std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
451
452  /**
453   * Starts collecting a CPU profile. Title may be an empty string. Several
454   * profiles may be collected at once. Attempts to start collecting several
455   * profiles with the same title are silently ignored.
456   */
457  CpuProfilingResult Start(
458      Local<String> title, CpuProfilingOptions options,
459      std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
460
461  /**
462   * Starts profiling with the same semantics as above, except with expanded
463   * parameters.
464   *
465   * |record_samples| parameter controls whether individual samples should
466   * be recorded in addition to the aggregated tree.
467   *
468   * |max_samples| controls the maximum number of samples that should be
469   * recorded by the profiler. Samples obtained after this limit will be
470   * discarded.
471   */
472  CpuProfilingResult Start(
473      Local<String> title, CpuProfilingMode mode, bool record_samples = false,
474      unsigned max_samples = CpuProfilingOptions::kNoSampleLimit);
475
476  /**
477   * The same as StartProfiling above, but the CpuProfilingMode defaults to
478   * kLeafNodeLineNumbers mode, which was the previous default behavior of the
479   * profiler.
480   */
481  CpuProfilingResult Start(Local<String> title, bool record_samples = false);
482
483  /**
484   * Starts collecting a CPU profile. Title may be an empty string. Several
485   * profiles may be collected at once. Attempts to start collecting several
486   * profiles with the same title are silently ignored.
487   */
488  CpuProfilingStatus StartProfiling(
489      Local<String> title, CpuProfilingOptions options,
490      std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
491
492  /**
493   * Starts profiling with the same semantics as above, except with expanded
494   * parameters.
495   *
496   * |record_samples| parameter controls whether individual samples should
497   * be recorded in addition to the aggregated tree.
498   *
499   * |max_samples| controls the maximum number of samples that should be
500   * recorded by the profiler. Samples obtained after this limit will be
501   * discarded.
502   */
503  CpuProfilingStatus StartProfiling(
504      Local<String> title, CpuProfilingMode mode, bool record_samples = false,
505      unsigned max_samples = CpuProfilingOptions::kNoSampleLimit);
506
507  /**
508   * The same as StartProfiling above, but the CpuProfilingMode defaults to
509   * kLeafNodeLineNumbers mode, which was the previous default behavior of the
510   * profiler.
511   */
512  CpuProfilingStatus StartProfiling(Local<String> title,
513                                    bool record_samples = false);
514
515  /**
516   * Stops collecting CPU profile with a given id and returns it.
517   */
518  CpuProfile* Stop(ProfilerId id);
519
520  /**
521   * Stops collecting CPU profile with a given title and returns it.
522   * If the title given is empty, finishes the last profile started.
523   */
524  CpuProfile* StopProfiling(Local<String> title);
525
526  /**
527   * Generate more detailed source positions to code objects. This results in
528   * better results when mapping profiling samples to script source.
529   */
530  static void UseDetailedSourcePositionsForProfiling(Isolate* isolate);
531
532 private:
533  CpuProfiler();
534  ~CpuProfiler();
535  CpuProfiler(const CpuProfiler&);
536  CpuProfiler& operator=(const CpuProfiler&);
537};
538
539/**
540 * HeapSnapshotEdge represents a directed connection between heap
541 * graph nodes: from retainers to retained nodes.
542 */
543class V8_EXPORT HeapGraphEdge {
544 public:
545  enum Type {
546    kContextVariable = 0,  // A variable from a function context.
547    kElement = 1,          // An element of an array.
548    kProperty = 2,         // A named object property.
549    kInternal = 3,         // A link that can't be accessed from JS,
550                           // thus, its name isn't a real property name
551                           // (e.g. parts of a ConsString).
552    kHidden = 4,           // A link that is needed for proper sizes
553                           // calculation, but may be hidden from user.
554    kShortcut = 5,         // A link that must not be followed during
555                           // sizes calculation.
556    kWeak = 6              // A weak reference (ignored by the GC).
557  };
558
559  /** Returns edge type (see HeapGraphEdge::Type). */
560  Type GetType() const;
561
562  /**
563   * Returns edge name. This can be a variable name, an element index, or
564   * a property name.
565   */
566  Local<Value> GetName() const;
567
568  /** Returns origin node. */
569  const HeapGraphNode* GetFromNode() const;
570
571  /** Returns destination node. */
572  const HeapGraphNode* GetToNode() const;
573};
574
575
576/**
577 * HeapGraphNode represents a node in a heap graph.
578 */
579class V8_EXPORT HeapGraphNode {
580 public:
581  enum Type {
582    kHidden = 0,         // Hidden node, may be filtered when shown to user.
583    kArray = 1,          // An array of elements.
584    kString = 2,         // A string.
585    kObject = 3,         // A JS object (except for arrays and strings).
586    kCode = 4,           // Compiled code.
587    kClosure = 5,        // Function closure.
588    kRegExp = 6,         // RegExp.
589    kHeapNumber = 7,     // Number stored in the heap.
590    kNative = 8,         // Native object (not from V8 heap).
591    kSynthetic = 9,      // Synthetic object, usually used for grouping
592                         // snapshot items together.
593    kConsString = 10,    // Concatenated string. A pair of pointers to strings.
594    kSlicedString = 11,  // Sliced string. A fragment of another string.
595    kSymbol = 12,        // A Symbol (ES6).
596    kBigInt = 13,        // BigInt.
597    kObjectShape = 14,   // Internal data used for tracking the shapes (or
598                         // "hidden classes") of JS objects.
599    kWasmObject = 15,    // A WasmGC struct or array.
600  };
601
602  /** Returns node type (see HeapGraphNode::Type). */
603  Type GetType() const;
604
605  /**
606   * Returns node name. Depending on node's type this can be the name
607   * of the constructor (for objects), the name of the function (for
608   * closures), string value, or an empty string (for compiled code).
609   */
610  Local<String> GetName() const;
611
612  /**
613   * Returns node id. For the same heap object, the id remains the same
614   * across all snapshots.
615   */
616  SnapshotObjectId GetId() const;
617
618  /** Returns node's own size, in bytes. */
619  size_t GetShallowSize() const;
620
621  /** Returns child nodes count of the node. */
622  int GetChildrenCount() const;
623
624  /** Retrieves a child by index. */
625  const HeapGraphEdge* GetChild(int index) const;
626};
627
628/**
629 * HeapSnapshots record the state of the JS heap at some moment.
630 */
631class V8_EXPORT HeapSnapshot {
632 public:
633  enum SerializationFormat {
634    kJSON = 0  // See format description near 'Serialize' method.
635  };
636
637  /** Returns the root node of the heap graph. */
638  const HeapGraphNode* GetRoot() const;
639
640  /** Returns a node by its id. */
641  const HeapGraphNode* GetNodeById(SnapshotObjectId id) const;
642
643  /** Returns total nodes count in the snapshot. */
644  int GetNodesCount() const;
645
646  /** Returns a node by index. */
647  const HeapGraphNode* GetNode(int index) const;
648
649  /** Returns a max seen JS object Id. */
650  SnapshotObjectId GetMaxSnapshotJSObjectId() const;
651
652  /**
653   * Deletes the snapshot and removes it from HeapProfiler's list.
654   * All pointers to nodes, edges and paths previously returned become
655   * invalid.
656   */
657  void Delete();
658
659  /**
660   * Prepare a serialized representation of the snapshot. The result
661   * is written into the stream provided in chunks of specified size.
662   * The total length of the serialized snapshot is unknown in
663   * advance, it can be roughly equal to JS heap size (that means,
664   * it can be really big - tens of megabytes).
665   *
666   * For the JSON format, heap contents are represented as an object
667   * with the following structure:
668   *
669   *  {
670   *    snapshot: {
671   *      title: "...",
672   *      uid: nnn,
673   *      meta: { meta-info },
674   *      node_count: nnn,
675   *      edge_count: nnn
676   *    },
677   *    nodes: [nodes array],
678   *    edges: [edges array],
679   *    strings: [strings array]
680   *  }
681   *
682   * Nodes reference strings, other nodes, and edges by their indexes
683   * in corresponding arrays.
684   */
685  void Serialize(OutputStream* stream,
686                 SerializationFormat format = kJSON) const;
687};
688
689
690/**
691 * An interface for reporting progress and controlling long-running
692 * activities.
693 */
694class V8_EXPORT ActivityControl {
695 public:
696  enum ControlOption {
697    kContinue = 0,
698    kAbort = 1
699  };
700  virtual ~ActivityControl() = default;
701  /**
702   * Notify about current progress. The activity can be stopped by
703   * returning kAbort as the callback result.
704   */
705  virtual ControlOption ReportProgressValue(uint32_t done, uint32_t total) = 0;
706};
707
708/**
709 * AllocationProfile is a sampled profile of allocations done by the program.
710 * This is structured as a call-graph.
711 */
712class V8_EXPORT AllocationProfile {
713 public:
714  struct Allocation {
715    /**
716     * Size of the sampled allocation object.
717     */
718    size_t size;
719
720    /**
721     * The number of objects of such size that were sampled.
722     */
723    unsigned int count;
724  };
725
726  /**
727   * Represents a node in the call-graph.
728   */
729  struct Node {
730    /**
731     * Name of the function. May be empty for anonymous functions or if the
732     * script corresponding to this function has been unloaded.
733     */
734    Local<String> name;
735
736    /**
737     * Name of the script containing the function. May be empty if the script
738     * name is not available, or if the script has been unloaded.
739     */
740    Local<String> script_name;
741
742    /**
743     * id of the script where the function is located. May be equal to
744     * v8::UnboundScript::kNoScriptId in cases where the script doesn't exist.
745     */
746    int script_id;
747
748    /**
749     * Start position of the function in the script.
750     */
751    int start_position;
752
753    /**
754     * 1-indexed line number where the function starts. May be
755     * kNoLineNumberInfo if no line number information is available.
756     */
757    int line_number;
758
759    /**
760     * 1-indexed column number where the function starts. May be
761     * kNoColumnNumberInfo if no line number information is available.
762     */
763    int column_number;
764
765    /**
766     * Unique id of the node.
767     */
768    uint32_t node_id;
769
770    /**
771     * List of callees called from this node for which we have sampled
772     * allocations. The lifetime of the children is scoped to the containing
773     * AllocationProfile.
774     */
775    std::vector<Node*> children;
776
777    /**
778     * List of self allocations done by this node in the call-graph.
779     */
780    std::vector<Allocation> allocations;
781  };
782
783  /**
784   * Represent a single sample recorded for an allocation.
785   */
786  struct Sample {
787    /**
788     * id of the node in the profile tree.
789     */
790    uint32_t node_id;
791
792    /**
793     * Size of the sampled allocation object.
794     */
795    size_t size;
796
797    /**
798     * The number of objects of such size that were sampled.
799     */
800    unsigned int count;
801
802    /**
803     * Unique time-ordered id of the allocation sample. Can be used to track
804     * what samples were added or removed between two snapshots.
805     */
806    uint64_t sample_id;
807  };
808
809  /**
810   * Returns the root node of the call-graph. The root node corresponds to an
811   * empty JS call-stack. The lifetime of the returned Node* is scoped to the
812   * containing AllocationProfile.
813   */
814  virtual Node* GetRootNode() = 0;
815  virtual const std::vector<Sample>& GetSamples() = 0;
816
817  virtual ~AllocationProfile() = default;
818
819  static const int kNoLineNumberInfo = Message::kNoLineNumberInfo;
820  static const int kNoColumnNumberInfo = Message::kNoColumnInfo;
821};
822
823/**
824 * An object graph consisting of embedder objects and V8 objects.
825 * Edges of the graph are strong references between the objects.
826 * The embedder can build this graph during heap snapshot generation
827 * to include the embedder objects in the heap snapshot.
828 * Usage:
829 * 1) Define derived class of EmbedderGraph::Node for embedder objects.
830 * 2) Set the build embedder graph callback on the heap profiler using
831 *    HeapProfiler::AddBuildEmbedderGraphCallback.
832 * 3) In the callback use graph->AddEdge(node1, node2) to add an edge from
833 *    node1 to node2.
834 * 4) To represent references from/to V8 object, construct V8 nodes using
835 *    graph->V8Node(value).
836 */
837class V8_EXPORT EmbedderGraph {
838 public:
839  class Node {
840   public:
841    /**
842     * Detachedness specifies whether an object is attached or detached from the
843     * main application state. While unkown in general, there may be objects
844     * that specifically know their state. V8 passes this information along in
845     * the snapshot. Users of the snapshot may use it to annotate the object
846     * graph.
847     */
848    enum class Detachedness : uint8_t {
849      kUnknown = 0,
850      kAttached = 1,
851      kDetached = 2,
852    };
853
854    Node() = default;
855    virtual ~Node() = default;
856    virtual const char* Name() = 0;
857    virtual size_t SizeInBytes() = 0;
858    /**
859     * The corresponding V8 wrapper node if not null.
860     * During heap snapshot generation the embedder node and the V8 wrapper
861     * node will be merged into one node to simplify retaining paths.
862     */
863    virtual Node* WrapperNode() { return nullptr; }
864    virtual bool IsRootNode() { return false; }
865    /** Must return true for non-V8 nodes. */
866    virtual bool IsEmbedderNode() { return true; }
867    /**
868     * Optional name prefix. It is used in Chrome for tagging detached nodes.
869     */
870    virtual const char* NamePrefix() { return nullptr; }
871
872    /**
873     * Returns the NativeObject that can be used for querying the
874     * |HeapSnapshot|.
875     */
876    virtual NativeObject GetNativeObject() { return nullptr; }
877
878    /**
879     * Detachedness state of a given object. While unkown in general, there may
880     * be objects that specifically know their state. V8 passes this information
881     * along in the snapshot. Users of the snapshot may use it to annotate the
882     * object graph.
883     */
884    virtual Detachedness GetDetachedness() { return Detachedness::kUnknown; }
885
886    /**
887     * Returns the address of the object in the embedder heap, or nullptr to not
888     * specify the address. If this address is provided, then V8 can generate
889     * consistent IDs for objects across subsequent heap snapshots, which allows
890     * devtools to determine which objects were retained from one snapshot to
891     * the next. This value is used only if GetNativeObject returns nullptr.
892     */
893    virtual const void* GetAddress() { return nullptr; }
894
895    Node(const Node&) = delete;
896    Node& operator=(const Node&) = delete;
897  };
898
899  /**
900   * Returns a node corresponding to the given V8 value. Ownership is not
901   * transferred. The result pointer is valid while the graph is alive.
902   */
903  virtual Node* V8Node(const v8::Local<v8::Value>& value) = 0;
904
905  /**
906   * Adds the given node to the graph and takes ownership of the node.
907   * Returns a raw pointer to the node that is valid while the graph is alive.
908   */
909  virtual Node* AddNode(std::unique_ptr<Node> node) = 0;
910
911  /**
912   * Adds an edge that represents a strong reference from the given
913   * node |from| to the given node |to|. The nodes must be added to the graph
914   * before calling this function.
915   *
916   * If name is nullptr, the edge will have auto-increment indexes, otherwise
917   * it will be named accordingly.
918   */
919  virtual void AddEdge(Node* from, Node* to, const char* name = nullptr) = 0;
920
921  virtual ~EmbedderGraph() = default;
922};
923
924/**
925 * Interface for controlling heap profiling. Instance of the
926 * profiler can be retrieved using v8::Isolate::GetHeapProfiler.
927 */
928class V8_EXPORT HeapProfiler {
929 public:
930  enum SamplingFlags {
931    kSamplingNoFlags = 0,
932    kSamplingForceGC = 1 << 0,
933    kSamplingIncludeObjectsCollectedByMajorGC = 1 << 1,
934    kSamplingIncludeObjectsCollectedByMinorGC = 1 << 2,
935  };
936
937  /**
938   * Callback function invoked during heap snapshot generation to retrieve
939   * the embedder object graph. The callback should use graph->AddEdge(..) to
940   * add references between the objects.
941   * The callback must not trigger garbage collection in V8.
942   */
943  typedef void (*BuildEmbedderGraphCallback)(v8::Isolate* isolate,
944                                             v8::EmbedderGraph* graph,
945                                             void* data);
946
947  /**
948   * Callback function invoked during heap snapshot generation to retrieve
949   * the detachedness state of an object referenced by a TracedReference.
950   *
951   * The callback takes Local<Value> as parameter to allow the embedder to
952   * unpack the TracedReference into a Local and reuse that Local for different
953   * purposes.
954   */
955  using GetDetachednessCallback = EmbedderGraph::Node::Detachedness (*)(
956      v8::Isolate* isolate, const v8::Local<v8::Value>& v8_value,
957      uint16_t class_id, void* data);
958
959  /** Returns the number of snapshots taken. */
960  int GetSnapshotCount();
961
962  /** Returns a snapshot by index. */
963  const HeapSnapshot* GetHeapSnapshot(int index);
964
965  /**
966   * Returns SnapshotObjectId for a heap object referenced by |value| if
967   * it has been seen by the heap profiler, kUnknownObjectId otherwise.
968   */
969  SnapshotObjectId GetObjectId(Local<Value> value);
970
971  /**
972   * Returns SnapshotObjectId for a native object referenced by |value| if it
973   * has been seen by the heap profiler, kUnknownObjectId otherwise.
974   */
975  SnapshotObjectId GetObjectId(NativeObject value);
976
977  /**
978   * Returns heap object with given SnapshotObjectId if the object is alive,
979   * otherwise empty handle is returned.
980   */
981  Local<Value> FindObjectById(SnapshotObjectId id);
982
983  /**
984   * Clears internal map from SnapshotObjectId to heap object. The new objects
985   * will not be added into it unless a heap snapshot is taken or heap object
986   * tracking is kicked off.
987   */
988  void ClearObjectIds();
989
990  /**
991   * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return
992   * it in case heap profiler cannot find id  for the object passed as
993   * parameter. HeapSnapshot::GetNodeById will always return NULL for such id.
994   */
995  static const SnapshotObjectId kUnknownObjectId = 0;
996
997  /**
998   * Callback interface for retrieving user friendly names of global objects.
999   */
1000  class ObjectNameResolver {
1001   public:
1002    /**
1003     * Returns name to be used in the heap snapshot for given node. Returned
1004     * string must stay alive until snapshot collection is completed.
1005     */
1006    virtual const char* GetName(Local<Object> object) = 0;
1007
1008   protected:
1009    virtual ~ObjectNameResolver() = default;
1010  };
1011
1012  enum class HeapSnapshotMode {
1013    /**
1014     * Heap snapshot for regular developers.
1015     */
1016    kRegular,
1017    /**
1018     * Heap snapshot is exposing internals that may be useful for experts.
1019     */
1020    kExposeInternals,
1021  };
1022
1023  enum class NumericsMode {
1024    /**
1025     * Numeric values are hidden as they are values of the corresponding
1026     * objects.
1027     */
1028    kHideNumericValues,
1029    /**
1030     * Numeric values are exposed in artificial fields.
1031     */
1032    kExposeNumericValues
1033  };
1034
1035  struct HeapSnapshotOptions final {
1036    // Manually define default constructor here to be able to use it in
1037    // `TakeSnapshot()` below.
1038    // NOLINTNEXTLINE
1039    HeapSnapshotOptions() {}
1040
1041    /**
1042     * The control used to report intermediate progress to.
1043     */
1044    ActivityControl* control = nullptr;
1045    /**
1046     * The resolver used by the snapshot generator to get names for V8 objects.
1047     */
1048    ObjectNameResolver* global_object_name_resolver = nullptr;
1049    /**
1050     * Mode for taking the snapshot, see `HeapSnapshotMode`.
1051     */
1052    HeapSnapshotMode snapshot_mode = HeapSnapshotMode::kRegular;
1053    /**
1054     * Mode for dealing with numeric values, see `NumericsMode`.
1055     */
1056    NumericsMode numerics_mode = NumericsMode::kHideNumericValues;
1057  };
1058
1059  /**
1060   * Takes a heap snapshot.
1061   *
1062   * \returns the snapshot.
1063   */
1064  const HeapSnapshot* TakeHeapSnapshot(
1065      const HeapSnapshotOptions& options = HeapSnapshotOptions());
1066
1067  /**
1068   * Takes a heap snapshot. See `HeapSnapshotOptions` for details on the
1069   * parameters.
1070   *
1071   * \returns the snapshot.
1072   */
1073  const HeapSnapshot* TakeHeapSnapshot(
1074      ActivityControl* control,
1075      ObjectNameResolver* global_object_name_resolver = nullptr,
1076      bool hide_internals = true, bool capture_numeric_value = false);
1077
1078  /**
1079   * Starts tracking of heap objects population statistics. After calling
1080   * this method, all heap objects relocations done by the garbage collector
1081   * are being registered.
1082   *
1083   * |track_allocations| parameter controls whether stack trace of each
1084   * allocation in the heap will be recorded and reported as part of
1085   * HeapSnapshot.
1086   */
1087  void StartTrackingHeapObjects(bool track_allocations = false);
1088
1089  /**
1090   * Adds a new time interval entry to the aggregated statistics array. The
1091   * time interval entry contains information on the current heap objects
1092   * population size. The method also updates aggregated statistics and
1093   * reports updates for all previous time intervals via the OutputStream
1094   * object. Updates on each time interval are provided as a stream of the
1095   * HeapStatsUpdate structure instances.
1096   * If |timestamp_us| is supplied, timestamp of the new entry will be written
1097   * into it. The return value of the function is the last seen heap object Id.
1098   *
1099   * StartTrackingHeapObjects must be called before the first call to this
1100   * method.
1101   */
1102  SnapshotObjectId GetHeapStats(OutputStream* stream,
1103                                int64_t* timestamp_us = nullptr);
1104
1105  /**
1106   * Stops tracking of heap objects population statistics, cleans up all
1107   * collected data. StartHeapObjectsTracking must be called again prior to
1108   * calling GetHeapStats next time.
1109   */
1110  void StopTrackingHeapObjects();
1111
1112  /**
1113   * Starts gathering a sampling heap profile. A sampling heap profile is
1114   * similar to tcmalloc's heap profiler and Go's mprof. It samples object
1115   * allocations and builds an online 'sampling' heap profile. At any point in
1116   * time, this profile is expected to be a representative sample of objects
1117   * currently live in the system. Each sampled allocation includes the stack
1118   * trace at the time of allocation, which makes this really useful for memory
1119   * leak detection.
1120   *
1121   * This mechanism is intended to be cheap enough that it can be used in
1122   * production with minimal performance overhead.
1123   *
1124   * Allocations are sampled using a randomized Poisson process. On average, one
1125   * allocation will be sampled every |sample_interval| bytes allocated. The
1126   * |stack_depth| parameter controls the maximum number of stack frames to be
1127   * captured on each allocation.
1128   *
1129   * NOTE: Support for native allocations doesn't exist yet, but is anticipated
1130   * in the future.
1131   *
1132   * Objects allocated before the sampling is started will not be included in
1133   * the profile.
1134   *
1135   * Returns false if a sampling heap profiler is already running.
1136   */
1137  bool StartSamplingHeapProfiler(uint64_t sample_interval = 512 * 1024,
1138                                 int stack_depth = 16,
1139                                 SamplingFlags flags = kSamplingNoFlags);
1140
1141  /**
1142   * Stops the sampling heap profile and discards the current profile.
1143   */
1144  void StopSamplingHeapProfiler();
1145
1146  /**
1147   * Returns the sampled profile of allocations allocated (and still live) since
1148   * StartSamplingHeapProfiler was called. The ownership of the pointer is
1149   * transferred to the caller. Returns nullptr if sampling heap profiler is not
1150   * active.
1151   */
1152  AllocationProfile* GetAllocationProfile();
1153
1154  /**
1155   * Deletes all snapshots taken. All previously returned pointers to
1156   * snapshots and their contents become invalid after this call.
1157   */
1158  void DeleteAllHeapSnapshots();
1159
1160  void AddBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback,
1161                                     void* data);
1162  void RemoveBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback,
1163                                        void* data);
1164
1165  void SetGetDetachednessCallback(GetDetachednessCallback callback, void* data);
1166
1167  /**
1168   * Default value of persistent handle class ID. Must not be used to
1169   * define a class. Can be used to reset a class of a persistent
1170   * handle.
1171   */
1172  static const uint16_t kPersistentHandleNoClassId = 0;
1173
1174 private:
1175  HeapProfiler();
1176  ~HeapProfiler();
1177  HeapProfiler(const HeapProfiler&);
1178  HeapProfiler& operator=(const HeapProfiler&);
1179};
1180
1181/**
1182 * A struct for exporting HeapStats data from V8, using "push" model.
1183 * See HeapProfiler::GetHeapStats.
1184 */
1185struct HeapStatsUpdate {
1186  HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size)
1187    : index(index), count(count), size(size) { }
1188  uint32_t index;  // Index of the time interval that was changed.
1189  uint32_t count;  // New value of count field for the interval with this index.
1190  uint32_t size;  // New value of size field for the interval with this index.
1191};
1192
1193#define CODE_EVENTS_LIST(V)                          \
1194  V(Builtin)                                         \
1195  V(Callback)                                        \
1196  V(Eval)                                            \
1197  V(Function)                                        \
1198  V(InterpretedFunction)                             \
1199  V(Handler)                                         \
1200  V(BytecodeHandler)                                 \
1201  V(LazyCompile) /* Unused, use kFunction instead */ \
1202  V(RegExp)                                          \
1203  V(Script)                                          \
1204  V(Stub)                                            \
1205  V(Relocation)
1206
1207/**
1208 * Note that this enum may be extended in the future. Please include a default
1209 * case if this enum is used in a switch statement.
1210 */
1211enum CodeEventType {
1212  kUnknownType = 0
1213#define V(Name) , k##Name##Type
1214  CODE_EVENTS_LIST(V)
1215#undef V
1216};
1217
1218/**
1219 * Representation of a code creation event
1220 */
1221class V8_EXPORT CodeEvent {
1222 public:
1223  uintptr_t GetCodeStartAddress();
1224  size_t GetCodeSize();
1225  Local<String> GetFunctionName();
1226  Local<String> GetScriptName();
1227  int GetScriptLine();
1228  int GetScriptColumn();
1229  /**
1230   * NOTE (mmarchini): We can't allocate objects in the heap when we collect
1231   * existing code, and both the code type and the comment are not stored in the
1232   * heap, so we return those as const char*.
1233   */
1234  CodeEventType GetCodeType();
1235  const char* GetComment();
1236
1237  static const char* GetCodeEventTypeName(CodeEventType code_event_type);
1238
1239  uintptr_t GetPreviousCodeStartAddress();
1240};
1241
1242/**
1243 * Interface to listen to code creation and code relocation events.
1244 */
1245class V8_EXPORT CodeEventHandler {
1246 public:
1247  /**
1248   * Creates a new listener for the |isolate|. The isolate must be initialized.
1249   * The listener object must be disposed after use by calling |Dispose| method.
1250   * Multiple listeners can be created for the same isolate.
1251   */
1252  explicit CodeEventHandler(Isolate* isolate);
1253  virtual ~CodeEventHandler();
1254
1255  /**
1256   * Handle is called every time a code object is created or moved. Information
1257   * about each code event will be available through the `code_event`
1258   * parameter.
1259   *
1260   * When the CodeEventType is kRelocationType, the code for this CodeEvent has
1261   * moved from `GetPreviousCodeStartAddress()` to `GetCodeStartAddress()`.
1262   */
1263  virtual void Handle(CodeEvent* code_event) = 0;
1264
1265  /**
1266   * Call `Enable()` to starts listening to code creation and code relocation
1267   * events. These events will be handled by `Handle()`.
1268   */
1269  void Enable();
1270
1271  /**
1272   * Call `Disable()` to stop listening to code creation and code relocation
1273   * events.
1274   */
1275  void Disable();
1276
1277 private:
1278  CodeEventHandler();
1279  CodeEventHandler(const CodeEventHandler&);
1280  CodeEventHandler& operator=(const CodeEventHandler&);
1281  void* internal_listener_;
1282};
1283
1284}  // namespace v8
1285
1286
1287#endif  // V8_V8_PROFILER_H_
1288