1// Copyright 2022 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/reference-summarizer.h"
6
7#include "src/heap/mark-compact-inl.h"
8#include "src/heap/marking-visitor-inl.h"
9#include "src/objects/embedder-data-array-inl.h"
10#include "src/objects/js-array-buffer-inl.h"
11
12namespace v8 {
13namespace internal {
14
15namespace {
16
17// A class which acts as a MarkingState but does not actually update any marking
18// bits. It reports all objects as white and all transitions as successful. It
19// also tracks which objects are retained by the primary object according to the
20// marking visitor.
21class ReferenceSummarizerMarkingState final {
22 public:
23  // Declares that this marking state is collecting retainers, so the marking
24  // visitor must fully visit each object and can't update on-heap state.
25  static constexpr bool kCollectRetainers = true;
26
27  explicit ReferenceSummarizerMarkingState(HeapObject object)
28      : primary_object_(object),
29        local_marking_worklists_(&marking_worklists_),
30        local_weak_objects_(&weak_objects_) {}
31
32  ~ReferenceSummarizerMarkingState() {
33    // Clean up temporary state.
34    local_weak_objects_.Publish();
35    weak_objects_.Clear();
36    local_marking_worklists_.Publish();
37    marking_worklists_.Clear();
38  }
39
40  // Retrieves the references that were collected by this marker. This operation
41  // transfers ownership of the set, so calling it again would yield an empty
42  // result.
43  ReferenceSummary DestructivelyRetrieveReferences() {
44    ReferenceSummary tmp = std::move(references_);
45    references_.Clear();
46    return tmp;
47  }
48
49  // Standard marking visitor functions:
50
51  bool IsWhite(HeapObject obj) const { return true; }
52
53  bool IsBlackOrGrey(HeapObject obj) const { return false; }
54
55  bool WhiteToGrey(HeapObject obj) { return true; }
56
57  bool GreyToBlack(HeapObject obj) { return true; }
58
59  // Adds a retaining relationship found by the marking visitor.
60  void AddStrongReferenceForReferenceSummarizer(HeapObject host,
61                                                HeapObject obj) {
62    AddReference(host, obj, references_.strong_references());
63  }
64
65  // Adds a non-retaining weak reference found by the marking visitor. The value
66  // in an ephemeron hash table entry is also included here, since it is not
67  // known to be strong without further information about the key.
68  void AddWeakReferenceForReferenceSummarizer(HeapObject host, HeapObject obj) {
69    AddReference(host, obj, references_.weak_references());
70  }
71
72  // Other member functions, not part of the marking visitor contract:
73
74  MarkingWorklists::Local* local_marking_worklists() {
75    return &local_marking_worklists_;
76  }
77  WeakObjects::Local* local_weak_objects() { return &local_weak_objects_; }
78
79 private:
80  void AddReference(
81      HeapObject host, HeapObject obj,
82      std::unordered_set<HeapObject, Object::Hasher>& references) {
83    // It's possible that the marking visitor handles multiple objects at once,
84    // such as a Map and its DescriptorArray, but we're only interested in
85    // references from the primary object.
86    if (host == primary_object_) {
87      references.insert(obj);
88    }
89  }
90
91  ReferenceSummary references_;
92  HeapObject primary_object_;
93  MarkingWorklists marking_worklists_;
94  MarkingWorklists::Local local_marking_worklists_;
95  WeakObjects weak_objects_;
96  WeakObjects::Local local_weak_objects_;
97};
98
99}  // namespace
100
101ReferenceSummary ReferenceSummary::SummarizeReferencesFrom(Heap* heap,
102                                                           HeapObject obj) {
103  ReferenceSummarizerMarkingState marking_state(obj);
104
105  MainMarkingVisitor<ReferenceSummarizerMarkingState> visitor(
106      &marking_state, marking_state.local_marking_worklists(),
107      marking_state.local_weak_objects(), heap, 0 /*mark_compact_epoch*/,
108      {} /*code_flush_mode*/, false /*embedder_tracing_enabled*/,
109      true /*should_keep_ages_unchanged*/);
110  visitor.Visit(obj.map(heap->isolate()), obj);
111
112  return marking_state.DestructivelyRetrieveReferences();
113}
114
115}  // namespace internal
116}  // namespace v8
117