AK: Add RETURNS_NONNULL attribute and use it

This attribute tells compilers that the pointer returned by a function
is never null, which lets it optimize away null checks in some places.
This seems like a nice addition to `NonnullOwnPtr` and `NonnullRefPtr`.

Using this attribute causes extra UBSan checks to be emitted. To offset
its performance loss, some additional methods were marked ALWAYS_INLINE,
which lets the compiler optimize duplicate checks
This commit is contained in:
Daniel Bertalan 2021-06-29 15:45:24 +02:00 committed by Ali Mohammad Pur
parent 65b2d3add3
commit 23d66fe719
3 changed files with 29 additions and 15 deletions

View file

@ -98,17 +98,26 @@ public:
return exchange(m_ptr, nullptr);
}
T* ptr() { return m_ptr; }
const T* ptr() const { return m_ptr; }
ALWAYS_INLINE RETURNS_NONNULL T* ptr()
{
VERIFY(m_ptr);
return m_ptr;
}
T* operator->() { return m_ptr; }
const T* operator->() const { return m_ptr; }
ALWAYS_INLINE RETURNS_NONNULL const T* ptr() const
{
VERIFY(m_ptr);
return m_ptr;
}
T& operator*() { return *m_ptr; }
const T& operator*() const { return *m_ptr; }
ALWAYS_INLINE RETURNS_NONNULL T* operator->() { return ptr(); }
ALWAYS_INLINE RETURNS_NONNULL const T* operator->() const { return ptr(); }
operator const T*() const { return m_ptr; }
operator T*() { return m_ptr; }
ALWAYS_INLINE T& operator*() { return *ptr(); }
ALWAYS_INLINE const T& operator*() const { return *ptr(); }
ALWAYS_INLINE RETURNS_NONNULL operator const T*() const { return ptr(); }
ALWAYS_INLINE RETURNS_NONNULL operator T*() { return ptr(); }
operator bool() const = delete;
bool operator!() const = delete;

View file

@ -156,20 +156,20 @@ public:
return *ptr;
}
ALWAYS_INLINE T* ptr()
ALWAYS_INLINE RETURNS_NONNULL T* ptr()
{
return as_nonnull_ptr();
}
ALWAYS_INLINE const T* ptr() const
ALWAYS_INLINE RETURNS_NONNULL const T* ptr() const
{
return as_nonnull_ptr();
}
ALWAYS_INLINE T* operator->()
ALWAYS_INLINE RETURNS_NONNULL T* operator->()
{
return as_nonnull_ptr();
}
ALWAYS_INLINE const T* operator->() const
ALWAYS_INLINE RETURNS_NONNULL const T* operator->() const
{
return as_nonnull_ptr();
}
@ -183,11 +183,11 @@ public:
return *as_nonnull_ptr();
}
ALWAYS_INLINE operator T*()
ALWAYS_INLINE RETURNS_NONNULL operator T*()
{
return as_nonnull_ptr();
}
ALWAYS_INLINE operator const T*() const
ALWAYS_INLINE RETURNS_NONNULL operator const T*() const
{
return as_nonnull_ptr();
}
@ -232,7 +232,7 @@ private:
return (T*)(m_bits.load(AK::MemoryOrder::memory_order_relaxed) & ~(FlatPtr)1);
}
ALWAYS_INLINE T* as_nonnull_ptr() const
ALWAYS_INLINE RETURNS_NONNULL T* as_nonnull_ptr() const
{
T* ptr = (T*)(m_bits.load(AK::MemoryOrder::memory_order_relaxed) & ~(FlatPtr)1);
VERIFY(ptr);

View file

@ -40,6 +40,11 @@
#endif
#define FLATTEN __attribute__((flatten))
#ifdef RETURNS_NONNULL
# undef RETURNS_NONNULL
#endif
#define RETURNS_NONNULL __attribute__((returns_nonnull))
#ifdef NO_SANITIZE_ADDRESS
# undef NO_SANITIZE_ADDRESS
#endif