blob: 90f0715febeddea34f7147cad55575d39d2ef77e [file] [edit]
/*
* Copyright (C) 2025 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#pragma once
#include <wtf/RefCountDebugger.h>
namespace WTF {
// This base class holds the non-template methods and attributes.
// The RefCountedWithInlineWeakPtr class inherits from it reducing the template bloat
// generated by the compiler (technique called template hoisting).
class WTF_EMPTY_BASE_CLASS RefCountedWithInlineWeakPtrBase {
public:
void ref() const
{
m_refCountDebugger.willRef(m_strongCount);
++m_strongCount;
}
bool hasOneRef() const { return m_strongCount == 1; }
unsigned refCount() const { return m_strongCount; }
void weakRef() const { ++m_weakCount; }
RefCountDebugger& refCountDebugger() const { return const_cast<RefCountDebugger&>(m_refCountDebugger); }
protected:
RefCountedWithInlineWeakPtrBase() = default;
~RefCountedWithInlineWeakPtrBase()
{
m_refCountDebugger.willDestroy(m_strongCount);
RELEASE_ASSERT(m_strongCount == 1);
// Use volatile to prevent compilers from eliminating this code. <https://webkit.org/b/304549>
*static_cast<volatile unsigned*>(&m_strongCount) = 0;
}
// Returns true if the pointer should be destroyed.
bool derefBase() const
{
m_refCountDebugger.willDeref(m_strongCount);
if (m_strongCount != 1) {
--m_strongCount;
return false;
}
m_refCountDebugger.willDelete();
return true;
}
// Returns true if the pointer should be freed.
bool weakDerefBase() const
{
// FIXME: The macros allow builds to succeed, but a proper fix would better; see https://bugs.webkit.org/show_bug.cgi?id=318247
IGNORE_GCC_WARNINGS_BEGIN("uninitialized")
if (m_weakCount != 1) {
--m_weakCount;
return false;
}
IGNORE_GCC_WARNINGS_END
return true;
}
private:
mutable unsigned m_strongCount { 1 };
mutable unsigned m_weakCount { 1 }; // The strong counts collectively share one weak count.
NO_UNIQUE_ADDRESS RefCountDebugger m_refCountDebugger;
};
template<typename T> class RefCountedWithInlineWeakPtr : public RefCountedWithInlineWeakPtrBase {
WTF_MAKE_NONCOPYABLE(RefCountedWithInlineWeakPtr);
WTF_DEPRECATED_MAKE_FAST_ALLOCATED(RefCountedWithInlineWeakPtr);
public:
RefCountedWithInlineWeakPtr() = default;
void deref() const
{
if (!derefBase()) [[likely]]
return;
derefSlowCase();
}
void weakDeref() const
{
if (!weakDerefBase()) [[likely]]
return;
weakDerefSlowCase();
}
private:
void derefSlowCase() const;
void weakDerefSlowCase() const;
} SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT;
template<typename T> void RefCountedWithInlineWeakPtr<T>::derefSlowCase() const
{
const_cast<T*>(static_cast<const T*>(this))->~T();
weakDeref();
}
template<typename T> void RefCountedWithInlineWeakPtr<T>::weakDerefSlowCase() const
{
T::operator delete(const_cast<T*>(static_cast<const T*>(this)));
}
inline void adopted(RefCountedWithInlineWeakPtrBase* object)
{
if (!object)
return;
object->refCountDebugger().adopted();
}
} // namespace WTF
using WTF::RefCountedWithInlineWeakPtr;