Chromium Code Reviews| 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 { |