| File: | root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h |
| Warning: | line 189, column 7 Value stored to 'count' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | #ifndef StringBuffer_h__ |
| 8 | #define StringBuffer_h__ |
| 9 | |
| 10 | #include <atomic> |
| 11 | #include <cstring> |
| 12 | #include "mozilla/CheckedInt.h" |
| 13 | #include "mozilla/MemoryReporting.h" |
| 14 | #include "mozilla/Assertions.h" |
| 15 | #include "mozilla/AlreadyAddRefed.h" |
| 16 | #include "mozilla/Maybe.h" |
| 17 | #include "mozilla/RefCounted.h" |
| 18 | #include "mozmemory.h" |
| 19 | |
| 20 | namespace mozilla { |
| 21 | |
| 22 | /** |
| 23 | * This structure precedes the string buffers "we" allocate. It may be the |
| 24 | * case that nsTAString::mData does not point to one of these special |
| 25 | * buffers. The mDataFlags member variable distinguishes the buffer type. |
| 26 | * |
| 27 | * When this header is in use, it enables reference counting, and capacity |
| 28 | * tracking. NOTE: A string buffer can be modified only if its reference |
| 29 | * count is 1. |
| 30 | */ |
| 31 | class StringBuffer { |
| 32 | private: |
| 33 | std::atomic<uint32_t> mRefCount; |
| 34 | uint32_t mStorageSize; |
| 35 | |
| 36 | public: |
| 37 | MOZ_DECLARE_REFCOUNTED_TYPENAME(StringBuffer)const char* typeName() const { return "StringBuffer"; } size_t typeSize() const { return sizeof(*this); } |
| 38 | |
| 39 | /** |
| 40 | * Allocates a new string buffer, with given size in bytes and a |
| 41 | * reference count of one. When the string buffer is no longer needed, |
| 42 | * it should be released via Release. |
| 43 | * |
| 44 | * It is up to the caller to set the bytes corresponding to the string |
| 45 | * buffer by calling the Data method to fetch the raw data pointer. Care |
| 46 | * must be taken to properly null terminate the character array. The |
| 47 | * storage size can be greater than the length of the actual string |
| 48 | * (i.e., it is not required that the null terminator appear in the last |
| 49 | * storage unit of the string buffer's data). |
| 50 | * |
| 51 | * This guarantees that StorageSize() returns aSize if the returned |
| 52 | * buffer is non-null. Some callers like nsAttrValue rely on it. |
| 53 | * |
| 54 | * @return new string buffer or null if out of memory. |
| 55 | */ |
| 56 | static already_AddRefed<StringBuffer> Alloc( |
| 57 | size_t aSize, mozilla::Maybe<arena_id_t> aArena = mozilla::Nothing()) { |
| 58 | MOZ_ASSERT(aSize != 0, "zero capacity allocation not allowed")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aSize != 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aSize != 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aSize != 0" " (" "zero capacity allocation not allowed" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 58); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSize != 0" ") (" "zero capacity allocation not allowed" ")"); do { MOZ_CrashSequence (__null, 58); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 59 | MOZ_ASSERT(sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) &&do { static_assert( mozilla::detail::AssertionConditionType< decltype(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" " (" "mStorageSize will truncate" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 61); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" ") (" "mStorageSize will truncate" ")"); do { MOZ_CrashSequence (__null, 61); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false) |
| 60 | sizeof(StringBuffer) + aSize > aSize,do { static_assert( mozilla::detail::AssertionConditionType< decltype(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" " (" "mStorageSize will truncate" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 61); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" ") (" "mStorageSize will truncate" ")"); do { MOZ_CrashSequence (__null, 61); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false) |
| 61 | "mStorageSize will truncate")do { static_assert( mozilla::detail::AssertionConditionType< decltype(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" " (" "mStorageSize will truncate" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 61); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" ") (" "mStorageSize will truncate" ")"); do { MOZ_CrashSequence (__null, 61); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 62 | |
| 63 | size_t bytes = sizeof(StringBuffer) + aSize; |
| 64 | void* hdr = aArena ? moz_arena_malloc(*aArena, bytes) : malloc(bytes); |
| 65 | if (!hdr) { |
| 66 | return nullptr; |
| 67 | } |
| 68 | return ConstructInPlace(hdr, aSize); |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * Like Alloc, but use aBuffer instead of allocating a new buffer. This can |
| 73 | * be used when the caller already has a malloced buffer of the right size and |
| 74 | * allocating a new one would be too expensive. |
| 75 | * |
| 76 | * aStorageSize must be the string's length in bytes (including the null |
| 77 | * terminator). The caller must initialize all of these bytes either before or |
| 78 | * after calling this function. |
| 79 | * |
| 80 | * @return the new StringBuffer header. |
| 81 | */ |
| 82 | static already_AddRefed<StringBuffer> ConstructInPlace(void* aBuffer, |
| 83 | size_t aStorageSize) { |
| 84 | MOZ_ASSERT(aBuffer, "must have a valid buffer")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aBuffer)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aBuffer))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aBuffer" " (" "must have a valid buffer" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 84); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBuffer" ") (" "must have a valid buffer" ")"); do { MOZ_CrashSequence(__null , 84); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 85 | MOZ_ASSERT(aStorageSize != 0, "zero capacity StringBuffer not allowed")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aStorageSize != 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aStorageSize != 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aStorageSize != 0" " (" "zero capacity StringBuffer not allowed" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStorageSize != 0" ") (" "zero capacity StringBuffer not allowed" ")"); do { MOZ_CrashSequence (__null, 85); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 86 | auto* hdr = new (aBuffer) StringBuffer(); |
| 87 | hdr->mRefCount = 1; |
| 88 | hdr->mStorageSize = aStorageSize; |
| 89 | detail::RefCountLogger::logAddRef(hdr, 1); |
| 90 | return already_AddRefed(hdr); |
| 91 | } |
| 92 | |
| 93 | /** |
| 94 | * Returns true if (aLength + 1) * sizeof(CharT) is a valid allocation size |
| 95 | * for Alloc. Adds +1 to aLength for the null-terminator. |
| 96 | */ |
| 97 | template <typename CharT> |
| 98 | static constexpr bool IsValidLength(size_t aLength) { |
| 99 | auto checkedSize = |
| 100 | (CheckedUint32(aLength) + 1) * sizeof(CharT) + sizeof(StringBuffer); |
| 101 | return checkedSize.isValid(); |
| 102 | } |
| 103 | |
| 104 | /** |
| 105 | * Returns a string buffer initialized with the given string on it, or null on |
| 106 | * OOM. |
| 107 | * Note that this will allocate extra space for the trailing null byte, which |
| 108 | * this method will add. |
| 109 | */ |
| 110 | static already_AddRefed<StringBuffer> Create(const char16_t* aData, |
| 111 | size_t aLength) { |
| 112 | return DoCreate(aData, aLength); |
| 113 | } |
| 114 | static already_AddRefed<StringBuffer> Create(const char* aData, |
| 115 | size_t aLength) { |
| 116 | return DoCreate(aData, aLength); |
| 117 | } |
| 118 | static already_AddRefed<StringBuffer> Create(const unsigned char* aData, |
| 119 | size_t aLength) { |
| 120 | return DoCreate(aData, aLength); |
| 121 | } |
| 122 | |
| 123 | /** |
| 124 | * Resizes the given string buffer to the specified storage size. This |
| 125 | * method must not be called on a readonly string buffer. Use this API |
| 126 | * carefully!! |
| 127 | * |
| 128 | * This method behaves like the ANSI-C realloc function. (i.e., If the |
| 129 | * allocation fails, null will be returned and the given string buffer |
| 130 | * will remain unmodified.) |
| 131 | * |
| 132 | * @see IsReadonly |
| 133 | */ |
| 134 | static StringBuffer* Realloc( |
| 135 | StringBuffer* aHdr, size_t aSize, |
| 136 | mozilla::Maybe<arena_id_t> aArena = mozilla::Nothing()) { |
| 137 | MOZ_ASSERT(aSize != 0, "zero capacity allocation not allowed")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aSize != 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aSize != 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aSize != 0" " (" "zero capacity allocation not allowed" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSize != 0" ") (" "zero capacity allocation not allowed" ")"); do { MOZ_CrashSequence (__null, 137); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 138 | MOZ_ASSERT(sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) &&do { static_assert( mozilla::detail::AssertionConditionType< decltype(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" " (" "mStorageSize will truncate" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" ") (" "mStorageSize will truncate" ")"); do { MOZ_CrashSequence (__null, 140); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false) |
| 139 | sizeof(StringBuffer) + aSize > aSize,do { static_assert( mozilla::detail::AssertionConditionType< decltype(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" " (" "mStorageSize will truncate" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" ") (" "mStorageSize will truncate" ")"); do { MOZ_CrashSequence (__null, 140); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false) |
| 140 | "mStorageSize will truncate")do { static_assert( mozilla::detail::AssertionConditionType< decltype(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(sizeof(StringBuffer) + aSize <= size_t(uint32_t(- 1)) && sizeof(StringBuffer) + aSize > aSize))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" " (" "mStorageSize will truncate" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sizeof(StringBuffer) + aSize <= size_t(uint32_t(-1)) && sizeof(StringBuffer) + aSize > aSize" ") (" "mStorageSize will truncate" ")"); do { MOZ_CrashSequence (__null, 140); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 141 | |
| 142 | // no point in trying to save ourselves if we hit this assertion |
| 143 | MOZ_ASSERT(!aHdr->IsReadonly(), "|Realloc| attempted on readonly string")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aHdr->IsReadonly())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aHdr->IsReadonly()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!aHdr->IsReadonly()" " (" "|Realloc| attempted on readonly string" ")", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/mozilla/StringBuffer.h" , 143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aHdr->IsReadonly()" ") (" "|Realloc| attempted on readonly string" ")"); do { MOZ_CrashSequence (__null, 143); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 144 | |
| 145 | // Treat this as a release and addref for refcounting purposes, since we |
| 146 | // just asserted that the refcount is 1. If we don't do that, refcount |
| 147 | // logging will claim we've leaked all sorts of stuff. |
| 148 | { |
| 149 | detail::RefCountLogger::ReleaseLogger logger(aHdr); |
| 150 | logger.logRelease(0); |
| 151 | } |
| 152 | |
| 153 | size_t bytes = sizeof(StringBuffer) + aSize; |
| 154 | aHdr = aArena ? (StringBuffer*)moz_arena_realloc(*aArena, aHdr, bytes) |
| 155 | : (StringBuffer*)realloc(aHdr, bytes); |
| 156 | if (aHdr) { |
| 157 | detail::RefCountLogger::logAddRef(aHdr, 1); |
| 158 | aHdr->mStorageSize = aSize; |
| 159 | } |
| 160 | |
| 161 | return aHdr; |
| 162 | } |
| 163 | |
| 164 | void AddRef() { |
| 165 | // Memory synchronization is not required when incrementing a |
| 166 | // reference count. The first increment of a reference count on a |
| 167 | // thread is not important, since the first use of the object on a |
| 168 | // thread can happen before it. What is important is the transfer |
| 169 | // of the pointer to that thread, which may happen prior to the |
| 170 | // first increment on that thread. The necessary memory |
| 171 | // synchronization is done by the mechanism that transfers the |
| 172 | // pointer between threads. |
| 173 | uint32_t count = mRefCount.fetch_add(1, std::memory_order_relaxed) + 1; |
| 174 | detail::RefCountLogger::logAddRef(this, count); |
| 175 | } |
| 176 | |
| 177 | void Release() { |
| 178 | // Since this may be the last release on this thread, we need release |
| 179 | // semantics so that prior writes on this thread are visible to the thread |
| 180 | // that destroys the object when it reads mValue with acquire semantics. |
| 181 | detail::RefCountLogger::ReleaseLogger logger(this); |
| 182 | uint32_t count = mRefCount.fetch_sub(1, std::memory_order_release) - 1; |
| 183 | logger.logRelease(count); |
| 184 | if (count == 0) { |
| 185 | // We're going to destroy the object on this thread, so we need acquire |
| 186 | // semantics to synchronize with the memory released by the last release |
| 187 | // on other threads, that is, to ensure that writes prior to that release |
| 188 | // are now visible on this thread. |
| 189 | count = mRefCount.load(std::memory_order_acquire); |
Value stored to 'count' is never read | |
| 190 | free(this); // We were allocated with malloc. |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | /** |
| 195 | * This method returns the string buffer corresponding to the given data |
| 196 | * pointer. The data pointer must have been returned previously by a |
| 197 | * call to the StringBuffer::Data method. |
| 198 | */ |
| 199 | static StringBuffer* FromData(void* aData) { |
| 200 | return reinterpret_cast<StringBuffer*>(aData) - 1; |
| 201 | } |
| 202 | |
| 203 | /** |
| 204 | * This method returns the data pointer for this string buffer. |
| 205 | */ |
| 206 | void* Data() const { |
| 207 | return const_cast<char*>(reinterpret_cast<const char*>(this + 1)); |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * This function returns the storage size of a string buffer in bytes. |
| 212 | * This value is the same value that was originally passed to Alloc (or |
| 213 | * Realloc). |
| 214 | */ |
| 215 | uint32_t StorageSize() const { return mStorageSize; } |
| 216 | |
| 217 | /** |
| 218 | * This function returns the allocation size of a string buffer in bytes. |
| 219 | * This includes the size of the StringBuffer header. |
| 220 | */ |
| 221 | uint32_t AllocationSize() const { |
| 222 | return sizeof(StringBuffer) + StorageSize(); |
| 223 | } |
| 224 | |
| 225 | /** |
| 226 | * If this method returns false, then the caller can be sure that their |
| 227 | * reference to the string buffer is the only reference to the string |
| 228 | * buffer, and therefore it has exclusive access to the string buffer and |
| 229 | * associated data. However, if this function returns true, then other |
| 230 | * consumers may rely on the data in this buffer being immutable and |
| 231 | * other threads may access this buffer simultaneously. |
| 232 | */ |
| 233 | bool IsReadonly() const { |
| 234 | // This doesn't lead to the destruction of the buffer, so we don't |
| 235 | // need to perform acquire memory synchronization for the normal |
| 236 | // reason that a reference count needs acquire synchronization |
| 237 | // (ensuring that all writes to the object made on other threads are |
| 238 | // visible to the thread destroying the object). |
| 239 | // |
| 240 | // We then need to consider the possibility that there were prior |
| 241 | // writes to the buffer on a different thread: one that has either |
| 242 | // since released its reference count, or one that also has access |
| 243 | // to this buffer through the same reference. There are two ways |
| 244 | // for that to happen: either the buffer pointer or a data structure |
| 245 | // (e.g., string object) pointing to the buffer was transferred from |
| 246 | // one thread to another, or the data structure pointing to the |
| 247 | // buffer was already visible on both threads. In the first case |
| 248 | // (transfer), the transfer of data from one thread to another would |
| 249 | // have handled the memory synchronization. In the latter case |
| 250 | // (data structure visible on both threads), the caller needed some |
| 251 | // sort of higher level memory synchronization to protect against |
| 252 | // the string object being mutated at the same time on multiple |
| 253 | // threads. |
| 254 | |
| 255 | // See bug 1603504. TSan might complain about a race when using |
| 256 | // memory_order_relaxed, so use memory_order_acquire for making TSan |
| 257 | // happy. |
| 258 | #if defined(MOZ_TSAN) |
| 259 | return mRefCount.load(std::memory_order_acquire) > 1; |
| 260 | #else |
| 261 | return mRefCount.load(std::memory_order_relaxed) > 1; |
| 262 | #endif |
| 263 | } |
| 264 | |
| 265 | /** |
| 266 | * Alias for IsReadOnly. |
| 267 | */ |
| 268 | bool HasMultipleReferences() const { return IsReadonly(); } |
| 269 | |
| 270 | #ifdef DEBUG1 |
| 271 | /** |
| 272 | * Returns the buffer's reference count. This is only exposed for logging and |
| 273 | * testing purposes. |
| 274 | */ |
| 275 | uint32_t RefCount() const { |
| 276 | return mRefCount.load(std::memory_order_acquire); |
| 277 | } |
| 278 | #endif |
| 279 | |
| 280 | /** |
| 281 | * This measures the size only if the StringBuffer is unshared. |
| 282 | */ |
| 283 | size_t SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const { |
| 284 | return IsReadonly() ? 0 : aMallocSizeOf(this); |
| 285 | } |
| 286 | |
| 287 | /** |
| 288 | * This measures the size regardless of whether the StringBuffer is |
| 289 | * unshared. |
| 290 | * |
| 291 | * WARNING: Only use this if you really know what you are doing, because |
| 292 | * it can easily lead to double-counting strings. If you do use them, |
| 293 | * please explain clearly in a comment why it's safe and won't lead to |
| 294 | * double-counting. |
| 295 | */ |
| 296 | size_t SizeOfIncludingThisEvenIfShared(MallocSizeOf aMallocSizeOf) const { |
| 297 | return aMallocSizeOf(this); |
| 298 | } |
| 299 | |
| 300 | private: |
| 301 | template <typename CharT> |
| 302 | static already_AddRefed<StringBuffer> DoCreate(const CharT* aData, |
| 303 | size_t aLength) { |
| 304 | StringBuffer* buffer = Alloc((aLength + 1) * sizeof(CharT)).take(); |
| 305 | if (MOZ_LIKELY(buffer)(__builtin_expect(!!(buffer), 1))) { |
| 306 | auto* data = reinterpret_cast<CharT*>(buffer->Data()); |
| 307 | memcpy(data, aData, aLength * sizeof(CharT)); |
| 308 | data[aLength] = 0; |
| 309 | } |
| 310 | return already_AddRefed(buffer); |
| 311 | } |
| 312 | }; |
| 313 | |
| 314 | } // namespace mozilla |
| 315 | |
| 316 | #endif |