Bug 1893683 - Remove ns{A,C}String and other xpcom dependencies from nsStringBuffer. r=smaug,media-playback-reviewers,karlt

* nsStringBuffer::FromString -> nsTSubString::GetStringBuffer
 * nsStringBuffer::ToString -> nsTSubString::Assign(nsStringBuffer*, len)
 * Move refcounting inline but refcount-logging and other XPCOM-related
   things out-of-line.

Differential Revision: https://phabricator.services.mozilla.com/D208771
This commit is contained in:
Emilio Cobos Álvarez 2024-05-09 08:34:35 +00:00
Родитель 597a1ab19f
Коммит 8aaf44fea9
38 изменённых файлов: 170 добавлений и 297 удалений

Просмотреть файл

@ -141,7 +141,7 @@ bool MiscContainer::GetString(nsAString& aString) const {
}
if (isString) {
auto* buffer = static_cast<nsStringBuffer*>(ptr);
buffer->ToString(buffer->StorageSize() / sizeof(char16_t) - 1, aString);
aString.Assign(buffer, buffer->StorageSize() / sizeof(char16_t) - 1);
} else {
static_cast<nsAtom*>(ptr)->ToString(aString);
}
@ -280,11 +280,9 @@ void nsAttrValue::Shutdown() {
void nsAttrValue::Reset() {
switch (BaseType()) {
case eStringBase: {
nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
if (str) {
if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) {
str->Release();
}
break;
}
case eOtherBase: {
@ -320,8 +318,7 @@ void nsAttrValue::SetTo(const nsAttrValue& aOther) {
switch (aOther.BaseType()) {
case eStringBase: {
ResetIfSet();
nsStringBuffer* str = static_cast<nsStringBuffer*>(aOther.GetPtr());
if (str) {
if (auto* str = static_cast<nsStringBuffer*>(aOther.GetPtr())) {
str->AddRef();
SetPtrValueAndType(str, eStringBase);
}
@ -623,18 +620,16 @@ void nsAttrValue::ToString(nsAString& aResult) const {
switch (Type()) {
case eString: {
nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
if (str) {
str->ToString(str->StorageSize() / sizeof(char16_t) - 1, aResult);
if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) {
aResult.Assign(str, str->StorageSize() / sizeof(char16_t) - 1);
} else {
aResult.Truncate();
}
break;
}
case eAtom: {
nsAtom* atom = static_cast<nsAtom*>(GetPtr());
auto* atom = static_cast<nsAtom*>(GetPtr());
atom->ToString(aResult);
break;
}
case eInteger: {
@ -895,8 +890,7 @@ nsAtom* nsAttrValue::AtomAt(int32_t aIndex) const {
uint32_t nsAttrValue::HashValue() const {
switch (BaseType()) {
case eStringBase: {
nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
if (str) {
if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) {
uint32_t len = str->StorageSize() / sizeof(char16_t) - 1;
return HashString(static_cast<char16_t*>(str->Data()), len);
}
@ -1208,8 +1202,7 @@ bool nsAttrValue::SubstringCheck(const nsAString& aValue,
nsCaseTreatment aCaseSensitive) const {
switch (BaseType()) {
case eStringBase: {
auto str = static_cast<nsStringBuffer*>(GetPtr());
if (str) {
if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) {
return F::Check(static_cast<char16_t*>(str->Data()),
str->StorageSize() / sizeof(char16_t) - 1, aValue,
aCaseSensitive);
@ -1217,7 +1210,7 @@ bool nsAttrValue::SubstringCheck(const nsAString& aValue,
return aValue.IsEmpty();
}
case eAtomBase: {
auto atom = static_cast<nsAtom*>(GetPtr());
auto* atom = static_cast<nsAtom*>(GetPtr());
return F::Check(atom->GetUTF16String(), atom->GetLength(), aValue,
aCaseSensitive);
}
@ -2107,12 +2100,11 @@ already_AddRefed<nsStringBuffer> nsAttrValue::GetStringBuffer(
if (!len) {
return nullptr;
}
RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aValue);
if (buf && (buf->StorageSize() / sizeof(char16_t) - 1) == len) {
if (nsStringBuffer* buf = aValue.GetStringBuffer();
buf && (buf->StorageSize() / sizeof(char16_t) - 1) == len) {
// We can only reuse the buffer if it's exactly sized, since we rely on
// StorageSize() to get the string length in ToString().
return buf.forget();
return do_AddRef(buf);
}
return nsStringBuffer::Create(aValue.Data(), aValue.Length());
}

Просмотреть файл

@ -108,7 +108,9 @@ const uintptr_t NS_ATTRVALUE_BASETYPE_MASK = 3;
class nsCheapString : public nsString {
public:
explicit nsCheapString(nsStringBuffer* aBuf) {
if (aBuf) aBuf->ToString(aBuf->StorageSize() / sizeof(char16_t) - 1, *this);
if (aBuf) {
Assign(aBuf, aBuf->StorageSize() / sizeof(char16_t) - 1);
}
}
};

Просмотреть файл

@ -7010,25 +7010,6 @@ bool nsContentUtils::PlatformToDOMLineBreaks(nsString& aString,
return true;
}
void nsContentUtils::PopulateStringFromStringBuffer(nsStringBuffer* aBuf,
nsAString& aResultString) {
MOZ_ASSERT(aBuf, "Expecting a non-null string buffer");
uint32_t stringLen = NS_strlen(static_cast<char16_t*>(aBuf->Data()));
// SANITY CHECK: In case the nsStringBuffer isn't correctly
// null-terminated, let's clamp its length using the allocated size, to be
// sure the resulting string doesn't sample past the end of the the buffer.
// (Note that StorageSize() is in units of bytes, so we have to convert that
// to units of PRUnichars, and subtract 1 for the null-terminator.)
uint32_t allocStringLen = (aBuf->StorageSize() / sizeof(char16_t)) - 1;
MOZ_ASSERT(stringLen <= allocStringLen,
"string buffer lacks null terminator!");
stringLen = std::min(stringLen, allocStringLen);
aBuf->ToString(stringLen, aResultString);
}
already_AddRefed<nsContentList> nsContentUtils::GetElementsByClassName(
nsINode* aRootNode, const nsAString& aClasses) {
MOZ_ASSERT(aRootNode, "Must have root node");

Просмотреть файл

@ -115,7 +115,6 @@ class nsNodeInfoManager;
class nsParser;
class nsPIWindowRoot;
class nsPresContext;
class nsStringBuffer;
class nsTextFragment;
class nsView;
class nsWrapperCache;
@ -2446,14 +2445,6 @@ class nsContentUtils {
[[nodiscard]] static bool PlatformToDOMLineBreaks(nsString& aString,
const mozilla::fallible_t&);
/**
* Populates aResultString with the contents of the string-buffer aBuf, up
* to aBuf's null-terminator. aBuf must not be null. Ownership of the string
* is not transferred.
*/
static void PopulateStringFromStringBuffer(nsStringBuffer* aBuf,
nsAString& aResultString);
static bool IsHandlingKeyBoardEvent() { return sIsHandlingKeyBoardEvent; }
static void SetIsHandlingKeyBoardEvent(bool aHandling) {

Просмотреть файл

@ -113,8 +113,7 @@ class nsTextFragment final {
}
ReleaseText();
if (aForce2b && !aUpdateBidi) {
nsStringBuffer* buffer = nsStringBuffer::FromString(aString);
if (buffer) {
if (nsStringBuffer* buffer = aString.GetStringBuffer()) {
NS_ADDREF(m2b = buffer);
mState.mInHeap = true;
mState.mIs2b = true;
@ -154,19 +153,13 @@ class nsTextFragment final {
const mozilla::fallible_t& aFallible) const {
if (mState.mIs2b) {
if (aString.IsEmpty()) {
m2b->ToString(mState.mLength, aString);
aString.Assign(m2b, mState.mLength);
return true;
}
bool ok = aString.Append(Get2b(), mState.mLength, aFallible);
if (!ok) {
return false;
}
return true;
} else {
return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString,
aFallible);
return aString.Append(Get2b(), mState.mLength, aFallible);
}
return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString,
aFallible);
}
/**

Просмотреть файл

@ -169,8 +169,7 @@ class MOZ_STACK_CLASS DOMString {
if (MOZ_UNLIKELY(aString.IsVoid())) {
SetNull();
} else if (!aString.IsEmpty()) {
nsStringBuffer* buf = nsStringBuffer::FromString(aString);
if (buf) {
if (nsStringBuffer* buf = aString.GetStringBuffer()) {
SetKnownLiveStringBuffer(buf, aString.Length());
} else if (aString.IsLiteral()) {
SetLiteralInternal(aString.BeginReading(), aString.Length());
@ -236,7 +235,7 @@ class MOZ_STACK_CLASS DOMString {
auto chars = static_cast<char16_t*>(buf->Data());
if (chars[len] == '\0') {
// Safe to share the buffer.
buf->ToString(len, aString);
aString.Assign(buf, len);
} else {
// We need to copy, unfortunately.
aString.Assign(chars, len);

Просмотреть файл

@ -51,7 +51,7 @@ struct FakeString {
// depend upon aString's data. aString should outlive this instance of
// FakeString.
void ShareOrDependUpon(const AString& aString) {
RefPtr<nsStringBuffer> sharedBuffer = nsStringBuffer::FromString(aString);
RefPtr<nsStringBuffer> sharedBuffer = aString.GetStringBuffer();
if (!sharedBuffer) {
InitData(aString.BeginReading(), aString.Length());
if (!aString.IsTerminated()) {

Просмотреть файл

@ -66,8 +66,7 @@ void TestFunctions::GetStringDataAsDOMString(const Optional<uint32_t>& aLength,
length = mStringData.Length();
}
nsStringBuffer* buf = nsStringBuffer::FromString(mStringData);
if (buf) {
if (nsStringBuffer* buf = mStringData.GetStringBuffer()) {
aString.SetKnownLiveStringBuffer(buf, length);
return;
}
@ -134,7 +133,7 @@ StringType TestFunctions::GetStringType(const nsAString& aString) {
return StringType::Literal;
}
if (nsStringBuffer::FromString(aString)) {
if (aString.GetStringBuffer()) {
return StringType::Stringbuffer;
}
@ -146,9 +145,8 @@ StringType TestFunctions::GetStringType(const nsAString& aString) {
}
bool TestFunctions::StringbufferMatchesStored(const nsAString& aString) {
return nsStringBuffer::FromString(aString) &&
nsStringBuffer::FromString(aString) ==
nsStringBuffer::FromString(mStringData);
return aString.GetStringBuffer() &&
aString.GetStringBuffer() == mStringData.GetStringBuffer();
}
void TestFunctions::TestThrowNsresult(ErrorResult& aError) {

Просмотреть файл

@ -1083,7 +1083,7 @@ already_AddRefed<nsITransferable> DataTransfer::GetTransferable(
static_cast<char*>(stringBuffer->Data())[amountRead] = 0;
nsCString str;
stringBuffer->ToString(totalCustomLength, str);
str.Assign(stringBuffer, totalCustomLength);
nsCOMPtr<nsISupportsCString> strSupports(
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
strSupports->SetData(str);

Просмотреть файл

@ -9,7 +9,7 @@
#include "nsString.h" // Required before 'mozilla/ErrorNames.h'!?
#include "mozilla/ErrorNames.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "nsError.h"
#include "nsPrintfCString.h"

Просмотреть файл

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DDLifetime.h"
#include "mozilla/IntegerPrintfMacros.h"
namespace mozilla {

Просмотреть файл

@ -6,7 +6,7 @@
#include "CDMStorageIdProvider.h"
#include "GMPLog.h"
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "nsICryptoHash.h"
#ifdef SUPPORT_STORAGE_ID

Просмотреть файл

@ -341,7 +341,7 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
// argument of nsIContentSerializer::Init().
bool mNeedsPreformatScanning;
bool mIsCopying; // Set to true only while copying
nsStringBuffer* mCachedBuffer;
RefPtr<nsStringBuffer> mCachedBuffer;
class NodeSerializer {
public:
@ -701,11 +701,7 @@ nsresult nsDocumentEncoder::SerializeWholeDocument(uint32_t aMaxLength) {
return rv;
}
nsDocumentEncoder::~nsDocumentEncoder() {
if (mCachedBuffer) {
mCachedBuffer->Release();
}
}
nsDocumentEncoder::~nsDocumentEncoder() = default;
NS_IMETHODIMP
nsDocumentEncoder::Init(Document* aDocument, const nsAString& aMimeType,
@ -1372,7 +1368,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
nsString output;
static const size_t kStringBufferSizeInBytes = 2048;
if (!mCachedBuffer) {
mCachedBuffer = nsStringBuffer::Alloc(kStringBufferSizeInBytes).take();
mCachedBuffer = nsStringBuffer::Alloc(kStringBufferSizeInBytes);
if (NS_WARN_IF(!mCachedBuffer)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -1381,9 +1377,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
!mCachedBuffer->IsReadonly(),
"nsIDocumentEncoder shouldn't keep reference to non-readonly buffer!");
static_cast<char16_t*>(mCachedBuffer->Data())[0] = char16_t(0);
mCachedBuffer->ToString(0, output, true);
// output owns the buffer now!
mCachedBuffer = nullptr;
output.Assign(mCachedBuffer.forget(), 0);
if (!mSerializer) {
nsAutoCString progId(NS_CONTENTSERIALIZER_CONTRACTID_PREFIX);
@ -1407,21 +1401,18 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
rv = mSerializer->FlushAndFinish();
mCachedBuffer = nsStringBuffer::FromString(output);
// We have to be careful how we set aOutputString, because we don't
// want it to end up sharing mCachedBuffer if we plan to reuse it.
bool setOutput = false;
MOZ_ASSERT(!mCachedBuffer);
// Try to cache the buffer.
if (mCachedBuffer) {
if ((mCachedBuffer->StorageSize() == kStringBufferSizeInBytes) &&
!mCachedBuffer->IsReadonly()) {
mCachedBuffer->AddRef();
} else {
if (NS_SUCCEEDED(rv)) {
mCachedBuffer->ToString(output.Length(), aOutputString);
setOutput = true;
}
mCachedBuffer = nullptr;
if (nsStringBuffer* outputBuffer = output.GetStringBuffer()) {
if (outputBuffer->StorageSize() == kStringBufferSizeInBytes &&
!outputBuffer->IsReadonly()) {
mCachedBuffer = outputBuffer;
} else if (NS_SUCCEEDED(rv)) {
aOutputString.Assign(outputBuffer, output.Length());
setOutput = true;
}
}

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "mozilla/webgpu/WebGPUTypes.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "nsPrintfCString.h"
#include "nsString.h"
#include "ObjectModel.h"

Просмотреть файл

@ -58,8 +58,7 @@ class XMLHttpRequestStringBuffer final {
// XXX: Bug 1408793 suggests encapsulating the following sequence within
// DOMString.
nsStringBuffer* buf = nsStringBuffer::FromString(mData);
if (buf) {
if (nsStringBuffer* buf = mData.GetStringBuffer()) {
// We have to use SetStringBuffer, because once we release our mutex mData
// can get mutated from some other thread while the DOMString is still
// alive.

Просмотреть файл

@ -8,7 +8,8 @@
#include <ostream>
#include "mozilla/HashFunctions.h" // for HashGeneric
#include "nsPrintfCString.h" // for nsPrintfCString
#include "mozilla/IntegerPrintfMacros.h"
#include "nsPrintfCString.h" // for nsPrintfCString
namespace mozilla {
namespace layers {

Просмотреть файл

@ -7,6 +7,7 @@
#include "FocusState.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/layers/APZThreadUtils.h"
static mozilla::LazyLogModule sApzFstLog("apz.focusstate");

Просмотреть файл

@ -104,8 +104,7 @@ bool XPCStringConvert::ReadableToJSVal(JSContext* cx, const nsAString& readable,
return StringLiteralToJSVal(cx, readable.BeginReading(), length, vp);
}
nsStringBuffer* buf = nsStringBuffer::FromString(readable);
if (buf) {
if (nsStringBuffer* buf = readable.GetStringBuffer()) {
bool shared;
if (!UCStringBufferToJSVal(cx, buf, length, vp, &shared)) {
return false;
@ -138,8 +137,7 @@ bool XPCStringConvert::Latin1ToJSVal(JSContext* cx, const nsACString& latin1,
length, vp);
}
nsStringBuffer* buf = nsStringBuffer::FromString(latin1);
if (buf) {
if (nsStringBuffer* buf = latin1.GetStringBuffer()) {
bool shared;
if (!Latin1StringBufferToJSVal(cx, buf, length, vp, &shared)) {
return false;
@ -170,8 +168,7 @@ bool XPCStringConvert::UTF8ToJSVal(JSContext* cx, const nsACString& utf8,
cx, JS::UTF8Chars(utf8.BeginReading(), length), vp);
}
nsStringBuffer* buf = nsStringBuffer::FromString(utf8);
if (buf) {
if (nsStringBuffer* buf = utf8.GetStringBuffer()) {
bool shared;
if (!UTF8StringBufferToJSVal(cx, buf, length, vp, &shared)) {
return false;

Просмотреть файл

@ -238,11 +238,11 @@ extern JS::UniqueChars xpc_PrintJSStack(JSContext* cx, bool showArgs,
inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len,
nsAString& dest) {
buffer->ToString(len, dest);
dest.Assign(buffer, len);
}
inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len,
nsACString& dest) {
buffer->ToString(len, dest);
dest.Assign(buffer, len);
}
// readable string conversions, static methods and members only

Просмотреть файл

@ -8,6 +8,7 @@
#include "CacheFile.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "mozilla/IntegerPrintfMacros.h"
#include <algorithm>
namespace mozilla::net {

Просмотреть файл

@ -9,7 +9,7 @@
#include "CacheEntry.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/IntegerPrintfMacros.h"
#include <algorithm>
namespace mozilla::net {

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsIObserverService.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Services.h"
#include "mozilla/Logging.h"

Просмотреть файл

@ -8,6 +8,7 @@
#include "nsNetworkLinkService.h"
#include "nsString.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "nsNetAddr.h"
#include "mozilla/StaticPrefs_network.h"

Просмотреть файл

@ -5,12 +5,11 @@
#include "nsHtml5String.h"
#include "nsCharTraits.h"
#include "nsHtml5TreeBuilder.h"
#include "nsUTF8Utils.h"
void nsHtml5String::ToString(nsAString& aString) {
switch (GetKind()) {
case eStringBuffer:
return AsStringBuffer()->ToString(Length(), aString);
return aString.Assign(AsStringBuffer(), Length());
case eAtom:
return AsAtom()->ToString(aString);
case eEmpty:
@ -157,12 +156,14 @@ nsHtml5String nsHtml5String::FromString(const nsAString& aString) {
if (!length) {
return nsHtml5String(eEmpty);
}
RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString);
if (buffer && (length == buffer->StorageSize() / sizeof(char16_t) - 1)) {
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
eStringBuffer);
if (nsStringBuffer* buffer = aString.GetStringBuffer()) {
if (length == buffer->StorageSize() / sizeof(char16_t) - 1) {
buffer->AddRef();
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer) | eStringBuffer);
}
}
buffer = nsStringBuffer::Alloc((length + 1) * sizeof(char16_t));
RefPtr<nsStringBuffer> buffer =
nsStringBuffer::Alloc((length + 1) * sizeof(char16_t));
if (!buffer) {
MOZ_CRASH("Out of memory.");
}

Просмотреть файл

@ -7,6 +7,7 @@
#include "EnterpriseRoots.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Casting.h"
#include "mozilla/Logging.h"
#include "mozilla/Unused.h"

Просмотреть файл

@ -15,17 +15,12 @@
#include "nsIFile.h"
#include "nsThreadUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "prtime.h"
#include "mozilla/StaticPrefs_storage.h"
#include "mozStorageConnection.h"
#include "mozStoragePrivateHelpers.h"
#include "mozIStorageStatement.h"
#include "mozIStorageCompletionCallback.h"
#include "mozIStorageAsyncStatement.h"
#include "mozIStoragePendingStatement.h"
#include "mozIStorageError.h"
#include "mozStorageHelper.h"
#include "nsXULAppAPI.h"
#include "xpcpublic.h"

Просмотреть файл

@ -15,9 +15,8 @@
#include "mozStorageCID.h"
#include "mozilla/Components.h"
#include "mozilla/Monitor.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Services.h"
#include "mozilla/ShutdownPhase.h"
#include "nsCOMPtr.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIObserverService.h"

Просмотреть файл

@ -9,6 +9,7 @@
#include "ErrorList.h"
#include "mozilla/Assertions.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "nsIPrincipal.h"
namespace mozilla {

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/glean/bindings/jog/jog_ffi_generated.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/StaticPrefs_telemetry.h"
#include "mozilla/AppShutdown.h"
#include "nsDirectoryServiceDefs.h"
@ -22,8 +23,7 @@
namespace mozilla::glean {
using mozilla::LogLevel;
static mozilla::LazyLogModule sLog("jog");
static LazyLogModule sLog("jog");
// Storage
// Thread Safety: Only used on the main thread.

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "mozilla/Services.h"
#include "mozilla/Atomics.h"
#include "mozilla/IntegerPrintfMacros.h"
#ifdef ANDROID
# include <stdio.h>

Просмотреть файл

@ -82,7 +82,7 @@ nsDynamicAtom* nsDynamicAtom::Create(const nsAString& aString, uint32_t aHash) {
// We tack the chars onto the end of the nsDynamicAtom object.
const bool isAsciiLower =
::IsAsciiLowercase(aString.Data(), aString.Length());
RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString);
RefPtr<nsStringBuffer> buffer = aString.GetStringBuffer();
if (!buffer) {
buffer = nsStringBuffer::Create(aString.Data(), aString.Length());
if (MOZ_UNLIKELY(!buffer)) {
@ -111,7 +111,7 @@ void nsAtom::ToString(nsAString& aString) const {
// which is what's important.
aString.AssignLiteral(AsStatic()->String(), mLength);
} else {
AsDynamic()->StringBuffer()->ToString(mLength, aString);
aString.Assign(AsDynamic()->StringBuffer(), mLength);
}
}
@ -577,7 +577,7 @@ already_AddRefed<nsAtom> nsAtomTable::Atomize(const nsACString& aUTF8String) {
nsString str;
CopyUTF8toUTF16(aUTF8String, str);
MOZ_ASSERT(nsStringBuffer::FromString(str), "Should create a string buffer");
MOZ_ASSERT(str.GetStringBuffer(), "Should create a string buffer");
RefPtr<nsAtom> atom = dont_AddRef(nsDynamicAtom::Create(str, key.mHash));
he->mAtom = atom;

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/Maybe.h"
#include "mozilla/Mutex.h"
#include "mozilla/Attributes.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "nsIInputStreamTee.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"

Просмотреть файл

@ -7,64 +7,7 @@
#include "nsStringBuffer.h"
#include "mozilla/MemoryReporting.h"
#include "nsISupportsImpl.h"
#include "nsString.h"
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
;
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);
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) {
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,
@ -91,78 +34,31 @@ already_AddRefed<nsStringBuffer> nsStringBuffer::Create(const char16_t* aData,
}
nsStringBuffer* nsStringBuffer::Realloc(nsStringBuffer* aHdr, 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");
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);

Просмотреть файл

@ -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
@ -148,34 +179,6 @@ class nsStringBuffer {
#endif
}
/**
* 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.
*/

Просмотреть файл

@ -403,6 +403,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) {

Просмотреть файл

@ -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));

Просмотреть файл

@ -23,6 +23,7 @@
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "nsIDirectoryService.h"
#include "nsIFile.h"
#include "nsIObserverService.h"

Просмотреть файл

@ -1183,11 +1183,9 @@ TEST_F(Strings, stringbuffer) {
memcpy(data, kData, sizeof(kData));
nsCString str;
buf->ToString(sizeof(kData) - 1, str);
nsStringBuffer* buf2;
buf2 = nsStringBuffer::FromString(str);
str.Assign(buf, sizeof(kData) - 1);
nsStringBuffer* buf2 = str.GetStringBuffer();
EXPECT_EQ(buf, buf2);
}