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 { |