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
parent ea6f2a50ec
commit 85ab2ab799
38 changed files with 170 additions and 297 deletions

View File

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

View File

@@ -108,7 +108,9 @@ const uintptr_t NS_ATTRVALUE_BASETYPE_MASK = 3;
class nsCheapString : public nsString { class nsCheapString : public nsString {
public: public:
explicit nsCheapString(nsStringBuffer* aBuf) { 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);
}
} }
}; };

View File

@@ -7010,25 +7010,6 @@ bool nsContentUtils::PlatformToDOMLineBreaks(nsString& aString,
return true; 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( already_AddRefed<nsContentList> nsContentUtils::GetElementsByClassName(
nsINode* aRootNode, const nsAString& aClasses) { nsINode* aRootNode, const nsAString& aClasses) {
MOZ_ASSERT(aRootNode, "Must have root node"); MOZ_ASSERT(aRootNode, "Must have root node");

View File

@@ -115,7 +115,6 @@ class nsNodeInfoManager;
class nsParser; class nsParser;
class nsPIWindowRoot; class nsPIWindowRoot;
class nsPresContext; class nsPresContext;
class nsStringBuffer;
class nsTextFragment; class nsTextFragment;
class nsView; class nsView;
class nsWrapperCache; class nsWrapperCache;
@@ -2446,14 +2445,6 @@ class nsContentUtils {
[[nodiscard]] static bool PlatformToDOMLineBreaks(nsString& aString, [[nodiscard]] static bool PlatformToDOMLineBreaks(nsString& aString,
const mozilla::fallible_t&); 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 bool IsHandlingKeyBoardEvent() { return sIsHandlingKeyBoardEvent; }
static void SetIsHandlingKeyBoardEvent(bool aHandling) { static void SetIsHandlingKeyBoardEvent(bool aHandling) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,64 +7,7 @@
#include "nsStringBuffer.h" #include "nsStringBuffer.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "nsISupportsImpl.h" #include "mozilla/RefPtr.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);
}
template <typename CharT> template <typename CharT>
static already_AddRefed<nsStringBuffer> DoCreate(const CharT* aData, 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) { nsStringBuffer* nsStringBuffer::Realloc(nsStringBuffer* aHdr, size_t aSize) {
NS_ASSERTION(aSize != 0, "zero capacity allocation not allowed"); MOZ_ASSERT(aSize != 0, "zero capacity allocation not allowed");
NS_ASSERTION(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) && MOZ_ASSERT(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) &&
sizeof(nsStringBuffer) + aSize > aSize, sizeof(nsStringBuffer) + aSize > aSize,
"mStorageSize will truncate"); "mStorageSize will truncate");
// no point in trying to save ourselves if we hit this assertion // 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 // 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 // just asserted that the refcount is 1. If we don't do that, refcount
// logging will claim we've leaked all sorts of stuff. // 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); aHdr = (nsStringBuffer*)realloc(aHdr, sizeof(nsStringBuffer) + aSize);
if (aHdr) { if (aHdr) {
NS_LOG_ADDREF(aHdr, 1, "nsStringBuffer", sizeof(*aHdr)); mozilla::detail::RefCountLogger::logAddRef(aHdr, 1);
aHdr->mStorageSize = aSize; aHdr->mStorageSize = aSize;
} }
return aHdr; 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( size_t nsStringBuffer::SizeOfIncludingThisIfUnshared(
mozilla::MallocSizeOf aMallocSizeOf) const { mozilla::MallocSizeOf aMallocSizeOf) const {
return IsReadonly() ? 0 : aMallocSizeOf(this); return IsReadonly() ? 0 : aMallocSizeOf(this);

View File

@@ -9,10 +9,9 @@
#include <atomic> #include <atomic>
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "nsStringFwd.h" #include "mozilla/Assertions.h"
#include "mozilla/AlreadyAddRefed.h"
template <class T> #include "mozilla/RefCounted.h"
struct already_AddRefed;
/** /**
* This structure precedes the string buffers "we" allocate. It may be the * This structure precedes the string buffers "we" allocate. It may be the
@@ -25,12 +24,12 @@ struct already_AddRefed;
*/ */
class nsStringBuffer { class nsStringBuffer {
private: private:
friend class CheckStaticAtomSizes;
std::atomic<uint32_t> mRefCount; std::atomic<uint32_t> mRefCount;
uint32_t mStorageSize; uint32_t mStorageSize;
public: public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(nsStringBuffer)
/** /**
* Allocates a new string buffer, with given size in bytes and a * Allocates a new string buffer, with given size in bytes and a
* reference count of one. When the string buffer is no longer needed, * 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 * (i.e., it is not required that the null terminator appear in the last
* storage unit of the string buffer's data). * 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. * buffer is non-null. Some callers like nsAttrValue rely on it.
* *
* @return new string buffer or null if out of memory. * @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 * 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); static nsStringBuffer* Realloc(nsStringBuffer* aBuf, size_t aStorageSize);
/** void AddRef() {
* Increment the reference count on this string buffer. // Memory synchronization is not required when incrementing a
*/ // reference count. The first increment of a reference count on a
void NS_FASTCALL AddRef(); // 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);
}
/** void Release() {
* Decrement the reference count on this string buffer. The string // Since this may be the last release on this thread, we need release
* buffer will be destroyed when its reference count reaches zero. // semantics so that prior writes on this thread are visible to the thread
*/ // that destroys the object when it reads mValue with acquire semantics.
void NS_FASTCALL Release(); 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 * This method returns the string buffer corresponding to the given data
@@ -148,34 +179,6 @@ class nsStringBuffer {
#endif #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. * This measures the size only if the StringBuffer is unshared.
*/ */

View File

@@ -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> template <typename T>
bool nsTSubstring<T>::Assign(const char_type* aData, bool nsTSubstring<T>::Assign(const char_type* aData,
const fallible_t& aFallible) { const fallible_t& aFallible) {

View File

@@ -8,20 +8,17 @@
#ifndef nsTSubstring_h #ifndef nsTSubstring_h
#define nsTSubstring_h #define nsTSubstring_h
#include <iterator>
#include <type_traits> #include <type_traits>
#include "mozilla/Casting.h" #include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/ResultExtensions.h" #include "mozilla/ResultExtensions.h"
#include "mozilla/Span.h" #include "mozilla/Span.h"
#include "mozilla/Try.h" #include "mozilla/Try.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "nsStringBuffer.h"
#include "nsTStringRepr.h" #include "nsTStringRepr.h"
@@ -422,6 +419,13 @@ class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
[[nodiscard]] bool NS_FASTCALL Assign(const substring_tuple_type&, [[nodiscard]] bool NS_FASTCALL Assign(const substring_tuple_type&,
const fallible_t&); 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) #if defined(MOZ_USE_CHAR16_WRAPPER)
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>> template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
void Assign(char16ptr_t aData) { void Assign(char16ptr_t aData) {
@@ -1142,11 +1146,22 @@ class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
* clears the pointer without releasing the buffer. * clears the pointer without releasing the buffer.
*/ */
void ForgetSharedBuffer() { void ForgetSharedBuffer() {
if (base_string_type::mDataFlags & DataFlags::REFCOUNTED) { if (this->mDataFlags & DataFlags::REFCOUNTED) {
SetToEmptyBuffer(); 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: protected:
void AssertValid() { void AssertValid() {
MOZ_DIAGNOSTIC_ASSERT(!(this->mClassFlags & ClassFlags::INVALID_MASK)); MOZ_DIAGNOSTIC_ASSERT(!(this->mClassFlags & ClassFlags::INVALID_MASK));

View File

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

View File

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