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

Unified Diff: base/memory/weak_ptr.h

Issue 2963623002: Make base::WeakPtr::Get() fast (Closed)
Patch Set: Move WeakReference::Flag::Invalidate out-of-line; it's only called from WeakReferenceOwner::Invalid… 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | base/memory/weak_ptr.cc » ('j') | base/memory/weak_ptr.cc » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/memory/weak_ptr.h
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
index 5c9ed545d726a1b8d7f5c16b7ff2721f64a9dfcc..bda05a9962fd0a0bc3c4f20bd6bf0842bbb3ef9e 100644
--- a/base/memory/weak_ptr.h
+++ b/base/memory/weak_ptr.h
@@ -96,16 +96,44 @@ class BASE_EXPORT WeakReference {
public:
Flag();
+ // Get a pointer to the "Null Flag", a sentinel object used by WeakReference
+ // objects that don't point to a valid Flag, either because they're default
+ // constructed or because they have been invalidated. This can be used like
+ // any other Flag object, but it is invalidated already from the start, and
+ // its refcount will never reach zero.
+ static Flag* NullFlag();
+
void Invalidate();
- bool IsValid() const;
+
+ // Returns a pointer-sized bitmask of all 1s if valid or all 0s otherwise.
+ uintptr_t IsValid() const {
+#if DCHECK_IS_ON()
+ if (this == NullFlag()) {
+ // The Null Flag does not participate in the sequence checks below.
+ // Since its state never changes, it can be accessed from any thread.
+ DCHECK(!is_valid_);
+ return 0;
+ }
+ DCHECK(sequence_checker_.CalledOnValidSequence())
+ << "WeakPtrs must be checked on the same sequenced thread.";
+#endif
+ return is_valid_;
+ }
private:
friend class base::RefCountedThreadSafe<Flag>;
+ enum NullFlagTag { kNullFlagTag };
+ Flag(NullFlagTag);
+
~Flag();
+ uintptr_t is_valid_;
+#if DCHECK_IS_ON()
+ // Even if SequenceChecker is an empty class in non-dcheck builds, it still
+ // takes up space in the class.
SequenceChecker sequence_checker_;
gab 2017/07/18 20:31:08 You can use SEQUENCE_CHECKER() and friends macros
hans 2017/07/19 08:08:23 Done.
- bool is_valid_;
+#endif
};
WeakReference();
@@ -117,9 +145,11 @@ class BASE_EXPORT WeakReference {
WeakReference& operator=(WeakReference&& other) = default;
WeakReference& operator=(const WeakReference& other) = default;
- bool is_valid() const;
+ uintptr_t is_valid() const { return flag_->IsValid(); }
private:
+ // Note: To avoid null-checks, flag_ always points to either Flag::NullFlag()
+ // or some other object.
scoped_refptr<const Flag> flag_;
};
@@ -131,7 +161,7 @@ class BASE_EXPORT WeakReferenceOwner {
WeakReference GetRef() const;
bool HasRefs() const {
- return flag_.get() && !flag_->HasOneRef();
+ return flag_ != WeakReference::Flag::NullFlag() && !flag_->HasOneRef();
}
void Invalidate();
@@ -236,7 +266,10 @@ class WeakPtr : public internal::WeakPtrBase {
}
T* get() const {
- return ref_.is_valid() ? reinterpret_cast<T*>(ptr_) : nullptr;
+ // Intentionally bitwise and; see command on Flag::IsValid(). This provides
+ // a fast way of conditionally retrieving the pointer, and conveniently sets
+ // EFLAGS for any null-check performed by the caller.
+ return reinterpret_cast<T*>(ref_.is_valid() & ptr_);
}
T& operator*() const {
« no previous file with comments | « no previous file | base/memory/weak_ptr.cc » ('j') | base/memory/weak_ptr.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698