File: heap_observer_list.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (139 lines) | stat: -rw-r--r-- 5,004 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_

#include "base/auto_reset.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"

namespace blink {

// A list of observers. Ensures list is not mutated while iterating. Observers
// are not retained by the list. The implementation favors performance of
// iteration instead of modifications.
template <class ObserverType>
class PLATFORM_EXPORT HeapObserverList final {
  DISALLOW_NEW();

 public:
  // Add an observer to this list. An observer must not be added to the same
  // list more than once. Adding an observer is O(n).
  void AddObserver(ObserverType* observer) {
    CHECK(mutation_state_ & kAllowAddition);
    DCHECK(!HasObserver(observer));
    observers_.push_back(observer);
    if (check_capacity_) [[unlikely]] {
      // On first addition after GC, check whether we need to shrink to a
      // reasoanble capacity.
      observers_.ShrinkToReasonableCapacity();
      check_capacity_ = false;
    }
  }

  // Removes the given observer from this list. Does nothing if this observer is
  // not in this list. Removing an observer is O(n).
  void RemoveObserver(ObserverType* observer) {
    CHECK(mutation_state_ & kAllowRemoval);
    const auto it = std::find(observers_.begin(), observers_.end(), observer);
    if (it != observers_.end()) {
      observers_.erase(it);
    }
  }

  // Determine whether a particular observer is in the list. Checking
  // containment is O(n).
  bool HasObserver(ObserverType* observer) const {
    DCHECK(!IsIteratingOverObservers());
    return observers_.Contains(observer);
  }

  // Returns true if the list is being iterated over.
  bool IsIteratingOverObservers() const { return mutation_state_ != kAllowAll; }

  // Removes all the observers from this list.
  void Clear() {
    CHECK(mutation_state_ & kAllowRemoval);
    observers_.clear();
  }

  // Iterate over the registered lifecycle observers in an unpredictable order.
  //
  // Adding or removing observers is not allowed during iteration. The callable
  // will be called synchronously inside `ForEachObserver()`.
  //
  // Sample usage:
  //     ForEachObserver([](ObserverType* observer) {
  //       observer->SomeMethod();
  //     });
  template <typename ForEachCallable>
  void ForEachObserver(const ForEachCallable& callable) const {
    base::AutoReset<MutationState> scope(&mutation_state_, kNoMutationAllowed);
    for (ObserverType* observer : observers_) {
      // See CleanupDeadObservers() for why we can receive nullptr here.
      if (observer) {
        callable(observer);
      }
    }
  }

  void Trace(Visitor* visitor) const {
    visitor->Trace(observers_);
    visitor->RegisterWeakCallbackMethod<
        HeapObserverList, &HeapObserverList::CleanupDeadObservers>(this);
  }

 private:
  // HeapVector doesn't allow WeakMember at this point. Instead, use a
  // UntracedMember with a custom weak callback.
  using ObserverList = HeapVector<UntracedMember<ObserverType>>;

  void CleanupDeadObservers(const LivenessBroker& broker) {
    // This method must not allocate.

    // The GC currently does not strongify UntracedMember, even during
    // iteration. This implies that we must not move around items as using the
    // erase/remove_if pattern may move a valid object in a slot where we just
    // retrieved a nullptr.
    if (mutation_state_ == kNoMutationAllowed) {
      for (auto& observer : observers_) {
        if (!broker.IsHeapObjectAlive(observer)) {
          observer.Clear();
        }
      }
    } else {
      // We are not iterating, so we we can prepare the backing store by moving
      // dead slots to the end. Backing store reallocations will happen during
      // addition and removal.
      observers_.erase(
          std::remove_if(observers_.begin(), observers_.end(),
                         [broker](auto& observer) {
                           return !broker.IsHeapObjectAlive(observer);
                         }),
          observers_.end());
      check_capacity_ = true;
    }
  }

  // TODO(keishi): Clean up iteration state once transition from
  // LifecycleObserver is complete.
  enum MutationState {
    kNoMutationAllowed = 0,
    kAllowAddition = 1,
    kAllowRemoval = 1 << 1,
    kAllowAll = kAllowAddition | kAllowRemoval,
  };

  // MutationState records whether mutations are allowed to the set of
  // observers. Iteration e.g. prohibits any mutations.
  mutable MutationState mutation_state_ = kAllowAll;
  bool check_capacity_ = false;
  ObserverList observers_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_