Bug 1772006 - Part 1: Split nsSubstring.cpp into relevant files, r=xpcom-reviewers,barret
This file only exists as a wrapper around nsTSubstring.cpp, with some methods left in it due to how the string types were defined before they were turned into templates. Differential Revision: https://phabricator.services.mozilla.com/D148296
This commit is contained in:
123
xpcom/string/RustStringAPI.cpp
Normal file
123
xpcom/string/RustStringAPI.cpp
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* -*- 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 "nsISupports.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
|
||||||
|
// Extern "C" utilities used by the rust nsString bindings.
|
||||||
|
|
||||||
|
// Provide rust bindings to the nsA[C]String types
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// This is a no-op on release, so we ifdef it out such that using it in release
|
||||||
|
// results in a linker error.
|
||||||
|
#ifdef DEBUG
|
||||||
|
void Gecko_IncrementStringAdoptCount(void* aData) {
|
||||||
|
MOZ_LOG_CTOR(aData, "StringAdopt", 1);
|
||||||
|
}
|
||||||
|
#elif defined(MOZ_DEBUG_RUST)
|
||||||
|
void Gecko_IncrementStringAdoptCount(void* aData) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Gecko_FinalizeCString(nsACString* aThis) { aThis->~nsACString(); }
|
||||||
|
|
||||||
|
void Gecko_AssignCString(nsACString* aThis, const nsACString* aOther) {
|
||||||
|
aThis->Assign(*aOther);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gecko_TakeFromCString(nsACString* aThis, nsACString* aOther) {
|
||||||
|
aThis->Assign(std::move(*aOther));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gecko_AppendCString(nsACString* aThis, const nsACString* aOther) {
|
||||||
|
aThis->Append(*aOther);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gecko_SetLengthCString(nsACString* aThis, uint32_t aLength) {
|
||||||
|
aThis->SetLength(aLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleAssignCString(nsACString* aThis, const nsACString* aOther) {
|
||||||
|
return aThis->Assign(*aOther, mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleTakeFromCString(nsACString* aThis, nsACString* aOther) {
|
||||||
|
return aThis->Assign(std::move(*aOther), mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleAppendCString(nsACString* aThis, const nsACString* aOther) {
|
||||||
|
return aThis->Append(*aOther, mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleSetLengthCString(nsACString* aThis, uint32_t aLength) {
|
||||||
|
return aThis->SetLength(aLength, mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Gecko_BeginWritingCString(nsACString* aThis) {
|
||||||
|
return aThis->BeginWriting();
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Gecko_FallibleBeginWritingCString(nsACString* aThis) {
|
||||||
|
return aThis->BeginWriting(mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Gecko_StartBulkWriteCString(nsACString* aThis, uint32_t aCapacity,
|
||||||
|
uint32_t aUnitsToPreserve,
|
||||||
|
bool aAllowShrinking) {
|
||||||
|
return aThis->StartBulkWriteImpl(aCapacity, aUnitsToPreserve, aAllowShrinking)
|
||||||
|
.unwrapOr(UINT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gecko_FinalizeString(nsAString* aThis) { aThis->~nsAString(); }
|
||||||
|
|
||||||
|
void Gecko_AssignString(nsAString* aThis, const nsAString* aOther) {
|
||||||
|
aThis->Assign(*aOther);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gecko_TakeFromString(nsAString* aThis, nsAString* aOther) {
|
||||||
|
aThis->Assign(std::move(*aOther));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gecko_AppendString(nsAString* aThis, const nsAString* aOther) {
|
||||||
|
aThis->Append(*aOther);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gecko_SetLengthString(nsAString* aThis, uint32_t aLength) {
|
||||||
|
aThis->SetLength(aLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleAssignString(nsAString* aThis, const nsAString* aOther) {
|
||||||
|
return aThis->Assign(*aOther, mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleTakeFromString(nsAString* aThis, nsAString* aOther) {
|
||||||
|
return aThis->Assign(std::move(*aOther), mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleAppendString(nsAString* aThis, const nsAString* aOther) {
|
||||||
|
return aThis->Append(*aOther, mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gecko_FallibleSetLengthString(nsAString* aThis, uint32_t aLength) {
|
||||||
|
return aThis->SetLength(aLength, mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
char16_t* Gecko_BeginWritingString(nsAString* aThis) {
|
||||||
|
return aThis->BeginWriting();
|
||||||
|
}
|
||||||
|
|
||||||
|
char16_t* Gecko_FallibleBeginWritingString(nsAString* aThis) {
|
||||||
|
return aThis->BeginWriting(mozilla::fallible);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Gecko_StartBulkWriteString(nsAString* aThis, uint32_t aCapacity,
|
||||||
|
uint32_t aUnitsToPreserve,
|
||||||
|
bool aAllowShrinking) {
|
||||||
|
return aThis->StartBulkWriteImpl(aCapacity, aUnitsToPreserve, aAllowShrinking)
|
||||||
|
.unwrapOr(UINT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
@@ -42,14 +42,19 @@ UNIFIED_SOURCES += [
|
|||||||
"nsPromiseFlatString.cpp",
|
"nsPromiseFlatString.cpp",
|
||||||
"nsReadableUtils.cpp",
|
"nsReadableUtils.cpp",
|
||||||
"nsString.cpp",
|
"nsString.cpp",
|
||||||
|
"nsStringBuffer.cpp",
|
||||||
"nsStringComparator.cpp",
|
"nsStringComparator.cpp",
|
||||||
"nsStringObsolete.cpp",
|
"nsStringObsolete.cpp",
|
||||||
"nsSubstring.cpp",
|
|
||||||
"nsTextFormatter.cpp",
|
"nsTextFormatter.cpp",
|
||||||
|
"nsTSubstring.cpp",
|
||||||
"nsTSubstringTuple.cpp",
|
"nsTSubstringTuple.cpp",
|
||||||
"precompiled_templates.cpp",
|
"precompiled_templates.cpp",
|
||||||
|
"RustStringAPI.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if CONFIG["MOZ_DEBUG"]:
|
||||||
|
UNIFIED_SOURCES += ["nsStringStats.cpp"]
|
||||||
|
|
||||||
FINAL_LIBRARY = "xul"
|
FINAL_LIBRARY = "xul"
|
||||||
|
|
||||||
REQUIRES_UNIFIED_BUILD = True
|
REQUIRES_UNIFIED_BUILD = True
|
||||||
|
|||||||
162
xpcom/string/nsStringBuffer.cpp
Normal file
162
xpcom/string/nsStringBuffer.cpp
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/* -*- 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 "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");
|
||||||
|
|
||||||
|
nsStringBuffer* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
// no point in trying to save ourselves if we hit this assertion
|
||||||
|
NS_ASSERTION(!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");
|
||||||
|
|
||||||
|
aHdr = (nsStringBuffer*)realloc(aHdr, sizeof(nsStringBuffer) + aSize);
|
||||||
|
if (aHdr) {
|
||||||
|
NS_LOG_ADDREF(aHdr, 1, "nsStringBuffer", sizeof(*aHdr));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nsStringBuffer::SizeOfIncludingThisEvenIfShared(
|
||||||
|
mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||||
|
return aMallocSizeOf(this);
|
||||||
|
}
|
||||||
66
xpcom/string/nsStringStats.cpp
Normal file
66
xpcom/string/nsStringStats.cpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/* -*- 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);
|
||||||
|
}
|
||||||
32
xpcom/string/nsStringStats.h
Normal file
32
xpcom/string/nsStringStats.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* -*- 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
|
||||||
@@ -1,424 +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/. */
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
# define ENABLE_STRING_STATS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mozilla/Atomics.h"
|
|
||||||
#include "mozilla/MemoryReporting.h"
|
|
||||||
|
|
||||||
#ifdef ENABLE_STRING_STATS
|
|
||||||
# include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "nsAString.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "nsStringBuffer.h"
|
|
||||||
#include "nsDependentString.h"
|
|
||||||
#include "nsMemory.h"
|
|
||||||
#include "prprf.h"
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
|
|
||||||
#include "mozilla/IntegerPrintfMacros.h"
|
|
||||||
#ifdef XP_WIN
|
|
||||||
# include <windows.h>
|
|
||||||
# include <process.h>
|
|
||||||
# define getpid() _getpid()
|
|
||||||
# define pthread_self() GetCurrentThreadId()
|
|
||||||
#else
|
|
||||||
# include <pthread.h>
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using mozilla::Atomic;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static const char16_t gNullChar = 0;
|
|
||||||
|
|
||||||
char* const nsCharTraits<char>::sEmptyBuffer =
|
|
||||||
(char*)const_cast<char16_t*>(&gNullChar);
|
|
||||||
char16_t* const nsCharTraits<char16_t>::sEmptyBuffer =
|
|
||||||
const_cast<char16_t*>(&gNullChar);
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifdef ENABLE_STRING_STATS
|
|
||||||
class nsStringStats {
|
|
||||||
public:
|
|
||||||
nsStringStats()
|
|
||||||
: mAllocCount(0), mReallocCount(0), mFreeCount(0), mShareCount(0) {}
|
|
||||||
|
|
||||||
~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");
|
|
||||||
}
|
|
||||||
printf(" => Process ID: %" PRIuPTR ", Thread ID: %" PRIuPTR "\n",
|
|
||||||
uintptr_t(getpid()), uintptr_t(pthread_self()));
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef Atomic<int32_t, mozilla::SequentiallyConsistent> AtomicInt;
|
|
||||||
|
|
||||||
AtomicInt mAllocCount;
|
|
||||||
AtomicInt mReallocCount;
|
|
||||||
AtomicInt mFreeCount;
|
|
||||||
AtomicInt mShareCount;
|
|
||||||
AtomicInt mAdoptCount;
|
|
||||||
AtomicInt mAdoptFreeCount;
|
|
||||||
};
|
|
||||||
static nsStringStats gStringStats;
|
|
||||||
# define STRING_STAT_INCREMENT(_s) (gStringStats.m##_s##Count)++
|
|
||||||
#else
|
|
||||||
# define STRING_STAT_INCREMENT(_s)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void ReleaseData(void* aData, nsAString::DataFlags aFlags) {
|
|
||||||
if (aFlags & nsAString::DataFlags::REFCOUNTED) {
|
|
||||||
nsStringBuffer::FromData(aData)->Release();
|
|
||||||
} else if (aFlags & nsAString::DataFlags::OWNED) {
|
|
||||||
free(aData);
|
|
||||||
STRING_STAT_INCREMENT(AdoptFree);
|
|
||||||
// Treat this as destruction of a "StringAdopt" object for leak
|
|
||||||
// tracking purposes.
|
|
||||||
MOZ_LOG_DTOR(aData, "StringAdopt", 1);
|
|
||||||
}
|
|
||||||
// otherwise, nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// XXX or we could make nsStringBuffer be a friend of nsTAString
|
|
||||||
|
|
||||||
class nsAStringAccessor : public nsAString {
|
|
||||||
private:
|
|
||||||
nsAStringAccessor(); // NOT IMPLEMENTED
|
|
||||||
|
|
||||||
public:
|
|
||||||
char_type* data() const { return mData; }
|
|
||||||
size_type length() const { return mLength; }
|
|
||||||
DataFlags flags() const { return mDataFlags; }
|
|
||||||
|
|
||||||
void set(char_type* aData, size_type aLen, DataFlags aDataFlags) {
|
|
||||||
ReleaseData(mData, mDataFlags);
|
|
||||||
SetData(aData, aLen, aDataFlags);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class nsACStringAccessor : public nsACString {
|
|
||||||
private:
|
|
||||||
nsACStringAccessor(); // NOT IMPLEMENTED
|
|
||||||
|
|
||||||
public:
|
|
||||||
char_type* data() const { return mData; }
|
|
||||||
size_type length() const { return mLength; }
|
|
||||||
DataFlags flags() const { return mDataFlags; }
|
|
||||||
|
|
||||||
void set(char_type* aData, size_type aLen, DataFlags aDataFlags) {
|
|
||||||
ReleaseData(mData, mDataFlags);
|
|
||||||
SetData(aData, aLen, aDataFlags);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
nsStringBuffer* 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 dont_AddRef(hdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
// no point in trying to save ourselves if we hit this assertion
|
|
||||||
NS_ASSERTION(!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");
|
|
||||||
|
|
||||||
aHdr = (nsStringBuffer*)realloc(aHdr, sizeof(nsStringBuffer) + aSize);
|
|
||||||
if (aHdr) {
|
|
||||||
NS_LOG_ADDREF(aHdr, 1, "nsStringBuffer", sizeof(*aHdr));
|
|
||||||
aHdr->mStorageSize = aSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aHdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsStringBuffer* nsStringBuffer::FromString(const nsAString& aStr) {
|
|
||||||
const nsAStringAccessor* accessor =
|
|
||||||
static_cast<const nsAStringAccessor*>(&aStr);
|
|
||||||
|
|
||||||
if (!(accessor->flags() & nsAString::DataFlags::REFCOUNTED)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FromData(accessor->data());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsStringBuffer* nsStringBuffer::FromString(const nsACString& aStr) {
|
|
||||||
const nsACStringAccessor* accessor =
|
|
||||||
static_cast<const nsACStringAccessor*>(&aStr);
|
|
||||||
|
|
||||||
if (!(accessor->flags() & nsACString::DataFlags::REFCOUNTED)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FromData(accessor->data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsStringBuffer::ToString(uint32_t aLen, nsAString& aStr,
|
|
||||||
bool aMoveOwnership) {
|
|
||||||
char16_t* data = static_cast<char16_t*>(Data());
|
|
||||||
|
|
||||||
nsAStringAccessor* accessor = static_cast<nsAStringAccessor*>(&aStr);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
accessor->set(data, aLen, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsStringBuffer::ToString(uint32_t aLen, nsACString& aStr,
|
|
||||||
bool aMoveOwnership) {
|
|
||||||
char* data = static_cast<char*>(Data());
|
|
||||||
|
|
||||||
nsACStringAccessor* accessor = static_cast<nsACStringAccessor*>(&aStr);
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(data[aLen] == char(0),
|
|
||||||
"data should be null terminated");
|
|
||||||
|
|
||||||
nsACString::DataFlags flags =
|
|
||||||
nsACString::DataFlags::REFCOUNTED | nsACString::DataFlags::TERMINATED;
|
|
||||||
|
|
||||||
if (!aMoveOwnership) {
|
|
||||||
AddRef();
|
|
||||||
}
|
|
||||||
accessor->set(data, aLen, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t nsStringBuffer::SizeOfIncludingThisIfUnshared(
|
|
||||||
mozilla::MallocSizeOf aMallocSizeOf) const {
|
|
||||||
return IsReadonly() ? 0 : aMallocSizeOf(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t nsStringBuffer::SizeOfIncludingThisEvenIfShared(
|
|
||||||
mozilla::MallocSizeOf aMallocSizeOf) const {
|
|
||||||
return aMallocSizeOf(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// define nsAString
|
|
||||||
#include "nsTSubstring.cpp"
|
|
||||||
|
|
||||||
// Provide rust bindings to the nsA[C]String types
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
// This is a no-op on release, so we ifdef it out such that using it in release
|
|
||||||
// results in a linker error.
|
|
||||||
#ifdef DEBUG
|
|
||||||
void Gecko_IncrementStringAdoptCount(void* aData) {
|
|
||||||
MOZ_LOG_CTOR(aData, "StringAdopt", 1);
|
|
||||||
}
|
|
||||||
#elif defined(MOZ_DEBUG_RUST)
|
|
||||||
void Gecko_IncrementStringAdoptCount(void* aData) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Gecko_FinalizeCString(nsACString* aThis) { aThis->~nsACString(); }
|
|
||||||
|
|
||||||
void Gecko_AssignCString(nsACString* aThis, const nsACString* aOther) {
|
|
||||||
aThis->Assign(*aOther);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gecko_TakeFromCString(nsACString* aThis, nsACString* aOther) {
|
|
||||||
aThis->Assign(std::move(*aOther));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gecko_AppendCString(nsACString* aThis, const nsACString* aOther) {
|
|
||||||
aThis->Append(*aOther);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gecko_SetLengthCString(nsACString* aThis, uint32_t aLength) {
|
|
||||||
aThis->SetLength(aLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleAssignCString(nsACString* aThis, const nsACString* aOther) {
|
|
||||||
return aThis->Assign(*aOther, mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleTakeFromCString(nsACString* aThis, nsACString* aOther) {
|
|
||||||
return aThis->Assign(std::move(*aOther), mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleAppendCString(nsACString* aThis, const nsACString* aOther) {
|
|
||||||
return aThis->Append(*aOther, mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleSetLengthCString(nsACString* aThis, uint32_t aLength) {
|
|
||||||
return aThis->SetLength(aLength, mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* Gecko_BeginWritingCString(nsACString* aThis) {
|
|
||||||
return aThis->BeginWriting();
|
|
||||||
}
|
|
||||||
|
|
||||||
char* Gecko_FallibleBeginWritingCString(nsACString* aThis) {
|
|
||||||
return aThis->BeginWriting(mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Gecko_StartBulkWriteCString(nsACString* aThis, uint32_t aCapacity,
|
|
||||||
uint32_t aUnitsToPreserve,
|
|
||||||
bool aAllowShrinking) {
|
|
||||||
return aThis->StartBulkWriteImpl(aCapacity, aUnitsToPreserve, aAllowShrinking)
|
|
||||||
.unwrapOr(UINT32_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gecko_FinalizeString(nsAString* aThis) { aThis->~nsAString(); }
|
|
||||||
|
|
||||||
void Gecko_AssignString(nsAString* aThis, const nsAString* aOther) {
|
|
||||||
aThis->Assign(*aOther);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gecko_TakeFromString(nsAString* aThis, nsAString* aOther) {
|
|
||||||
aThis->Assign(std::move(*aOther));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gecko_AppendString(nsAString* aThis, const nsAString* aOther) {
|
|
||||||
aThis->Append(*aOther);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gecko_SetLengthString(nsAString* aThis, uint32_t aLength) {
|
|
||||||
aThis->SetLength(aLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleAssignString(nsAString* aThis, const nsAString* aOther) {
|
|
||||||
return aThis->Assign(*aOther, mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleTakeFromString(nsAString* aThis, nsAString* aOther) {
|
|
||||||
return aThis->Assign(std::move(*aOther), mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleAppendString(nsAString* aThis, const nsAString* aOther) {
|
|
||||||
return aThis->Append(*aOther, mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gecko_FallibleSetLengthString(nsAString* aThis, uint32_t aLength) {
|
|
||||||
return aThis->SetLength(aLength, mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
char16_t* Gecko_BeginWritingString(nsAString* aThis) {
|
|
||||||
return aThis->BeginWriting();
|
|
||||||
}
|
|
||||||
|
|
||||||
char16_t* Gecko_FallibleBeginWritingString(nsAString* aThis) {
|
|
||||||
return aThis->BeginWriting(mozilla::fallible);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Gecko_StartBulkWriteString(nsAString* aThis, uint32_t aCapacity,
|
|
||||||
uint32_t aUnitsToPreserve,
|
|
||||||
bool aAllowShrinking) {
|
|
||||||
return aThis->StartBulkWriteImpl(aCapacity, aUnitsToPreserve, aAllowShrinking)
|
|
||||||
.unwrapOr(UINT32_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
@@ -172,8 +172,6 @@ void nsTSubstring<T>::ReplaceChar(const char_type* aSet, char_type aNewChar) {
|
|||||||
|
|
||||||
template void nsTSubstring<char16_t>::ReplaceChar(const char*, char16_t);
|
template void nsTSubstring<char16_t>::ReplaceChar(const char*, char16_t);
|
||||||
|
|
||||||
void ReleaseData(void* aData, nsAString::DataFlags aFlags);
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void nsTSubstring<T>::ReplaceSubstring(const char_type* aTarget,
|
void nsTSubstring<T>::ReplaceSubstring(const char_type* aTarget,
|
||||||
const char_type* aNewValue) {
|
const char_type* aNewValue) {
|
||||||
|
|||||||
@@ -12,6 +12,15 @@
|
|||||||
#include "mozilla/ResultExtensions.h"
|
#include "mozilla/ResultExtensions.h"
|
||||||
|
|
||||||
#include "nsASCIIMask.h"
|
#include "nsASCIIMask.h"
|
||||||
|
#include "nsCharTraits.h"
|
||||||
|
#include "nsISupports.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# include "nsStringStats.h"
|
||||||
|
#else
|
||||||
|
# define STRING_STAT_INCREMENT(_s)
|
||||||
|
#endif
|
||||||
|
|
||||||
// It's not worthwhile to reallocate the buffer and memcpy the
|
// It's not worthwhile to reallocate the buffer and memcpy the
|
||||||
// contents over when the size difference isn't large. With
|
// contents over when the size difference isn't large. With
|
||||||
@@ -33,6 +42,32 @@ const uint32_t kNsStringBufferShrinkingThreshold = 384;
|
|||||||
|
|
||||||
using double_conversion::DoubleToStringConverter;
|
using double_conversion::DoubleToStringConverter;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static const char16_t gNullChar = 0;
|
||||||
|
|
||||||
|
char* const nsCharTraits<char>::sEmptyBuffer =
|
||||||
|
(char*)const_cast<char16_t*>(&gNullChar);
|
||||||
|
char16_t* const nsCharTraits<char16_t>::sEmptyBuffer =
|
||||||
|
const_cast<char16_t*>(&gNullChar);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void ReleaseData(void* aData, nsAString::DataFlags aFlags) {
|
||||||
|
if (aFlags & nsAString::DataFlags::REFCOUNTED) {
|
||||||
|
nsStringBuffer::FromData(aData)->Release();
|
||||||
|
} else if (aFlags & nsAString::DataFlags::OWNED) {
|
||||||
|
free(aData);
|
||||||
|
STRING_STAT_INCREMENT(AdoptFree);
|
||||||
|
// Treat this as destruction of a "StringAdopt" object for leak
|
||||||
|
// tracking purposes.
|
||||||
|
MOZ_LOG_DTOR(aData, "StringAdopt", 1);
|
||||||
|
}
|
||||||
|
// otherwise, nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
|
#ifdef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
|
||||||
template <typename T>
|
template <typename T>
|
||||||
nsTSubstring<T>::nsTSubstring(char_type* aData, size_type aLength,
|
nsTSubstring<T>::nsTSubstring(char_type* aData, size_type aLength,
|
||||||
@@ -87,7 +122,7 @@ auto nsTSubstring<T>::StartBulkWriteImpl(size_type aCapacity,
|
|||||||
// If zero capacity is requested, set the string to the special empty
|
// If zero capacity is requested, set the string to the special empty
|
||||||
// string.
|
// string.
|
||||||
if (MOZ_UNLIKELY(!aCapacity)) {
|
if (MOZ_UNLIKELY(!aCapacity)) {
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
SetToEmptyBuffer();
|
SetToEmptyBuffer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -236,7 +271,7 @@ auto nsTSubstring<T>::StartBulkWriteImpl(size_type aCapacity,
|
|||||||
char_traits::copy(newData, oldData, aPrefixToPreserve);
|
char_traits::copy(newData, oldData, aPrefixToPreserve);
|
||||||
char_traits::copy(newData + aNewSuffixStart, oldData + aOldSuffixStart,
|
char_traits::copy(newData + aNewSuffixStart, oldData + aOldSuffixStart,
|
||||||
aSuffixLength);
|
aSuffixLength);
|
||||||
::ReleaseData(oldData, oldFlags);
|
ReleaseData(oldData, oldFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newCapacity;
|
return newCapacity;
|
||||||
@@ -247,7 +282,7 @@ void nsTSubstring<T>::FinishBulkWriteImpl(size_type aLength) {
|
|||||||
if (aLength) {
|
if (aLength) {
|
||||||
FinishBulkWriteImplImpl(aLength);
|
FinishBulkWriteImplImpl(aLength);
|
||||||
} else {
|
} else {
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
SetToEmptyBuffer();
|
SetToEmptyBuffer();
|
||||||
}
|
}
|
||||||
AssertValid();
|
AssertValid();
|
||||||
@@ -255,7 +290,7 @@ void nsTSubstring<T>::FinishBulkWriteImpl(size_type aLength) {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void nsTSubstring<T>::Finalize() {
|
void nsTSubstring<T>::Finalize() {
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
// this->mData, this->mLength, and this->mDataFlags are purposefully left
|
// this->mData, this->mLength, and this->mDataFlags are purposefully left
|
||||||
// dangling
|
// dangling
|
||||||
}
|
}
|
||||||
@@ -436,7 +471,7 @@ bool nsTSubstring<T>::AssignASCII(const char* aData, size_type aLength,
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void nsTSubstring<T>::AssignLiteral(const char_type* aData, size_type aLength) {
|
void nsTSubstring<T>::AssignLiteral(const char_type* aData, size_type aLength) {
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
SetData(const_cast<char_type*>(aData), aLength,
|
SetData(const_cast<char_type*>(aData), aLength,
|
||||||
DataFlags::TERMINATED | DataFlags::LITERAL);
|
DataFlags::TERMINATED | DataFlags::LITERAL);
|
||||||
}
|
}
|
||||||
@@ -471,7 +506,7 @@ bool nsTSubstring<T>::Assign(const self_type& aStr,
|
|||||||
NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED,
|
NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED,
|
||||||
"shared, but not terminated");
|
"shared, but not terminated");
|
||||||
|
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
|
|
||||||
SetData(aStr.mData, aStr.mLength,
|
SetData(aStr.mData, aStr.mLength,
|
||||||
DataFlags::TERMINATED | DataFlags::REFCOUNTED);
|
DataFlags::TERMINATED | DataFlags::REFCOUNTED);
|
||||||
@@ -509,7 +544,7 @@ void nsTSubstring<T>::AssignOwned(self_type&& aStr) {
|
|||||||
MOZ_ASSERT(aStr.mDataFlags & DataFlags::TERMINATED,
|
MOZ_ASSERT(aStr.mDataFlags & DataFlags::TERMINATED,
|
||||||
"shared or owned, but not terminated");
|
"shared or owned, but not terminated");
|
||||||
|
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
|
|
||||||
SetData(aStr.mData, aStr.mLength, aStr.mDataFlags);
|
SetData(aStr.mData, aStr.mLength, aStr.mDataFlags);
|
||||||
aStr.SetToEmptyBuffer();
|
aStr.SetToEmptyBuffer();
|
||||||
@@ -585,7 +620,7 @@ bool nsTSubstring<T>::Assign(const substring_tuple_type& aTuple,
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void nsTSubstring<T>::Adopt(char_type* aData, size_type aLength) {
|
void nsTSubstring<T>::Adopt(char_type* aData, size_type aLength) {
|
||||||
if (aData) {
|
if (aData) {
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
|
|
||||||
if (aLength == size_type(-1)) {
|
if (aLength == size_type(-1)) {
|
||||||
aLength = char_traits::length(aData);
|
aLength = char_traits::length(aData);
|
||||||
@@ -933,7 +968,7 @@ bool nsTSubstring<T>::SetLength(size_type aLength,
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void nsTSubstring<T>::Truncate() {
|
void nsTSubstring<T>::Truncate() {
|
||||||
::ReleaseData(this->mData, this->mDataFlags);
|
ReleaseData(this->mData, this->mDataFlags);
|
||||||
SetToEmptyBuffer();
|
SetToEmptyBuffer();
|
||||||
AssertValid();
|
AssertValid();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
// memory checking. (Limited to avoid quadratic behavior.)
|
// memory checking. (Limited to avoid quadratic behavior.)
|
||||||
const size_t kNsStringBufferMaxPoison = 16;
|
const size_t kNsStringBufferMaxPoison = 16;
|
||||||
|
|
||||||
|
class nsStringBuffer;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class nsTSubstringSplitter;
|
class nsTSubstringSplitter;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -285,6 +286,7 @@ class BulkWriteHandle final {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
|
class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
|
||||||
friend class mozilla::BulkWriteHandle<T>;
|
friend class mozilla::BulkWriteHandle<T>;
|
||||||
|
friend class nsStringBuffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef nsTSubstring<T> self_type;
|
typedef nsTSubstring<T> self_type;
|
||||||
|
|||||||
Reference in New Issue
Block a user