Commit 0698f106 authored by hlopko's avatar hlopko Committed by Commit bot

Introduce EmbedderReachableReferenceReporter

This cl introduces reporter to the embedder heap tracer. Heap tracer uses
reporter to report reachable objects from embedder heap. This refactoring is a
step towards being able to take heap snapshots with wrapper tracing.

LOG=no
BUG=468240

Review-Url: https://codereview.chromium.org/2371733002
Cr-Commit-Position: refs/heads/master@{#39824}
parent 8d8c134b
......@@ -206,14 +206,19 @@ class PersistentValueMapBase {
}
/**
* Call V8::RegisterExternallyReferencedObject with the map value for given
* key.
* Deprecated. Call V8::RegisterExternallyReferencedObject with the map value
* for given key.
* TODO(hlopko) Remove once migration to reporter is finished.
*/
void RegisterExternallyReferencedObject(K& key) {
void RegisterExternallyReferencedObject(K& key) {}
/**
* Use EmbedderReachableReferenceReporter with the map value for given key.
*/
void RegisterExternallyReferencedObject(
EmbedderReachableReferenceReporter* reporter, K& key) {
DCHECK(Contains(key));
V8::RegisterExternallyReferencedObject(
reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))),
reinterpret_cast<internal::Isolate*>(GetIsolate()));
reporter->ReportExternalReference(FromVal(Traits::Get(&impl_, key)));
}
/**
......
......@@ -467,6 +467,16 @@ class WeakCallbackInfo {
// possible to request a second pass callback.
enum class WeakCallbackType { kParameter, kInternalFields, kFinalizer };
/**
* A reporter class that embedder will use to report reachable references found
* by EmbedderHeapTracer.
*/
class V8_EXPORT EmbedderReachableReferenceReporter {
public:
virtual void ReportExternalReference(Value* object) = 0;
virtual ~EmbedderReachableReferenceReporter() = default;
};
/**
* An object reference that is independent of any handle scope. Where
* a Local handle only lives as long as the HandleScope in which it was
......@@ -563,12 +573,19 @@ template <class T> class PersistentBase {
// TODO(dcarney): remove this.
V8_INLINE void ClearWeak() { ClearWeak<void>(); }
/**
* Deprecated.
* TODO(hlopko): remove once migration to reporter is finished.
*/
V8_INLINE void RegisterExternalReference(Isolate* isolate) const {}
/**
* Allows the embedder to tell the v8 garbage collector that a certain object
* is alive. Only allowed when the embedder is asked to trace its heap by
* EmbedderHeapTracer.
*/
V8_INLINE void RegisterExternalReference(Isolate* isolate) const;
V8_INLINE void RegisterExternalReference(
EmbedderReachableReferenceReporter* reporter) const;
/**
* Marks the reference to this object independent. Garbage collector is free
......@@ -6129,8 +6146,8 @@ enum class MemoryPressureLevel { kNone, kModerate, kCritical };
* Interface for tracing through the embedder heap. During the v8 garbage
* collection, v8 collects hidden fields of all potential wrappers, and at the
* end of its marking phase iterates the collection and asks the embedder to
* trace through its heap and call PersistentBase::RegisterExternalReference on
* each js object reachable from any of the given wrappers.
* trace through its heap and use reporter to report each js object reachable
* from any of the given wrappers.
*
* Before the first call to the TraceWrappersFrom function TracePrologue will be
* called. When the garbage collection cycle is finished, TraceEpilogue will be
......@@ -6156,14 +6173,21 @@ class V8_EXPORT EmbedderHeapTracer {
const std::vector<std::pair<void*, void*> >& internal_fields) = 0;
/**
* V8 will call this method at the beginning of a GC cycle.
* Deprecated.
* TODO(hlopko) Remove once the migration to reporter is finished.
*/
virtual void TracePrologue() {}
/**
* V8 will call this method at the beginning of a GC cycle. Embedder is
* expected to use EmbedderReachableReferenceReporter for reporting all
* reachable v8 objects.
*/
virtual void TracePrologue() = 0;
virtual void TracePrologue(EmbedderReachableReferenceReporter* reporter) {}
/**
* Embedder is expected to trace its heap starting from wrappers reported by
* RegisterV8References method, and call
* PersistentBase::RegisterExternalReference() on all reachable wrappers.
* RegisterV8References method, and use reporter for all reachable wrappers.
* Embedder is expected to stop tracing by the given deadline.
*
* Returns true if there is still work to do.
......@@ -7480,8 +7504,6 @@ class V8_EXPORT V8 {
int* index);
static Local<Value> GetEternal(Isolate* isolate, int index);
static void RegisterExternallyReferencedObject(internal::Object** object,
internal::Isolate* isolate);
template <class K, class V, class T>
friend class PersistentValueMapBase;
......@@ -8542,11 +8564,10 @@ P* PersistentBase<T>::ClearWeak() {
}
template <class T>
void PersistentBase<T>::RegisterExternalReference(Isolate* isolate) const {
void PersistentBase<T>::RegisterExternalReference(
EmbedderReachableReferenceReporter* reporter) const {
if (IsEmpty()) return;
V8::RegisterExternallyReferencedObject(
reinterpret_cast<internal::Object**>(this->val_),
reinterpret_cast<internal::Isolate*>(isolate));
reporter->ReportExternalReference(this->val_);
}
template <class T>
......
......@@ -786,11 +786,6 @@ i::Object** V8::CopyPersistent(i::Object** obj) {
return result.location();
}
void V8::RegisterExternallyReferencedObject(i::Object** object,
i::Isolate* isolate) {
isolate->heap()->RegisterExternallyReferencedObject(object);
}
void V8::MakeWeak(i::Object** location, void* parameter,
int internal_field_index1, int internal_field_index2,
WeakCallbackInfo<void>::Callback weak_callback) {
......
......@@ -156,6 +156,8 @@ Heap::Heap()
deserialization_complete_(false),
strong_roots_list_(NULL),
heap_iterator_depth_(0),
embedder_heap_tracer_(nullptr),
embedder_reference_reporter_(new TracePossibleWrapperReporter(this)),
force_oom_(false) {
// Allow build-time customization of the max semispace size. Building
// V8 with snapshots and a non-default max semispace size is much
......@@ -1622,7 +1624,7 @@ void Heap::Scavenge() {
// Register found wrappers with embedder so it can add them to its marking
// deque and correctly manage the case when v8 scavenger collects the
// wrappers by either keeping wrappables alive, or cleaning marking deque.
mark_compact_collector()->RegisterWrappersWithEmbedderHeapTracer();
RegisterWrappersWithEmbedderHeapTracer();
}
// Flip the semispaces. After flipping, to space is empty, from space has
......@@ -4220,10 +4222,8 @@ void Heap::ReduceNewSpaceSize() {
bool Heap::MarkingDequesAreEmpty() {
return mark_compact_collector()->marking_deque()->IsEmpty() &&
(!UsingEmbedderHeapTracer() ||
(mark_compact_collector()->wrappers_to_trace() == 0 &&
mark_compact_collector()
->embedder_heap_tracer()
->NumberOfWrappersToTrace() == 0));
(wrappers_to_trace() == 0 &&
embedder_heap_tracer()->NumberOfWrappersToTrace() == 0));
}
void Heap::FinalizeIncrementalMarkingIfComplete(
......@@ -5554,15 +5554,36 @@ void Heap::NotifyDeserializationComplete() {
}
void Heap::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) {
mark_compact_collector()->SetEmbedderHeapTracer(tracer);
DCHECK_NOT_NULL(tracer);
CHECK_NULL(embedder_heap_tracer_);
embedder_heap_tracer_ = tracer;
}
bool Heap::UsingEmbedderHeapTracer() {
return mark_compact_collector()->UsingEmbedderHeapTracer();
void Heap::RegisterWrappersWithEmbedderHeapTracer() {
DCHECK(UsingEmbedderHeapTracer());
if (wrappers_to_trace_.empty()) {
return;
}
embedder_heap_tracer()->RegisterV8References(wrappers_to_trace_);
wrappers_to_trace_.clear();
}
void Heap::TracePossibleWrapper(JSObject* js_object) {
mark_compact_collector()->TracePossibleWrapper(js_object);
DCHECK(js_object->WasConstructedFromApiFunction());
if (js_object->GetInternalFieldCount() >= 2 &&
js_object->GetInternalField(0) &&
js_object->GetInternalField(0) != undefined_value() &&
js_object->GetInternalField(1) != undefined_value()) {
DCHECK(reinterpret_cast<intptr_t>(js_object->GetInternalField(0)) % 2 == 0);
wrappers_to_trace_.push_back(std::pair<void*, void*>(
reinterpret_cast<void*>(js_object->GetInternalField(0)),
reinterpret_cast<void*>(js_object->GetInternalField(1))));
}
}
bool Heap::RequiresImmediateWrapperProcessing() {
const size_t kTooManyWrappers = 16000;
return wrappers_to_trace_.size() > kTooManyWrappers;
}
void Heap::RegisterExternallyReferencedObject(Object** object) {
......@@ -5693,6 +5714,9 @@ void Heap::TearDown() {
delete memory_allocator_;
memory_allocator_ = nullptr;
delete embedder_reference_reporter_;
embedder_reference_reporter_ = nullptr;
}
......
......@@ -337,6 +337,7 @@ class Scavenger;
class ScavengeJob;
class Space;
class StoreBuffer;
class TracePossibleWrapperReporter;
class WeakObjectRetainer;
typedef void (*ObjectSlotCallback)(HeapObject** from, HeapObject* to);
......@@ -1204,12 +1205,26 @@ class Heap {
void SetEmbedderHeapTracer(EmbedderHeapTracer* tracer);
bool UsingEmbedderHeapTracer();
bool UsingEmbedderHeapTracer() { return embedder_heap_tracer(); }
void TracePossibleWrapper(JSObject* js_object);
void RegisterExternallyReferencedObject(Object** object);
void RegisterWrappersWithEmbedderHeapTracer();
// In order to avoid running out of memory we force tracing wrappers if there
// are too many of them.
bool RequiresImmediateWrapperProcessing();
EmbedderHeapTracer* embedder_heap_tracer() { return embedder_heap_tracer_; }
EmbedderReachableReferenceReporter* embedder_reachable_reference_reporter() {
return embedder_reference_reporter_;
}
size_t wrappers_to_trace() { return wrappers_to_trace_.size(); }
// ===========================================================================
// External string table API. ================================================
// ===========================================================================
......@@ -2296,6 +2311,10 @@ class Heap {
// The depth of HeapIterator nestings.
int heap_iterator_depth_;
EmbedderHeapTracer* embedder_heap_tracer_;
EmbedderReachableReferenceReporter* embedder_reference_reporter_;
std::vector<std::pair<void*, void*>> wrappers_to_trace_;
// Used for testing purposes.
bool force_oom_;
......@@ -2613,6 +2632,18 @@ class AllocationObserver {
DISALLOW_COPY_AND_ASSIGN(AllocationObserver);
};
class TracePossibleWrapperReporter : public EmbedderReachableReferenceReporter {
public:
explicit TracePossibleWrapperReporter(Heap* heap) : heap_(heap) {}
void ReportExternalReference(Value* object) override {
heap_->RegisterExternallyReferencedObject(
reinterpret_cast<Object**>(object));
}
private:
Heap* heap_;
};
} // namespace internal
} // namespace v8
......
......@@ -569,7 +569,8 @@ void IncrementalMarking::StartMarking() {
if (heap_->UsingEmbedderHeapTracer()) {
TRACE_GC(heap()->tracer(),
GCTracer::Scope::MC_INCREMENTAL_WRAPPER_PROLOGUE);
heap_->mark_compact_collector()->embedder_heap_tracer()->TracePrologue();
heap_->embedder_heap_tracer()->TracePrologue(
heap_->embedder_reachable_reference_reporter());
}
RecordWriteStub::Mode mode = is_compacting_
......@@ -796,8 +797,7 @@ void IncrementalMarking::FinalizeIncrementally() {
abs(old_marking_deque_top -
heap_->mark_compact_collector()->marking_deque()->top());
marking_progress +=
static_cast<int>(heap_->mark_compact_collector()->wrappers_to_trace());
marking_progress += static_cast<int>(heap_->wrappers_to_trace());
double end = heap_->MonotonicallyIncreasingTimeInMs();
double delta = end - start;
......@@ -1224,8 +1224,7 @@ void IncrementalMarking::Step(intptr_t bytes_to_process,
FLAG_incremental_marking_wrappers && heap_->UsingEmbedderHeapTracer();
const bool process_wrappers =
incremental_wrapper_tracing &&
(heap_->mark_compact_collector()
->RequiresImmediateWrapperProcessing() ||
(heap_->RequiresImmediateWrapperProcessing() ||
heap_->mark_compact_collector()->marking_deque()->IsEmpty());
bool wrapper_work_left = incremental_wrapper_tracing;
if (!process_wrappers) {
......@@ -1246,14 +1245,11 @@ void IncrementalMarking::Step(intptr_t bytes_to_process,
heap_->MonotonicallyIncreasingTimeInMs() + kStepSizeInMs;
TRACE_GC(heap()->tracer(),
GCTracer::Scope::MC_INCREMENTAL_WRAPPER_TRACING);
heap_->mark_compact_collector()->RegisterWrappersWithEmbedderHeapTracer();
wrapper_work_left =
heap_->mark_compact_collector()
->embedder_heap_tracer()
->AdvanceTracing(wrapper_deadline,
EmbedderHeapTracer::AdvanceTracingActions(
EmbedderHeapTracer::ForceCompletionAction::
DO_NOT_FORCE_COMPLETION));
heap_->RegisterWrappersWithEmbedderHeapTracer();
wrapper_work_left = heap_->embedder_heap_tracer()->AdvanceTracing(
wrapper_deadline, EmbedderHeapTracer::AdvanceTracingActions(
EmbedderHeapTracer::ForceCompletionAction::
DO_NOT_FORCE_COMPLETION));
}
if (heap_->mark_compact_collector()->marking_deque()->IsEmpty() &&
......
......@@ -61,7 +61,6 @@ MarkCompactCollector::MarkCompactCollector(Heap* heap)
marking_deque_memory_(NULL),
marking_deque_memory_committed_(0),
code_flusher_(nullptr),
embedder_heap_tracer_(nullptr),
sweeper_(heap) {
}
......@@ -809,7 +808,7 @@ void MarkCompactCollector::Prepare() {
AbortTransitionArrays();
AbortCompaction();
if (heap_->UsingEmbedderHeapTracer()) {
heap_->mark_compact_collector()->embedder_heap_tracer()->AbortTracing();
heap_->embedder_heap_tracer()->AbortTracing();
}
was_marked_incrementally_ = false;
}
......@@ -817,12 +816,13 @@ void MarkCompactCollector::Prepare() {
if (!was_marked_incrementally_) {
if (heap_->UsingEmbedderHeapTracer()) {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_PROLOGUE);
heap_->mark_compact_collector()->embedder_heap_tracer()->TracePrologue();
heap_->embedder_heap_tracer()->TracePrologue(
heap_->embedder_reachable_reference_reporter());
}
}
if (UsingEmbedderHeapTracer()) {
embedder_heap_tracer()->EnterFinalPause();
if (heap_->UsingEmbedderHeapTracer()) {
heap_->embedder_heap_tracer()->EnterFinalPause();
}
// Don't start compaction if we are in the middle of incremental
......@@ -2085,10 +2085,10 @@ void MarkCompactCollector::ProcessEphemeralMarking(
DCHECK(marking_deque_.IsEmpty() && !marking_deque_.overflowed());
bool work_to_do = true;
while (work_to_do) {
if (UsingEmbedderHeapTracer()) {
if (heap_->UsingEmbedderHeapTracer()) {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_TRACING);
RegisterWrappersWithEmbedderHeapTracer();
embedder_heap_tracer()->AdvanceTracing(
heap_->RegisterWrappersWithEmbedderHeapTracer();
heap_->embedder_heap_tracer()->AdvanceTracing(
0, EmbedderHeapTracer::AdvanceTracingActions(
EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION));
}
......@@ -2202,39 +2202,6 @@ void MarkingDeque::Uninitialize(bool aborting) {
in_use_ = false;
}
void MarkCompactCollector::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) {
DCHECK_NOT_NULL(tracer);
CHECK_NULL(embedder_heap_tracer_);
embedder_heap_tracer_ = tracer;
}
bool MarkCompactCollector::RequiresImmediateWrapperProcessing() {
const size_t kTooManyWrappers = 16000;
return wrappers_to_trace_.size() > kTooManyWrappers;
}
void MarkCompactCollector::RegisterWrappersWithEmbedderHeapTracer() {
DCHECK(UsingEmbedderHeapTracer());
if (wrappers_to_trace_.empty()) {
return;
}
embedder_heap_tracer()->RegisterV8References(wrappers_to_trace_);
wrappers_to_trace_.clear();
}
void MarkCompactCollector::TracePossibleWrapper(JSObject* js_object) {
DCHECK(js_object->WasConstructedFromApiFunction());
if (js_object->GetInternalFieldCount() >= 2 &&
js_object->GetInternalField(0) &&
js_object->GetInternalField(0) != heap_->undefined_value() &&
js_object->GetInternalField(1) != heap_->undefined_value()) {
DCHECK(reinterpret_cast<intptr_t>(js_object->GetInternalField(0)) % 2 == 0);
wrappers_to_trace_.push_back(std::pair<void*, void*>(
reinterpret_cast<void*>(js_object->GetInternalField(0)),
reinterpret_cast<void*>(js_object->GetInternalField(1))));
}
}
class MarkCompactCollector::ObjectStatsVisitor
: public MarkCompactCollector::HeapObjectVisitor {
public:
......@@ -2373,9 +2340,9 @@ void MarkCompactCollector::MarkLiveObjects() {
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WEAK_CLOSURE_HARMONY);
ProcessEphemeralMarking(&root_visitor, true);
if (UsingEmbedderHeapTracer()) {
if (heap_->UsingEmbedderHeapTracer()) {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_EPILOGUE);
embedder_heap_tracer()->TraceEpilogue();
heap()->embedder_heap_tracer()->TraceEpilogue();
}
}
}
......
......@@ -490,24 +490,6 @@ class MarkCompactCollector {
Sweeper& sweeper() { return sweeper_; }
// ===========================================================================
// Embedder heap tracer support. =============================================
// ===========================================================================
void SetEmbedderHeapTracer(EmbedderHeapTracer* tracer);
EmbedderHeapTracer* embedder_heap_tracer() { return embedder_heap_tracer_; }
bool UsingEmbedderHeapTracer() { return embedder_heap_tracer(); }
// In order to avoid running out of memory we force tracing wrappers if there
// are too many of them.
bool RequiresImmediateWrapperProcessing();
void RegisterWrappersWithEmbedderHeapTracer();
void TracePossibleWrapper(JSObject* js_object);
size_t wrappers_to_trace() { return wrappers_to_trace_.size(); }
private:
class EvacuateNewSpacePageVisitor;
class EvacuateNewSpaceVisitor;
......@@ -747,12 +729,9 @@ class MarkCompactCollector {
base::VirtualMemory* marking_deque_memory_;
size_t marking_deque_memory_committed_;
MarkingDeque marking_deque_;
std::vector<std::pair<void*, void*>> wrappers_to_trace_;
CodeFlusher* code_flusher_;
EmbedderHeapTracer* embedder_heap_tracer_;
List<Page*> evacuation_candidates_;
List<Page*> newspace_evacuation_candidates_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment