• 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 #include "src/heap/embedder-tracing.h"
6 
7 #include "src/base/logging.h"
8 #include "src/heap/gc-tracer.h"
9 #include "src/objects/embedder-data-slot.h"
10 #include "src/objects/js-objects-inl.h"
11 
12 namespace v8 {
13 namespace internal {
14 
SetRemoteTracer(EmbedderHeapTracer * tracer)15 void LocalEmbedderHeapTracer::SetRemoteTracer(EmbedderHeapTracer* tracer) {
16   if (remote_tracer_) remote_tracer_->isolate_ = nullptr;
17 
18   remote_tracer_ = tracer;
19   if (remote_tracer_)
20     remote_tracer_->isolate_ = reinterpret_cast<v8::Isolate*>(isolate_);
21 }
22 
TracePrologue(EmbedderHeapTracer::TraceFlags flags)23 void LocalEmbedderHeapTracer::TracePrologue(
24     EmbedderHeapTracer::TraceFlags flags) {
25   if (!InUse()) return;
26 
27   embedder_worklist_empty_ = false;
28   remote_tracer_->TracePrologue(flags);
29 }
30 
TraceEpilogue()31 void LocalEmbedderHeapTracer::TraceEpilogue() {
32   if (!InUse()) return;
33 
34   EmbedderHeapTracer::TraceSummary summary;
35   remote_tracer_->TraceEpilogue(&summary);
36   remote_stats_.used_size = summary.allocated_size;
37   // Force a check next time increased memory is reported. This allows for
38   // setting limits close to actual heap sizes.
39   remote_stats_.allocated_size_limit_for_check = 0;
40   constexpr double kMinReportingTimeMs = 0.5;
41   if (summary.time > kMinReportingTimeMs) {
42     isolate_->heap()->tracer()->RecordEmbedderSpeed(summary.allocated_size,
43                                                     summary.time);
44   }
45 }
46 
EnterFinalPause()47 void LocalEmbedderHeapTracer::EnterFinalPause() {
48   if (!InUse()) return;
49 
50   remote_tracer_->EnterFinalPause(embedder_stack_state_);
51   // Resetting to state unknown as there may be follow up garbage collections
52   // triggered from callbacks that have a different stack state.
53   embedder_stack_state_ =
54       EmbedderHeapTracer::EmbedderStackState::kMayContainHeapPointers;
55 }
56 
Trace(double deadline)57 bool LocalEmbedderHeapTracer::Trace(double deadline) {
58   if (!InUse()) return true;
59 
60   return remote_tracer_->AdvanceTracing(deadline);
61 }
62 
IsRemoteTracingDone()63 bool LocalEmbedderHeapTracer::IsRemoteTracingDone() {
64   return !InUse() || remote_tracer_->IsTracingDone();
65 }
66 
SetEmbedderStackStateForNextFinalization(EmbedderHeapTracer::EmbedderStackState stack_state)67 void LocalEmbedderHeapTracer::SetEmbedderStackStateForNextFinalization(
68     EmbedderHeapTracer::EmbedderStackState stack_state) {
69   if (!InUse()) return;
70 
71   embedder_stack_state_ = stack_state;
72   if (EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers == stack_state) {
73     remote_tracer()->NotifyEmptyEmbedderStack();
74   }
75 }
76 
ProcessingScope(LocalEmbedderHeapTracer * tracer)77 LocalEmbedderHeapTracer::ProcessingScope::ProcessingScope(
78     LocalEmbedderHeapTracer* tracer)
79     : tracer_(tracer) {
80   wrapper_cache_.reserve(kWrapperCacheSize);
81 }
82 
~ProcessingScope()83 LocalEmbedderHeapTracer::ProcessingScope::~ProcessingScope() {
84   if (!wrapper_cache_.empty()) {
85     tracer_->remote_tracer()->RegisterV8References(std::move(wrapper_cache_));
86   }
87 }
88 
89 // static
90 LocalEmbedderHeapTracer::WrapperInfo
ExtractWrapperInfo(Isolate * isolate,JSObject js_object)91 LocalEmbedderHeapTracer::ExtractWrapperInfo(Isolate* isolate,
92                                             JSObject js_object) {
93   DCHECK_GE(js_object.GetEmbedderFieldCount(), 2);
94   DCHECK(js_object.IsApiWrapper());
95 
96   WrapperInfo info;
97   if (EmbedderDataSlot(js_object, 0)
98           .ToAlignedPointerSafe(isolate, &info.first) &&
99       info.first &&
100       EmbedderDataSlot(js_object, 1)
101           .ToAlignedPointerSafe(isolate, &info.second)) {
102     return info;
103   }
104   return {nullptr, nullptr};
105 }
106 
TracePossibleWrapper(JSObject js_object)107 void LocalEmbedderHeapTracer::ProcessingScope::TracePossibleWrapper(
108     JSObject js_object) {
109   DCHECK(js_object.IsApiWrapper());
110   if (js_object.GetEmbedderFieldCount() < 2) return;
111 
112   WrapperInfo info =
113       LocalEmbedderHeapTracer::ExtractWrapperInfo(tracer_->isolate_, js_object);
114   if (VerboseWrapperInfo(info).is_valid()) {
115     wrapper_cache_.push_back(std::move(info));
116   }
117   FlushWrapperCacheIfFull();
118 }
119 
FlushWrapperCacheIfFull()120 void LocalEmbedderHeapTracer::ProcessingScope::FlushWrapperCacheIfFull() {
121   if (wrapper_cache_.size() == wrapper_cache_.capacity()) {
122     tracer_->remote_tracer()->RegisterV8References(std::move(wrapper_cache_));
123     wrapper_cache_.clear();
124     wrapper_cache_.reserve(kWrapperCacheSize);
125   }
126 }
127 
AddWrapperInfoForTesting(WrapperInfo info)128 void LocalEmbedderHeapTracer::ProcessingScope::AddWrapperInfoForTesting(
129     WrapperInfo info) {
130   wrapper_cache_.push_back(info);
131   FlushWrapperCacheIfFull();
132 }
133 
StartIncrementalMarkingIfNeeded()134 void LocalEmbedderHeapTracer::StartIncrementalMarkingIfNeeded() {
135   if (!FLAG_global_gc_scheduling || !FLAG_incremental_marking) return;
136 
137   Heap* heap = isolate_->heap();
138   heap->StartIncrementalMarkingIfAllocationLimitIsReached(
139       heap->GCFlagsForIncrementalMarking(),
140       kGCCallbackScheduleIdleGarbageCollection);
141   if (heap->AllocationLimitOvershotByLargeMargin()) {
142     heap->FinalizeIncrementalMarkingAtomically(
143         i::GarbageCollectionReason::kExternalFinalize);
144   }
145 }
146 
147 }  // namespace internal
148 }  // namespace v8
149