Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(327)

Side by Side Diff: base/memory/weak_ptr.h

Issue 2963623002: Make base::WeakPtr::Get() fast (Closed)
Patch Set: address review comments Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | base/memory/weak_ptr.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Weak pointers are pointers to an object that do not affect its lifetime, 5 // Weak pointers are pointers to an object that do not affect its lifetime,
6 // and which may be invalidated (i.e. reset to nullptr) by the object, or its 6 // and which may be invalidated (i.e. reset to nullptr) by the object, or its
7 // owner, at any time, most commonly when the object is about to be deleted. 7 // owner, at any time, most commonly when the object is about to be deleted.
8 8
9 // Weak pointers are useful when an object needs to be accessed safely by one 9 // Weak pointers are useful when an object needs to be accessed safely by one
10 // or more objects other than its owner, and those callers can cope with the 10 // or more objects other than its owner, and those callers can cope with the
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 // DO NOT USE THESE CLASSES DIRECTLY YOURSELF. 89 // DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
90 90
91 class BASE_EXPORT WeakReference { 91 class BASE_EXPORT WeakReference {
92 public: 92 public:
93 // Although Flag is bound to a specific SequencedTaskRunner, it may be 93 // Although Flag is bound to a specific SequencedTaskRunner, it may be
94 // deleted from another via base::WeakPtr::~WeakPtr(). 94 // deleted from another via base::WeakPtr::~WeakPtr().
95 class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> { 95 class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> {
96 public: 96 public:
97 Flag(); 97 Flag();
98 98
99 void Invalidate(); 99 // Get a pointer to the "Null Flag", a sentinel object used by WeakReference
100 bool IsValid() const; 100 // objects that don't point to a valid Flag, either because they're default
101 // consturcted or because they have been invalidated. This can be used like
Nico 2017/06/28 20:57:03 typo consturcted
hans 2017/06/28 21:16:59 Done.
102 // any other Flag object, but it is invalidated already from the start, and
103 // its refcount will never reach zero.
104 static Flag* NullFlag();
105
106 void Invalidate() {
107 #if DCHECK_IS_ON()
108 if (this == NullFlag()) {
109 // The Null Flag does not participate in the sequence checks below.
110 // Since its state never changes, it can be accessed from any thread.
111 DCHECK(!is_valid_);
112 return;
113 }
114 // The flag being invalidated with a single ref implies that there are no
115 // weak pointers in existence. Allow deletion on other thread in this
116 // case.
117 DCHECK(sequence_checker_.CalledOnValidSequence() || HasOneRef())
118 << "WeakPtrs must be invalidated on the same sequenced thread.";
119 #endif
120 is_valid_ = 0;
121 }
122
123 // Returns a pointer-sized bitmask of all 1s if valid or all 0s otherwise.
124 uintptr_t IsValid() const {
125 #if DCHECK_IS_ON()
126 if (this == NullFlag()) {
127 // The Null Flag does not participate in the sequence checks below.
128 // Since its state never changes, it can be accessed from any thread.
129 DCHECK(!is_valid_);
130 return 0;
131 }
132 DCHECK(sequence_checker_.CalledOnValidSequence())
133 << "WeakPtrs must be checked on the same sequenced thread.";
134 #endif
135 return is_valid_;
136 }
101 137
102 private: 138 private:
103 friend class base::RefCountedThreadSafe<Flag>; 139 friend class base::RefCountedThreadSafe<Flag>;
104 140
141 enum NullFlagTag { kNullFlagTag };
142 Flag(NullFlagTag);
143
105 ~Flag(); 144 ~Flag();
106 145
146 uintptr_t is_valid_;
147 #if DCHECK_IS_ON()
148 // Even if SequenceChecker is an empty class in non-dcheck builds, it still
149 // takes up space in the class.
107 SequenceChecker sequence_checker_; 150 SequenceChecker sequence_checker_;
108 bool is_valid_; 151 #endif
109 }; 152 };
110 153
111 WeakReference(); 154 WeakReference();
112 explicit WeakReference(const Flag* flag); 155 explicit WeakReference(const Flag* flag);
113 ~WeakReference(); 156 ~WeakReference();
114 157
115 WeakReference(WeakReference&& other); 158 WeakReference(WeakReference&& other);
116 WeakReference(const WeakReference& other); 159 WeakReference(const WeakReference& other);
117 WeakReference& operator=(WeakReference&& other) = default; 160 WeakReference& operator=(WeakReference&& other) = default;
118 WeakReference& operator=(const WeakReference& other) = default; 161 WeakReference& operator=(const WeakReference& other) = default;
119 162
120 bool is_valid() const; 163 uintptr_t is_valid() const { return flag_->IsValid(); }
121 164
122 private: 165 private:
166 // Note: To avoid null-checks, flag_ always points to either Flag::NullFlag()
167 // or some other object.
123 scoped_refptr<const Flag> flag_; 168 scoped_refptr<const Flag> flag_;
124 }; 169 };
125 170
126 class BASE_EXPORT WeakReferenceOwner { 171 class BASE_EXPORT WeakReferenceOwner {
127 public: 172 public:
128 WeakReferenceOwner(); 173 WeakReferenceOwner();
129 ~WeakReferenceOwner(); 174 ~WeakReferenceOwner();
130 175
131 WeakReference GetRef() const; 176 WeakReference GetRef() const;
132 177
133 bool HasRefs() const { 178 bool HasRefs() const {
134 return flag_.get() && !flag_->HasOneRef(); 179 return flag_ != WeakReference::Flag::NullFlag() && !flag_->HasOneRef();
135 } 180 }
136 181
137 void Invalidate(); 182 void Invalidate();
138 183
139 private: 184 private:
140 mutable scoped_refptr<WeakReference::Flag> flag_; 185 mutable scoped_refptr<WeakReference::Flag> flag_;
141 }; 186 };
142 187
143 // This class simplifies the implementation of WeakPtr's type conversion 188 // This class simplifies the implementation of WeakPtr's type conversion
144 // constructor by avoiding the need for a public accessor for ref_. A 189 // constructor by avoiding the need for a public accessor for ref_. A
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 260
216 // Allow conversion from U to T provided U "is a" T. Note that this 261 // Allow conversion from U to T provided U "is a" T. Note that this
217 // is separate from the (implicit) copy and move constructors. 262 // is separate from the (implicit) copy and move constructors.
218 template <typename U> 263 template <typename U>
219 WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) { 264 WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) {
220 } 265 }
221 template <typename U> 266 template <typename U>
222 WeakPtr(WeakPtr<U>&& other) 267 WeakPtr(WeakPtr<U>&& other)
223 : WeakPtrBase(std::move(other)), ptr_(other.ptr_) {} 268 : WeakPtrBase(std::move(other)), ptr_(other.ptr_) {}
224 269
225 T* get() const { return ref_.is_valid() ? ptr_ : nullptr; } 270 T* get() const {
271 // Intentionally bitwise and; see command on Flag::IsValid(). This provides
272 // a fast way of conditionally retrieving the pointer, and conveniently sets
273 // EFLAGS for any null-check performed by the caller.
274 return reinterpret_cast<T*>(ref_.is_valid() &
275 reinterpret_cast<uintptr_t>(ptr_));
276 }
226 277
227 T& operator*() const { 278 T& operator*() const {
228 DCHECK(get() != nullptr); 279 DCHECK(get() != nullptr);
229 return *get(); 280 return *get();
230 } 281 }
231 T* operator->() const { 282 T* operator->() const {
232 DCHECK(get() != nullptr); 283 DCHECK(get() != nullptr);
233 return get(); 284 return get();
234 } 285 }
235 286
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 // base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails. 403 // base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails.
353 404
354 template <typename Derived> 405 template <typename Derived>
355 WeakPtr<Derived> AsWeakPtr(Derived* t) { 406 WeakPtr<Derived> AsWeakPtr(Derived* t) {
356 return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t); 407 return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t);
357 } 408 }
358 409
359 } // namespace base 410 } // namespace base
360 411
361 #endif // BASE_MEMORY_WEAK_PTR_H_ 412 #endif // BASE_MEMORY_WEAK_PTR_H_
OLDNEW
« no previous file with comments | « no previous file | base/memory/weak_ptr.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698