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  */
21 namespace v8 {
22 
23 enum class EmbedderStateTag : uint8_t;
24 class HeapGraphNode;
25 struct HeapStatsUpdate;
26 class Object;
27 enum StateTag : uint16_t;
28 
29 using NativeObject = void*;
30 using SnapshotObjectId = uint32_t;
31 using ProfilerId = uint32_t;
32 
33 struct CpuProfileDeoptFrame {
34   int script_id;
35   size_t position;
36 };
37 
38 namespace internal {
39 class CpuProfile;
40 }  // namespace internal
41 
42 }  // namespace v8
43 
44 #ifdef V8_OS_WIN
45 template class V8_EXPORT std::vector<v8::CpuProfileDeoptFrame>;
46 #endif
47 
48 namespace v8 {
49 
50 struct 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
59 template class V8_EXPORT std::vector<v8::CpuProfileDeoptInfo>;
60 #endif
61 
62 namespace v8 {
63 
64 /**
65  * CpuProfileNode represents a node in a call graph.
66  */
67 class 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  */
181 class 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. */
GetChunkSize()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    */
WriteHeapStatsChunk(HeapStatsUpdate* data, int count)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  */
209 class 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 
288 enum 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.
299 enum 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 
307 enum 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.
319 enum 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  */
329 struct CpuProfilingResult {
330   const ProfilerId id;
331   const CpuProfilingStatus status;
332 };
333 
334 /**
335  * Delegate for when max samples reached and samples are discarded.
336  */
337 class V8_EXPORT DiscardedSamplesDelegate {
338  public:
339   DiscardedSamplesDelegate() = default;
340 
341   virtual ~DiscardedSamplesDelegate() = default;
342   virtual void Notify() = 0;
343 
GetId() const344   ProfilerId GetId() const { return profiler_id_; }
345 
346  private:
347   friend internal::CpuProfile;
348 
SetId(ProfilerId id)349   void SetId(ProfilerId id) { profiler_id_ = id; }
350 
351   ProfilerId profiler_id_;
352 };
353 
354 /**
355  * Optional profiling attributes.
356  */
357 class 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 
mode() const385   CpuProfilingMode mode() const { return mode_; }
max_samples() const386   unsigned max_samples() const { return max_samples_; }
sampling_interval_us() const387   int sampling_interval_us() const { return sampling_interval_us_; }
388 
389  private:
390   friend class internal::CpuProfile;
391 
has_filter_context() const392   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  */
405 class 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  */
543 class 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  */
579 class 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  */
631 class 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  */
694 class 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  */
712 class 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  */
837 class 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      */
WrapperNode()863     virtual Node* WrapperNode() { return nullptr; }
IsRootNode()864     virtual bool IsRootNode() { return false; }
865     /** Must return true for non-V8 nodes. */
IsEmbedderNode()866     virtual bool IsEmbedderNode() { return true; }
867     /**
868      * Optional name prefix. It is used in Chrome for tagging detached nodes.
869      */
NamePrefix()870     virtual const char* NamePrefix() { return nullptr; }
871 
872     /**
873      * Returns the NativeObject that can be used for querying the
874      * |HeapSnapshot|.
875      */
GetNativeObject()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      */
GetDetachedness()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      */
GetAddress()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  */
928 class 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
HeapSnapshotOptionsv8::HeapProfiler::final1039     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  */
1185 struct HeapStatsUpdate {
HeapStatsUpdatev8::HeapStatsUpdate1186   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  */
1211 enum 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  */
1221 class 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  */
1245 class 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