• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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_EMBEDDER_TRACING_H_
6 #define V8_HEAP_EMBEDDER_TRACING_H_
7 
8 #include "include/v8.h"
9 #include "src/common/globals.h"
10 #include "src/flags/flags.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 class Heap;
16 class JSObject;
17 
18 class V8_EXPORT_PRIVATE LocalEmbedderHeapTracer final {
19  public:
20   using WrapperInfo = std::pair<void*, void*>;
21   using WrapperCache = std::vector<WrapperInfo>;
22 
23   // WrapperInfo is passed over the API. Use VerboseWrapperInfo to access pair
24   // internals in a named way. See ProcessingScope::TracePossibleJSWrapper()
25   // below on how a V8 object is parsed to gather the information.
26   struct VerboseWrapperInfo {
VerboseWrapperInfoVerboseWrapperInfo27     explicit VerboseWrapperInfo(const WrapperInfo& raw_info)
28         : raw_info(raw_info) {}
29 
30     // Information describing the type pointed to via instance().
type_infoVerboseWrapperInfo31     void* type_info() const { return raw_info.first; }
32     // Direct pointer to an instance described by type_info().
instanceVerboseWrapperInfo33     void* instance() const { return raw_info.second; }
34 
is_validVerboseWrapperInfo35     bool is_valid() const { return type_info(); }
36 
37     const WrapperInfo& raw_info;
38   };
39 
40   class V8_EXPORT_PRIVATE ProcessingScope {
41    public:
42     explicit ProcessingScope(LocalEmbedderHeapTracer* tracer);
43     ~ProcessingScope();
44 
45     void TracePossibleWrapper(JSObject js_object);
46 
47     void AddWrapperInfoForTesting(WrapperInfo info);
48 
49    private:
50     static constexpr size_t kWrapperCacheSize = 1000;
51 
52     void FlushWrapperCacheIfFull();
53 
54     LocalEmbedderHeapTracer* const tracer_;
55     WrapperCache wrapper_cache_;
56   };
57 
58   static WrapperInfo ExtractWrapperInfo(Isolate* isolate, JSObject js_object);
59 
LocalEmbedderHeapTracer(Isolate * isolate)60   explicit LocalEmbedderHeapTracer(Isolate* isolate) : isolate_(isolate) {}
61 
~LocalEmbedderHeapTracer()62   ~LocalEmbedderHeapTracer() {
63     if (remote_tracer_) remote_tracer_->isolate_ = nullptr;
64   }
65 
InUse()66   bool InUse() const { return remote_tracer_ != nullptr; }
remote_tracer()67   EmbedderHeapTracer* remote_tracer() const { return remote_tracer_; }
68 
69   void SetRemoteTracer(EmbedderHeapTracer* tracer);
70   void TracePrologue(EmbedderHeapTracer::TraceFlags flags);
71   void TraceEpilogue();
72   void EnterFinalPause();
73   bool Trace(double deadline);
74   bool IsRemoteTracingDone();
75 
IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value> & handle)76   bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) {
77     return !InUse() || remote_tracer_->IsRootForNonTracingGC(handle);
78   }
79 
IsRootForNonTracingGC(const v8::TracedReference<v8::Value> & handle)80   bool IsRootForNonTracingGC(const v8::TracedReference<v8::Value>& handle) {
81     return !InUse() || remote_tracer_->IsRootForNonTracingGC(handle);
82   }
83 
ResetHandleInNonTracingGC(const v8::TracedReference<v8::Value> & handle)84   void ResetHandleInNonTracingGC(const v8::TracedReference<v8::Value>& handle) {
85     // Resetting is only called when IsRootForNonTracingGC returns false which
86     // can only happen the EmbedderHeapTracer is set on API level.
87     DCHECK(InUse());
88     remote_tracer_->ResetHandleInNonTracingGC(handle);
89   }
90 
ShouldFinalizeIncrementalMarking()91   bool ShouldFinalizeIncrementalMarking() {
92     return !FLAG_incremental_marking_wrappers || !InUse() ||
93            (IsRemoteTracingDone() && embedder_worklist_empty_);
94   }
95 
96   void SetEmbedderStackStateForNextFinalization(
97       EmbedderHeapTracer::EmbedderStackState stack_state);
98 
SetEmbedderWorklistEmpty(bool is_empty)99   void SetEmbedderWorklistEmpty(bool is_empty) {
100     embedder_worklist_empty_ = is_empty;
101   }
102 
IncreaseAllocatedSize(size_t bytes)103   void IncreaseAllocatedSize(size_t bytes) {
104     remote_stats_.used_size += bytes;
105     remote_stats_.allocated_size += bytes;
106     if (remote_stats_.allocated_size >
107         remote_stats_.allocated_size_limit_for_check) {
108       StartIncrementalMarkingIfNeeded();
109       remote_stats_.allocated_size_limit_for_check =
110           remote_stats_.allocated_size + kEmbedderAllocatedThreshold;
111     }
112   }
113 
DecreaseAllocatedSize(size_t bytes)114   void DecreaseAllocatedSize(size_t bytes) {
115     DCHECK_GE(remote_stats_.used_size, bytes);
116     remote_stats_.used_size -= bytes;
117   }
118 
119   void StartIncrementalMarkingIfNeeded();
120 
used_size()121   size_t used_size() const { return remote_stats_.used_size; }
allocated_size()122   size_t allocated_size() const { return remote_stats_.allocated_size; }
123 
124  private:
125   static constexpr size_t kEmbedderAllocatedThreshold = 128 * KB;
126 
127   Isolate* const isolate_;
128   EmbedderHeapTracer* remote_tracer_ = nullptr;
129 
130   EmbedderHeapTracer::EmbedderStackState embedder_stack_state_ =
131       EmbedderHeapTracer::EmbedderStackState::kMayContainHeapPointers;
132   // Indicates whether the embedder worklist was observed empty on the main
133   // thread. This is opportunistic as concurrent marking tasks may hold local
134   // segments of potential embedder fields to move to the main thread.
135   bool embedder_worklist_empty_ = false;
136 
137   struct RemoteStatistics {
138     // Used size of objects in bytes reported by the embedder. Updated via
139     // TraceSummary at the end of tracing and incrementally when the GC is not
140     // in progress.
141     size_t used_size = 0;
142     // Totally bytes allocated by the embedder. Monotonically
143     // increasing value. Used to approximate allocation rate.
144     size_t allocated_size = 0;
145     // Limit for |allocated_size| in bytes to avoid checking for starting a GC
146     // on each increment.
147     size_t allocated_size_limit_for_check = 0;
148   } remote_stats_;
149 
150   friend class EmbedderStackStateScope;
151 };
152 
153 class V8_EXPORT_PRIVATE EmbedderStackStateScope final {
154  public:
EmbedderStackStateScope(LocalEmbedderHeapTracer * local_tracer,EmbedderHeapTracer::EmbedderStackState stack_state)155   EmbedderStackStateScope(LocalEmbedderHeapTracer* local_tracer,
156                           EmbedderHeapTracer::EmbedderStackState stack_state)
157       : local_tracer_(local_tracer),
158         old_stack_state_(local_tracer_->embedder_stack_state_) {
159     local_tracer_->embedder_stack_state_ = stack_state;
160     if (EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers ==
161         stack_state) {
162       if (local_tracer->remote_tracer())
163         local_tracer->remote_tracer()->NotifyEmptyEmbedderStack();
164     }
165   }
166 
~EmbedderStackStateScope()167   ~EmbedderStackStateScope() {
168     local_tracer_->embedder_stack_state_ = old_stack_state_;
169   }
170 
171  private:
172   LocalEmbedderHeapTracer* const local_tracer_;
173   const EmbedderHeapTracer::EmbedderStackState old_stack_state_;
174 };
175 
176 }  // namespace internal
177 }  // namespace v8
178 
179 #endif  // V8_HEAP_EMBEDDER_TRACING_H_
180