Index: base/memory/weak_ptr.h |
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h |
index 3544439dd3cafc9d8cc849a2cb4181cf70d2e947..b2af3635a89d994c244e56f2786913aa47786232 100644 |
--- a/base/memory/weak_ptr.h |
+++ b/base/memory/weak_ptr.h |
@@ -96,16 +96,59 @@ class BASE_EXPORT WeakReference { |
public: |
Flag(); |
- void Invalidate(); |
- bool IsValid() const; |
+ // 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 |
+ // 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.
|
+ // any other Flag object, but it is invalidated already from the start, and |
+ // its refcount will never reach zero. |
+ static Flag* NullFlag(); |
+ |
+ void Invalidate() { |
+#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; |
+ } |
+ // The flag being invalidated with a single ref implies that there are no |
+ // weak pointers in existence. Allow deletion on other thread in this |
+ // case. |
+ DCHECK(sequence_checker_.CalledOnValidSequence() || HasOneRef()) |
+ << "WeakPtrs must be invalidated on the same sequenced thread."; |
+#endif |
+ is_valid_ = 0; |
+ } |
+ |
+ // 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_; |
- bool is_valid_; |
+#endif |
}; |
WeakReference(); |
@@ -117,9 +160,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 +176,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(); |
@@ -222,7 +267,13 @@ class WeakPtr : public internal::WeakPtrBase { |
WeakPtr(WeakPtr<U>&& other) |
: WeakPtrBase(std::move(other)), ptr_(other.ptr_) {} |
- T* get() const { return ref_.is_valid() ? ptr_ : nullptr; } |
+ T* get() const { |
+ // 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() & |
+ reinterpret_cast<uintptr_t>(ptr_)); |
+ } |
T& operator*() const { |
DCHECK(get() != nullptr); |