1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/string/src/nsSubstring.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,342 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifdef DEBUG 1.11 +#define ENABLE_STRING_STATS 1.12 +#endif 1.13 + 1.14 +#include "mozilla/Atomics.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 + 1.17 +#ifdef ENABLE_STRING_STATS 1.18 +#include <stdio.h> 1.19 +#endif 1.20 + 1.21 +#include <stdlib.h> 1.22 +#include "nsSubstring.h" 1.23 +#include "nsString.h" 1.24 +#include "nsStringBuffer.h" 1.25 +#include "nsDependentString.h" 1.26 +#include "nsMemory.h" 1.27 +#include "prprf.h" 1.28 +#include "nsStaticAtom.h" 1.29 +#include "nsCOMPtr.h" 1.30 + 1.31 +#include "mozilla/IntegerPrintfMacros.h" 1.32 +#ifdef XP_WIN 1.33 +#include <windows.h> 1.34 +#include <process.h> 1.35 +#define getpid() _getpid() 1.36 +#define pthread_self() GetCurrentThreadId() 1.37 +#else 1.38 +#include <pthread.h> 1.39 +#include <unistd.h> 1.40 +#endif 1.41 + 1.42 +using mozilla::Atomic; 1.43 + 1.44 +// --------------------------------------------------------------------------- 1.45 + 1.46 +static const char16_t gNullChar = 0; 1.47 + 1.48 +char* const nsCharTraits<char>::sEmptyBuffer = 1.49 + (char*) const_cast<char16_t*>(&gNullChar); 1.50 +char16_t* const nsCharTraits<char16_t>::sEmptyBuffer = 1.51 + const_cast<char16_t*>(&gNullChar); 1.52 + 1.53 +// --------------------------------------------------------------------------- 1.54 + 1.55 +#ifdef ENABLE_STRING_STATS 1.56 +class nsStringStats 1.57 + { 1.58 + public: 1.59 + nsStringStats() 1.60 + : mAllocCount(0), mReallocCount(0), mFreeCount(0), mShareCount(0) {} 1.61 + 1.62 + ~nsStringStats() 1.63 + { 1.64 + // this is a hack to suppress duplicate string stats printing 1.65 + // in seamonkey as a result of the string code being linked 1.66 + // into seamonkey and libxpcom! :-( 1.67 + if (!mAllocCount && !mAdoptCount) 1.68 + return; 1.69 + 1.70 + printf("nsStringStats\n"); 1.71 + printf(" => mAllocCount: % 10d\n", int(mAllocCount)); 1.72 + printf(" => mReallocCount: % 10d\n", int(mReallocCount)); 1.73 + printf(" => mFreeCount: % 10d", int(mFreeCount)); 1.74 + if (mAllocCount > mFreeCount) 1.75 + printf(" -- LEAKED %d !!!\n", mAllocCount - mFreeCount); 1.76 + else 1.77 + printf("\n"); 1.78 + printf(" => mShareCount: % 10d\n", int(mShareCount)); 1.79 + printf(" => mAdoptCount: % 10d\n", int(mAdoptCount)); 1.80 + printf(" => mAdoptFreeCount: % 10d", int(mAdoptFreeCount)); 1.81 + if (mAdoptCount > mAdoptFreeCount) 1.82 + printf(" -- LEAKED %d !!!\n", mAdoptCount - mAdoptFreeCount); 1.83 + else 1.84 + printf("\n"); 1.85 + printf(" => Process ID: %" PRIuPTR ", Thread ID: %" PRIuPTR "\n", 1.86 + uintptr_t(getpid()), uintptr_t(pthread_self())); 1.87 + } 1.88 + 1.89 + Atomic<int32_t> mAllocCount; 1.90 + Atomic<int32_t> mReallocCount; 1.91 + Atomic<int32_t> mFreeCount; 1.92 + Atomic<int32_t> mShareCount; 1.93 + Atomic<int32_t> mAdoptCount; 1.94 + Atomic<int32_t> mAdoptFreeCount; 1.95 + }; 1.96 +static nsStringStats gStringStats; 1.97 +#define STRING_STAT_INCREMENT(_s) (gStringStats.m ## _s ## Count)++ 1.98 +#else 1.99 +#define STRING_STAT_INCREMENT(_s) 1.100 +#endif 1.101 + 1.102 +// --------------------------------------------------------------------------- 1.103 + 1.104 +inline void 1.105 +ReleaseData( void* data, uint32_t flags ) 1.106 + { 1.107 + if (flags & nsSubstring::F_SHARED) 1.108 + { 1.109 + nsStringBuffer::FromData(data)->Release(); 1.110 + } 1.111 + else if (flags & nsSubstring::F_OWNED) 1.112 + { 1.113 + nsMemory::Free(data); 1.114 + STRING_STAT_INCREMENT(AdoptFree); 1.115 +#ifdef NS_BUILD_REFCNT_LOGGING 1.116 + // Treat this as destruction of a "StringAdopt" object for leak 1.117 + // tracking purposes. 1.118 + NS_LogDtor(data, "StringAdopt", 1); 1.119 +#endif // NS_BUILD_REFCNT_LOGGING 1.120 + } 1.121 + // otherwise, nothing to do. 1.122 + } 1.123 + 1.124 +// --------------------------------------------------------------------------- 1.125 + 1.126 +// XXX or we could make nsStringBuffer be a friend of nsTAString 1.127 + 1.128 +class nsAStringAccessor : public nsAString 1.129 + { 1.130 + private: 1.131 + nsAStringAccessor(); // NOT IMPLEMENTED 1.132 + 1.133 + public: 1.134 + char_type *data() const { return mData; } 1.135 + size_type length() const { return mLength; } 1.136 + uint32_t flags() const { return mFlags; } 1.137 + 1.138 + void set(char_type *data, size_type len, uint32_t flags) 1.139 + { 1.140 + ReleaseData(mData, mFlags); 1.141 + mData = data; 1.142 + mLength = len; 1.143 + mFlags = flags; 1.144 + } 1.145 + }; 1.146 + 1.147 +class nsACStringAccessor : public nsACString 1.148 + { 1.149 + private: 1.150 + nsACStringAccessor(); // NOT IMPLEMENTED 1.151 + 1.152 + public: 1.153 + char_type *data() const { return mData; } 1.154 + size_type length() const { return mLength; } 1.155 + uint32_t flags() const { return mFlags; } 1.156 + 1.157 + void set(char_type *data, size_type len, uint32_t flags) 1.158 + { 1.159 + ReleaseData(mData, mFlags); 1.160 + mData = data; 1.161 + mLength = len; 1.162 + mFlags = flags; 1.163 + } 1.164 + }; 1.165 + 1.166 +// --------------------------------------------------------------------------- 1.167 + 1.168 +void 1.169 +nsStringBuffer::AddRef() 1.170 + { 1.171 + ++mRefCount; 1.172 + STRING_STAT_INCREMENT(Share); 1.173 + NS_LOG_ADDREF(this, mRefCount, "nsStringBuffer", sizeof(*this)); 1.174 + } 1.175 + 1.176 +void 1.177 +nsStringBuffer::Release() 1.178 + { 1.179 + int32_t count = --mRefCount; 1.180 + NS_LOG_RELEASE(this, count, "nsStringBuffer"); 1.181 + if (count == 0) 1.182 + { 1.183 + STRING_STAT_INCREMENT(Free); 1.184 + free(this); // we were allocated with |malloc| 1.185 + } 1.186 + } 1.187 + 1.188 + /** 1.189 + * Alloc returns a pointer to a new string header with set capacity. 1.190 + */ 1.191 +already_AddRefed<nsStringBuffer> 1.192 +nsStringBuffer::Alloc(size_t size) 1.193 + { 1.194 + NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); 1.195 + NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(uint32_t(-1)) && 1.196 + sizeof(nsStringBuffer) + size > size, 1.197 + "mStorageSize will truncate"); 1.198 + 1.199 + nsStringBuffer *hdr = 1.200 + (nsStringBuffer *) malloc(sizeof(nsStringBuffer) + size); 1.201 + if (hdr) 1.202 + { 1.203 + STRING_STAT_INCREMENT(Alloc); 1.204 + 1.205 + hdr->mRefCount = 1; 1.206 + hdr->mStorageSize = size; 1.207 + NS_LOG_ADDREF(hdr, 1, "nsStringBuffer", sizeof(*hdr)); 1.208 + } 1.209 + return dont_AddRef(hdr); 1.210 + } 1.211 + 1.212 +nsStringBuffer* 1.213 +nsStringBuffer::Realloc(nsStringBuffer* hdr, size_t size) 1.214 + { 1.215 + STRING_STAT_INCREMENT(Realloc); 1.216 + 1.217 + NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); 1.218 + NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(uint32_t(-1)) && 1.219 + sizeof(nsStringBuffer) + size > size, 1.220 + "mStorageSize will truncate"); 1.221 + 1.222 + // no point in trying to save ourselves if we hit this assertion 1.223 + NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string"); 1.224 + 1.225 + // Treat this as a release and addref for refcounting purposes, since we 1.226 + // just asserted that the refcount is 1. If we don't do that, refcount 1.227 + // logging will claim we've leaked all sorts of stuff. 1.228 + NS_LOG_RELEASE(hdr, 0, "nsStringBuffer"); 1.229 + 1.230 + hdr = (nsStringBuffer*) realloc(hdr, sizeof(nsStringBuffer) + size); 1.231 + if (hdr) { 1.232 + NS_LOG_ADDREF(hdr, 1, "nsStringBuffer", sizeof(*hdr)); 1.233 + hdr->mStorageSize = size; 1.234 + } 1.235 + 1.236 + return hdr; 1.237 + } 1.238 + 1.239 +nsStringBuffer* 1.240 +nsStringBuffer::FromString(const nsAString& str) 1.241 + { 1.242 + const nsAStringAccessor* accessor = 1.243 + static_cast<const nsAStringAccessor*>(&str); 1.244 + 1.245 + if (!(accessor->flags() & nsSubstring::F_SHARED)) 1.246 + return nullptr; 1.247 + 1.248 + return FromData(accessor->data()); 1.249 + } 1.250 + 1.251 +nsStringBuffer* 1.252 +nsStringBuffer::FromString(const nsACString& str) 1.253 + { 1.254 + const nsACStringAccessor* accessor = 1.255 + static_cast<const nsACStringAccessor*>(&str); 1.256 + 1.257 + if (!(accessor->flags() & nsCSubstring::F_SHARED)) 1.258 + return nullptr; 1.259 + 1.260 + return FromData(accessor->data()); 1.261 + } 1.262 + 1.263 +void 1.264 +nsStringBuffer::ToString(uint32_t len, nsAString &str, 1.265 + bool aMoveOwnership) 1.266 + { 1.267 + char16_t* data = static_cast<char16_t*>(Data()); 1.268 + 1.269 + nsAStringAccessor* accessor = static_cast<nsAStringAccessor*>(&str); 1.270 + NS_ASSERTION(data[len] == char16_t(0), "data should be null terminated"); 1.271 + 1.272 + // preserve class flags 1.273 + uint32_t flags = accessor->flags(); 1.274 + flags = (flags & 0xFFFF0000) | nsSubstring::F_SHARED | nsSubstring::F_TERMINATED; 1.275 + 1.276 + if (!aMoveOwnership) { 1.277 + AddRef(); 1.278 + } 1.279 + accessor->set(data, len, flags); 1.280 + } 1.281 + 1.282 +void 1.283 +nsStringBuffer::ToString(uint32_t len, nsACString &str, 1.284 + bool aMoveOwnership) 1.285 + { 1.286 + char* data = static_cast<char*>(Data()); 1.287 + 1.288 + nsACStringAccessor* accessor = static_cast<nsACStringAccessor*>(&str); 1.289 + NS_ASSERTION(data[len] == char(0), "data should be null terminated"); 1.290 + 1.291 + // preserve class flags 1.292 + uint32_t flags = accessor->flags(); 1.293 + flags = (flags & 0xFFFF0000) | nsCSubstring::F_SHARED | nsCSubstring::F_TERMINATED; 1.294 + 1.295 + if (!aMoveOwnership) { 1.296 + AddRef(); 1.297 + } 1.298 + accessor->set(data, len, flags); 1.299 + } 1.300 + 1.301 +size_t 1.302 +nsStringBuffer::SizeOfIncludingThisMustBeUnshared(mozilla::MallocSizeOf aMallocSizeOf) const 1.303 + { 1.304 + NS_ASSERTION(!IsReadonly(), 1.305 + "shared StringBuffer in SizeOfIncludingThisMustBeUnshared"); 1.306 + return aMallocSizeOf(this); 1.307 + } 1.308 + 1.309 +size_t 1.310 +nsStringBuffer::SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const 1.311 + { 1.312 + if (!IsReadonly()) 1.313 + { 1.314 + return SizeOfIncludingThisMustBeUnshared(aMallocSizeOf); 1.315 + } 1.316 + return 0; 1.317 + } 1.318 + 1.319 +size_t 1.320 +nsStringBuffer::SizeOfIncludingThisEvenIfShared(mozilla::MallocSizeOf aMallocSizeOf) const 1.321 + { 1.322 + return aMallocSizeOf(this); 1.323 + } 1.324 + 1.325 +// --------------------------------------------------------------------------- 1.326 + 1.327 + 1.328 + // define nsSubstring 1.329 +#include "string-template-def-unichar.h" 1.330 +#include "nsTSubstring.cpp" 1.331 +#include "string-template-undef.h" 1.332 + 1.333 + // define nsCSubstring 1.334 +#include "string-template-def-char.h" 1.335 +#include "nsTSubstring.cpp" 1.336 +#include "string-template-undef.h" 1.337 + 1.338 +// Check that internal and external strings have the same size. 1.339 +// See https://bugzilla.mozilla.org/show_bug.cgi?id=430581 1.340 + 1.341 +#include "prlog.h" 1.342 +#include "nsXPCOMStrings.h" 1.343 + 1.344 +static_assert(sizeof(nsStringContainer_base) == sizeof(nsSubstring), 1.345 + "internal and external strings must have the same size");