1 // Copyright 2019 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_HEAP_MEMORY_MEASUREMENT_H_
6 #define V8_HEAP_MEMORY_MEASUREMENT_H_
7 
8 #include <list>
9 #include <unordered_map>
10 
11 #include "src/base/platform/elapsed-timer.h"
12 #include "src/common/globals.h"
13 #include "src/objects/contexts.h"
14 #include "src/objects/map.h"
15 #include "src/objects/objects.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 class Heap;
21 class NativeContextStats;
22 
23 class MemoryMeasurement {
24  public:
25   explicit MemoryMeasurement(Isolate* isolate);
26 
27   bool EnqueueRequest(std::unique_ptr<v8::MeasureMemoryDelegate> delegate,
28                       v8::MeasureMemoryExecution execution,
29                       const std::vector<Handle<NativeContext>> contexts);
30   std::vector<Address> StartProcessing();
31   void FinishProcessing(const NativeContextStats& stats);
32 
33   static std::unique_ptr<v8::MeasureMemoryDelegate> DefaultDelegate(
34       Isolate* isolate, Handle<NativeContext> context,
35       Handle<JSPromise> promise, v8::MeasureMemoryMode mode);
36 
37  private:
38   static const int kGCTaskDelayInSeconds = 10;
39   struct Request {
40     std::unique_ptr<v8::MeasureMemoryDelegate> delegate;
41     Handle<WeakFixedArray> contexts;
42     std::vector<size_t> sizes;
43     size_t shared;
44     base::ElapsedTimer timer;
45   };
46   void ScheduleReportingTask();
47   void ReportResults();
48   void ScheduleGCTask(v8::MeasureMemoryExecution execution);
49   bool IsGCTaskPending(v8::MeasureMemoryExecution execution);
50   void SetGCTaskPending(v8::MeasureMemoryExecution execution);
51   void SetGCTaskDone(v8::MeasureMemoryExecution execution);
52 
53   std::list<Request> received_;
54   std::list<Request> processing_;
55   std::list<Request> done_;
56   Isolate* isolate_;
57   bool reporting_task_pending_ = false;
58   bool delayed_gc_task_pending_ = false;
59   bool eager_gc_task_pending_ = false;
60 };
61 
62 // Infers the native context for some of the heap objects.
63 class V8_EXPORT_PRIVATE NativeContextInferrer {
64  public:
65   // The native_context parameter is both the input and output parameter.
66   // It should be initialized to the context that will be used for the object
67   // if the inference is not successful. The function performs more work if the
68   // context is the shared context.
69   V8_INLINE bool Infer(Isolate* isolate, Map map, HeapObject object,
70                        Address* native_context);
71 
72  private:
73   bool InferForJSFunction(JSFunction function, Address* native_context);
74   bool InferForJSObject(Isolate* isolate, Map map, JSObject object,
75                         Address* native_context);
76 };
77 
78 // Maintains mapping from native contexts to their sizes.
79 class V8_EXPORT_PRIVATE NativeContextStats {
80  public:
81   V8_INLINE void IncrementSize(Address context, Map map, HeapObject object,
82                                size_t size);
83 
Get(Address context)84   size_t Get(Address context) const {
85     const auto it = size_by_context_.find(context);
86     if (it == size_by_context_.end()) return 0;
87     return it->second;
88   }
89   void Clear();
90   void Merge(const NativeContextStats& other);
91 
92  private:
93   V8_INLINE bool HasExternalBytes(Map map);
94   void IncrementExternalSize(Address context, Map map, HeapObject object);
95   std::unordered_map<Address, size_t> size_by_context_;
96 };
97 
98 }  // namespace internal
99 }  // namespace v8
100 
101 #endif  // V8_HEAP_MEMORY_MEASUREMENT_H_
102