summaryrefslogtreecommitdiffstats
path: root/xpcom/string
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/string')
-rw-r--r--xpcom/string/moz.build3
-rw-r--r--xpcom/string/nsStringBuffer.cpp138
-rw-r--r--xpcom/string/nsStringBuffer.h93
-rw-r--r--xpcom/string/nsStringStats.cpp66
-rw-r--r--xpcom/string/nsStringStats.h32
-rw-r--r--xpcom/string/nsTLiteralString.h12
-rw-r--r--xpcom/string/nsTSubstring.cpp20
-rw-r--r--xpcom/string/nsTSubstring.h27
8 files changed, 101 insertions, 290 deletions
diff --git a/xpcom/string/moz.build b/xpcom/string/moz.build
index c0f8091b8f..1220a16bc8 100644
--- a/xpcom/string/moz.build
+++ b/xpcom/string/moz.build
@@ -56,7 +56,4 @@ UNIFIED_SOURCES += [
"RustStringAPI.cpp",
]
-if CONFIG["MOZ_DEBUG"]:
- UNIFIED_SOURCES += ["nsStringStats.cpp"]
-
FINAL_LIBRARY = "xul"
diff --git a/xpcom/string/nsStringBuffer.cpp b/xpcom/string/nsStringBuffer.cpp
index b5d506333f..fbfc91f633 100644
--- a/xpcom/string/nsStringBuffer.cpp
+++ b/xpcom/string/nsStringBuffer.cpp
@@ -7,74 +7,7 @@
#include "nsStringBuffer.h"
#include "mozilla/MemoryReporting.h"
-#include "nsISupportsImpl.h"
-#include "nsString.h"
-
-#ifdef DEBUG
-# include "nsStringStats.h"
-#else
-# define STRING_STAT_INCREMENT(_s)
-#endif
-
-void nsStringBuffer::AddRef() {
- // Memory synchronization is not required when incrementing a
- // reference count. The first increment of a reference count on a
- // thread is not important, since the first use of the object on a
- // thread can happen before it. What is important is the transfer
- // of the pointer to that thread, which may happen prior to the
- // first increment on that thread. The necessary memory
- // synchronization is done by the mechanism that transfers the
- // pointer between threads.
-#ifdef NS_BUILD_REFCNT_LOGGING
- uint32_t count =
-#endif
- mRefCount.fetch_add(1, std::memory_order_relaxed)
-#ifdef NS_BUILD_REFCNT_LOGGING
- + 1
-#endif
- ;
- STRING_STAT_INCREMENT(Share);
- NS_LOG_ADDREF(this, count, "nsStringBuffer", sizeof(*this));
-}
-
-void nsStringBuffer::Release() {
- // Since this may be the last release on this thread, we need
- // release semantics so that prior writes on this thread are visible
- // to the thread that destroys the object when it reads mValue with
- // acquire semantics.
- uint32_t count = mRefCount.fetch_sub(1, std::memory_order_release) - 1;
- NS_LOG_RELEASE(this, count, "nsStringBuffer");
- if (count == 0) {
- // We're going to destroy the object on this thread, so we need
- // acquire semantics to synchronize with the memory released by
- // the last release on other threads, that is, to ensure that
- // writes prior to that release are now visible on this thread.
- count = mRefCount.load(std::memory_order_acquire);
-
- STRING_STAT_INCREMENT(Free);
- free(this); // we were allocated with |malloc|
- }
-}
-
-/**
- * Alloc returns a pointer to a new string header with set capacity.
- */
-already_AddRefed<nsStringBuffer> nsStringBuffer::Alloc(size_t aSize) {
- NS_ASSERTION(aSize != 0, "zero capacity allocation not allowed");
- NS_ASSERTION(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) &&
- sizeof(nsStringBuffer) + aSize > aSize,
- "mStorageSize will truncate");
-
- auto* hdr = (nsStringBuffer*)malloc(sizeof(nsStringBuffer) + aSize);
- if (hdr) {
- STRING_STAT_INCREMENT(Alloc);
-
- hdr->mRefCount = 1;
- hdr->mStorageSize = aSize;
- NS_LOG_ADDREF(hdr, 1, "nsStringBuffer", sizeof(*hdr));
- }
- return already_AddRefed(hdr);
-}
+#include "mozilla/RefPtr.h"
template <typename CharT>
static already_AddRefed<nsStringBuffer> DoCreate(const CharT* aData,
@@ -101,80 +34,31 @@ already_AddRefed<nsStringBuffer> nsStringBuffer::Create(const char16_t* aData,
}
nsStringBuffer* nsStringBuffer::Realloc(nsStringBuffer* aHdr, size_t aSize) {
- STRING_STAT_INCREMENT(Realloc);
-
- NS_ASSERTION(aSize != 0, "zero capacity allocation not allowed");
- NS_ASSERTION(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) &&
- sizeof(nsStringBuffer) + aSize > aSize,
- "mStorageSize will truncate");
+ MOZ_ASSERT(aSize != 0, "zero capacity allocation not allowed");
+ MOZ_ASSERT(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) &&
+ sizeof(nsStringBuffer) + aSize > aSize,
+ "mStorageSize will truncate");
// no point in trying to save ourselves if we hit this assertion
- NS_ASSERTION(!aHdr->IsReadonly(), "|Realloc| attempted on readonly string");
+ MOZ_ASSERT(!aHdr->IsReadonly(), "|Realloc| attempted on readonly string");
// Treat this as a release and addref for refcounting purposes, since we
// just asserted that the refcount is 1. If we don't do that, refcount
// logging will claim we've leaked all sorts of stuff.
- NS_LOG_RELEASE(aHdr, 0, "nsStringBuffer");
+ {
+ mozilla::detail::RefCountLogger::ReleaseLogger logger(aHdr);
+ logger.logRelease(0);
+ }
aHdr = (nsStringBuffer*)realloc(aHdr, sizeof(nsStringBuffer) + aSize);
if (aHdr) {
- NS_LOG_ADDREF(aHdr, 1, "nsStringBuffer", sizeof(*aHdr));
+ mozilla::detail::RefCountLogger::logAddRef(aHdr, 1);
aHdr->mStorageSize = aSize;
}
return aHdr;
}
-nsStringBuffer* nsStringBuffer::FromString(const nsAString& aStr) {
- if (!(aStr.mDataFlags & nsAString::DataFlags::REFCOUNTED)) {
- return nullptr;
- }
-
- return FromData(aStr.mData);
-}
-
-nsStringBuffer* nsStringBuffer::FromString(const nsACString& aStr) {
- if (!(aStr.mDataFlags & nsACString::DataFlags::REFCOUNTED)) {
- return nullptr;
- }
-
- return FromData(aStr.mData);
-}
-
-void nsStringBuffer::ToString(uint32_t aLen, nsAString& aStr,
- bool aMoveOwnership) {
- char16_t* data = static_cast<char16_t*>(Data());
-
- MOZ_DIAGNOSTIC_ASSERT(data[aLen] == char16_t(0),
- "data should be null terminated");
-
- nsAString::DataFlags flags =
- nsAString::DataFlags::REFCOUNTED | nsAString::DataFlags::TERMINATED;
-
- if (!aMoveOwnership) {
- AddRef();
- }
- aStr.Finalize();
- aStr.SetData(data, aLen, flags);
-}
-
-void nsStringBuffer::ToString(uint32_t aLen, nsACString& aStr,
- bool aMoveOwnership) {
- char* data = static_cast<char*>(Data());
-
- MOZ_DIAGNOSTIC_ASSERT(data[aLen] == char(0),
- "data should be null terminated");
-
- nsACString::DataFlags flags =
- nsACString::DataFlags::REFCOUNTED | nsACString::DataFlags::TERMINATED;
-
- if (!aMoveOwnership) {
- AddRef();
- }
- aStr.Finalize();
- aStr.SetData(data, aLen, flags);
-}
-
size_t nsStringBuffer::SizeOfIncludingThisIfUnshared(
mozilla::MallocSizeOf aMallocSizeOf) const {
return IsReadonly() ? 0 : aMallocSizeOf(this);
diff --git a/xpcom/string/nsStringBuffer.h b/xpcom/string/nsStringBuffer.h
index 43628d6668..dad41e48f7 100644
--- a/xpcom/string/nsStringBuffer.h
+++ b/xpcom/string/nsStringBuffer.h
@@ -9,10 +9,9 @@
#include <atomic>
#include "mozilla/MemoryReporting.h"
-#include "nsStringFwd.h"
-
-template <class T>
-struct already_AddRefed;
+#include "mozilla/Assertions.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/RefCounted.h"
/**
* This structure precedes the string buffers "we" allocate. It may be the
@@ -25,12 +24,12 @@ struct already_AddRefed;
*/
class nsStringBuffer {
private:
- friend class CheckStaticAtomSizes;
-
std::atomic<uint32_t> mRefCount;
uint32_t mStorageSize;
public:
+ MOZ_DECLARE_REFCOUNTED_TYPENAME(nsStringBuffer)
+
/**
* Allocates a new string buffer, with given size in bytes and a
* reference count of one. When the string buffer is no longer needed,
@@ -43,12 +42,25 @@ class nsStringBuffer {
* (i.e., it is not required that the null terminator appear in the last
* storage unit of the string buffer's data).
*
- * This guarantees that StorageSize() returns aStorageSize if the returned
+ * This guarantees that StorageSize() returns aSize if the returned
* buffer is non-null. Some callers like nsAttrValue rely on it.
*
* @return new string buffer or null if out of memory.
*/
- static already_AddRefed<nsStringBuffer> Alloc(size_t aStorageSize);
+ static already_AddRefed<nsStringBuffer> Alloc(size_t aSize) {
+ MOZ_ASSERT(aSize != 0, "zero capacity allocation not allowed");
+ MOZ_ASSERT(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) &&
+ sizeof(nsStringBuffer) + aSize > aSize,
+ "mStorageSize will truncate");
+
+ auto* hdr = (nsStringBuffer*)malloc(sizeof(nsStringBuffer) + aSize);
+ if (hdr) {
+ hdr->mRefCount = 1;
+ hdr->mStorageSize = aSize;
+ mozilla::detail::RefCountLogger::logAddRef(hdr, 1);
+ }
+ return already_AddRefed(hdr);
+ }
/**
* Returns a string buffer initialized with the given string on it, or null on
@@ -74,16 +86,35 @@ class nsStringBuffer {
*/
static nsStringBuffer* Realloc(nsStringBuffer* aBuf, size_t aStorageSize);
- /**
- * Increment the reference count on this string buffer.
- */
- void NS_FASTCALL AddRef();
+ void AddRef() {
+ // Memory synchronization is not required when incrementing a
+ // reference count. The first increment of a reference count on a
+ // thread is not important, since the first use of the object on a
+ // thread can happen before it. What is important is the transfer
+ // of the pointer to that thread, which may happen prior to the
+ // first increment on that thread. The necessary memory
+ // synchronization is done by the mechanism that transfers the
+ // pointer between threads.
+ uint32_t count = mRefCount.fetch_add(1, std::memory_order_relaxed) + 1;
+ mozilla::detail::RefCountLogger::logAddRef(this, count);
+ }
- /**
- * Decrement the reference count on this string buffer. The string
- * buffer will be destroyed when its reference count reaches zero.
- */
- void NS_FASTCALL Release();
+ void Release() {
+ // Since this may be the last release on this thread, we need release
+ // semantics so that prior writes on this thread are visible to the thread
+ // that destroys the object when it reads mValue with acquire semantics.
+ mozilla::detail::RefCountLogger::ReleaseLogger logger(this);
+ uint32_t count = mRefCount.fetch_sub(1, std::memory_order_release) - 1;
+ logger.logRelease(count);
+ if (count == 0) {
+ // We're going to destroy the object on this thread, so we need acquire
+ // semantics to synchronize with the memory released by the last release
+ // on other threads, that is, to ensure that writes prior to that release
+ // are now visible on this thread.
+ count = mRefCount.load(std::memory_order_acquire);
+ free(this); // We were allocated with malloc.
+ }
+ }
/**
* This method returns the string buffer corresponding to the given data
@@ -149,34 +180,6 @@ class nsStringBuffer {
}
/**
- * The FromString methods return a string buffer for the given string
- * object or null if the string object does not have a string buffer.
- * The reference count of the string buffer is NOT incremented by these
- * methods. If the caller wishes to hold onto the returned value, then
- * the returned string buffer must have its reference count incremented
- * via a call to the AddRef method.
- */
- static nsStringBuffer* FromString(const nsAString& aStr);
- static nsStringBuffer* FromString(const nsACString& aStr);
-
- /**
- * The ToString methods assign this string buffer to a given string
- * object. If the string object does not support sharable string
- * buffers, then its value will be set to a copy of the given string
- * buffer. Otherwise, these methods increment the reference count of the
- * given string buffer. It is important to specify the length (in
- * storage units) of the string contained in the string buffer since the
- * length of the string may be less than its storage size. The string
- * must have a null terminator at the offset specified by |len|.
- *
- * NOTE: storage size is measured in bytes even for wide strings;
- * however, string length is always measured in storage units
- * (2-byte units for wide strings).
- */
- void ToString(uint32_t aLen, nsAString& aStr, bool aMoveOwnership = false);
- void ToString(uint32_t aLen, nsACString& aStr, bool aMoveOwnership = false);
-
- /**
* This measures the size only if the StringBuffer is unshared.
*/
size_t SizeOfIncludingThisIfUnshared(
diff --git a/xpcom/string/nsStringStats.cpp b/xpcom/string/nsStringStats.cpp
deleted file mode 100644
index 7fc3d82ad5..0000000000
--- a/xpcom/string/nsStringStats.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsStringStats.h"
-
-#include "mozilla/IntegerPrintfMacros.h"
-#include "mozilla/MemoryReporting.h"
-#include "nsString.h"
-
-#include <stdint.h>
-#include <stdio.h>
-
-#ifdef XP_WIN
-# include <windows.h>
-# include <process.h>
-#else
-# include <unistd.h>
-# include <pthread.h>
-#endif
-
-nsStringStats gStringStats;
-
-nsStringStats::~nsStringStats() {
- // this is a hack to suppress duplicate string stats printing
- // in seamonkey as a result of the string code being linked
- // into seamonkey and libxpcom! :-(
- if (!mAllocCount && !mAdoptCount) {
- return;
- }
-
- // Only print the stats if we detect a leak.
- if (mAllocCount <= mFreeCount && mAdoptCount <= mAdoptFreeCount) {
- return;
- }
-
- printf("nsStringStats\n");
- printf(" => mAllocCount: % 10d\n", int(mAllocCount));
- printf(" => mReallocCount: % 10d\n", int(mReallocCount));
- printf(" => mFreeCount: % 10d", int(mFreeCount));
- if (mAllocCount > mFreeCount) {
- printf(" -- LEAKED %d !!!\n", mAllocCount - mFreeCount);
- } else {
- printf("\n");
- }
- printf(" => mShareCount: % 10d\n", int(mShareCount));
- printf(" => mAdoptCount: % 10d\n", int(mAdoptCount));
- printf(" => mAdoptFreeCount: % 10d", int(mAdoptFreeCount));
- if (mAdoptCount > mAdoptFreeCount) {
- printf(" -- LEAKED %d !!!\n", mAdoptCount - mAdoptFreeCount);
- } else {
- printf("\n");
- }
-
-#ifdef XP_WIN
- auto pid = uintptr_t(_getpid());
- auto tid = uintptr_t(GetCurrentThreadId());
-#else
- auto pid = uintptr_t(getpid());
- auto tid = uintptr_t(pthread_self());
-#endif
-
- printf(" => Process ID: %" PRIuPTR ", Thread ID: %" PRIuPTR "\n", pid, tid);
-}
diff --git a/xpcom/string/nsStringStats.h b/xpcom/string/nsStringStats.h
deleted file mode 100644
index a38304c2b7..0000000000
--- a/xpcom/string/nsStringStats.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsStringStats_h
-#define nsStringStats_h
-
-#include "mozilla/Atomics.h"
-
-class nsStringStats {
- public:
- nsStringStats() = default;
-
- ~nsStringStats();
-
- using AtomicInt = mozilla::Atomic<int32_t, mozilla::SequentiallyConsistent>;
-
- AtomicInt mAllocCount{0};
- AtomicInt mReallocCount{0};
- AtomicInt mFreeCount{0};
- AtomicInt mShareCount{0};
- AtomicInt mAdoptCount{0};
- AtomicInt mAdoptFreeCount{0};
-};
-
-extern nsStringStats gStringStats;
-
-#define STRING_STAT_INCREMENT(_s) (gStringStats.m##_s##Count)++
-
-#endif // nsStringStats_h
diff --git a/xpcom/string/nsTLiteralString.h b/xpcom/string/nsTLiteralString.h
index 38ffd32bdb..0d14614583 100644
--- a/xpcom/string/nsTLiteralString.h
+++ b/xpcom/string/nsTLiteralString.h
@@ -8,6 +8,7 @@
#define nsTLiteralString_h
#include "nsTStringRepr.h"
+#include "mozilla/StaticString.h"
/**
* nsTLiteralString_CharT
@@ -78,8 +79,10 @@ class nsTLiteralString : public mozilla::detail::nsTStringRepr<T> {
* Prohibit get() on temporaries as in "x"_ns.get().
* These should be written as just "x", using a string literal directly.
*/
- const typename raw_type<T, int>::type get() const&& = delete;
- const typename raw_type<T, int>::type get() const& { return this->mData; }
+ constexpr const typename raw_type<T, int>::type get() const&& = delete;
+ constexpr const typename raw_type<T, int>::type get() const& {
+ return this->mData;
+ }
// At least older gcc versions do not accept these friend declarations,
// complaining about an "invalid argument list" here, but not where the actual
@@ -110,4 +113,9 @@ class nsTLiteralString : public mozilla::detail::nsTStringRepr<T> {
extern template class nsTLiteralString<char>;
extern template class nsTLiteralString<char16_t>;
+namespace mozilla {
+constexpr MOZ_IMPLICIT StaticString::StaticString(nsLiteralCString const& str)
+ : mStr(str.get()) {}
+} // namespace mozilla
+
#endif
diff --git a/xpcom/string/nsTSubstring.cpp b/xpcom/string/nsTSubstring.cpp
index cff2031422..c89b6773d6 100644
--- a/xpcom/string/nsTSubstring.cpp
+++ b/xpcom/string/nsTSubstring.cpp
@@ -17,12 +17,6 @@
#include "nsString.h"
#include "nsTArray.h"
-#ifdef DEBUG
-# include "nsStringStats.h"
-#else
-# define STRING_STAT_INCREMENT(_s)
-#endif
-
// It's not worthwhile to reallocate the buffer and memcpy the
// contents over when the size difference isn't large. With
// power-of-two allocation buckets and 64 as the typical inline
@@ -63,7 +57,6 @@ static void ReleaseData(void* aData, nsAString::DataFlags aFlags) {
MOZ_LOG_DTOR(aData, "StringAdopt", 1);
free(aData);
- STRING_STAT_INCREMENT(AdoptFree);
}
// otherwise, nothing to do.
}
@@ -79,7 +72,6 @@ nsTSubstring<T>::nsTSubstring(char_type* aData, size_type aLength,
AssertValid();
if (aDataFlags & DataFlags::OWNED) {
- STRING_STAT_INCREMENT(Adopt);
MOZ_LOG_CTOR(this->mData, "StringAdopt", 1);
}
}
@@ -412,6 +404,17 @@ void nsTSubstring<T>::Assign(const char_type* aData, size_type aLength) {
}
template <typename T>
+void nsTSubstring<T>::Assign(already_AddRefed<nsStringBuffer> aBuffer,
+ size_type aLength) {
+ nsStringBuffer* buffer = aBuffer.take();
+ auto* data = reinterpret_cast<char_type*>(buffer->Data());
+ MOZ_DIAGNOSTIC_ASSERT(data[aLength] == char_type(0),
+ "data should be null terminated");
+ Finalize();
+ SetData(data, aLength, DataFlags::REFCOUNTED | DataFlags::TERMINATED);
+}
+
+template <typename T>
bool nsTSubstring<T>::Assign(const char_type* aData,
const fallible_t& aFallible) {
return Assign(aData, size_type(-1), aFallible);
@@ -631,7 +634,6 @@ void nsTSubstring<T>::Adopt(char_type* aData, size_type aLength) {
SetData(aData, aLength, DataFlags::TERMINATED | DataFlags::OWNED);
- STRING_STAT_INCREMENT(Adopt);
// Treat this as construction of a "StringAdopt" object for leak
// tracking purposes.
MOZ_LOG_CTOR(this->mData, "StringAdopt", 1);
diff --git a/xpcom/string/nsTSubstring.h b/xpcom/string/nsTSubstring.h
index 622b931afb..7459333dc0 100644
--- a/xpcom/string/nsTSubstring.h
+++ b/xpcom/string/nsTSubstring.h
@@ -8,20 +8,17 @@
#ifndef nsTSubstring_h
#define nsTSubstring_h
-#include <iterator>
#include <type_traits>
-#include "mozilla/Casting.h"
+#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
-#include "mozilla/IntegerPrintfMacros.h"
-#include "mozilla/UniquePtr.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
-#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/Span.h"
#include "mozilla/Try.h"
#include "mozilla/Unused.h"
+#include "nsStringBuffer.h"
#include "nsTStringRepr.h"
@@ -422,6 +419,13 @@ class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
[[nodiscard]] bool NS_FASTCALL Assign(const substring_tuple_type&,
const fallible_t&);
+ void Assign(nsStringBuffer* aBuffer, size_type aLength) {
+ aBuffer->AddRef();
+ Assign(already_AddRefed<nsStringBuffer>(aBuffer), aLength);
+ }
+ void NS_FASTCALL Assign(already_AddRefed<nsStringBuffer> aBuffer,
+ size_type aLength);
+
#if defined(MOZ_USE_CHAR16_WRAPPER)
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
void Assign(char16ptr_t aData) {
@@ -1142,11 +1146,22 @@ class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
* clears the pointer without releasing the buffer.
*/
void ForgetSharedBuffer() {
- if (base_string_type::mDataFlags & DataFlags::REFCOUNTED) {
+ if (this->mDataFlags & DataFlags::REFCOUNTED) {
SetToEmptyBuffer();
}
}
+ /**
+ * If the string uses a reference-counted buffer, this method returns a
+ * pointer to it without incrementing the buffer's refcount.
+ */
+ nsStringBuffer* GetStringBuffer() const {
+ if (this->mDataFlags & DataFlags::REFCOUNTED) {
+ return nsStringBuffer::FromData(this->mData);
+ }
+ return nullptr;
+ }
+
protected:
void AssertValid() {
MOZ_DIAGNOSTIC_ASSERT(!(this->mClassFlags & ClassFlags::INVALID_MASK));