LCOV - code coverage report
Current view: top level - xpcom/string - nsSubstring.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 78 167 46.7 %
Date: 2017-07-14 16:53:18 Functions: 14 38 36.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #ifdef DEBUG
       8             : #define ENABLE_STRING_STATS
       9             : #endif
      10             : 
      11             : #include "mozilla/Atomics.h"
      12             : #include "mozilla/MemoryReporting.h"
      13             : 
      14             : #ifdef ENABLE_STRING_STATS
      15             : #include <stdio.h>
      16             : #endif
      17             : 
      18             : #include <stdlib.h>
      19             : #include "nsSubstring.h"
      20             : #include "nsString.h"
      21             : #include "nsStringBuffer.h"
      22             : #include "nsDependentString.h"
      23             : #include "nsMemory.h"
      24             : #include "prprf.h"
      25             : #include "nsStaticAtom.h"
      26             : #include "nsCOMPtr.h"
      27             : 
      28             : #include "mozilla/IntegerPrintfMacros.h"
      29             : #ifdef XP_WIN
      30             : #include <windows.h>
      31             : #include <process.h>
      32             : #define getpid() _getpid()
      33             : #define pthread_self() GetCurrentThreadId()
      34             : #else
      35             : #include <pthread.h>
      36             : #include <unistd.h>
      37             : #endif
      38             : 
      39             : using mozilla::Atomic;
      40             : 
      41             : // ---------------------------------------------------------------------------
      42             : 
      43             : static const char16_t gNullChar = 0;
      44             : 
      45             : char* const nsCharTraits<char>::sEmptyBuffer =
      46             :   (char*)const_cast<char16_t*>(&gNullChar);
      47             : char16_t* const nsCharTraits<char16_t>::sEmptyBuffer =
      48             :   const_cast<char16_t*>(&gNullChar);
      49             : 
      50             : // ---------------------------------------------------------------------------
      51             : 
      52             : #ifdef ENABLE_STRING_STATS
      53             : class nsStringStats
      54             : {
      55             : public:
      56           3 :   nsStringStats()
      57           3 :     : mAllocCount(0)
      58             :     , mReallocCount(0)
      59             :     , mFreeCount(0)
      60           3 :     , mShareCount(0)
      61             :   {
      62           3 :   }
      63             : 
      64           0 :   ~nsStringStats()
      65           0 :   {
      66             :     // this is a hack to suppress duplicate string stats printing
      67             :     // in seamonkey as a result of the string code being linked
      68             :     // into seamonkey and libxpcom! :-(
      69           0 :     if (!mAllocCount && !mAdoptCount) {
      70           0 :       return;
      71             :     }
      72             : 
      73           0 :     printf("nsStringStats\n");
      74           0 :     printf(" => mAllocCount:     % 10d\n", int(mAllocCount));
      75           0 :     printf(" => mReallocCount:   % 10d\n", int(mReallocCount));
      76           0 :     printf(" => mFreeCount:      % 10d", int(mFreeCount));
      77           0 :     if (mAllocCount > mFreeCount) {
      78           0 :       printf("  --  LEAKED %d !!!\n", mAllocCount - mFreeCount);
      79             :     } else {
      80           0 :       printf("\n");
      81             :     }
      82           0 :     printf(" => mShareCount:     % 10d\n", int(mShareCount));
      83           0 :     printf(" => mAdoptCount:     % 10d\n", int(mAdoptCount));
      84           0 :     printf(" => mAdoptFreeCount: % 10d", int(mAdoptFreeCount));
      85           0 :     if (mAdoptCount > mAdoptFreeCount) {
      86           0 :       printf("  --  LEAKED %d !!!\n", mAdoptCount - mAdoptFreeCount);
      87             :     } else {
      88           0 :       printf("\n");
      89             :     }
      90           0 :     printf(" => Process ID: %" PRIuPTR ", Thread ID: %" PRIuPTR "\n",
      91           0 :            uintptr_t(getpid()), uintptr_t(pthread_self()));
      92           0 :   }
      93             : 
      94             :   Atomic<int32_t> mAllocCount;
      95             :   Atomic<int32_t> mReallocCount;
      96             :   Atomic<int32_t> mFreeCount;
      97             :   Atomic<int32_t> mShareCount;
      98             :   Atomic<int32_t> mAdoptCount;
      99             :   Atomic<int32_t> mAdoptFreeCount;
     100             : };
     101           3 : static nsStringStats gStringStats;
     102             : #define STRING_STAT_INCREMENT(_s) (gStringStats.m ## _s ## Count)++
     103             : #else
     104             : #define STRING_STAT_INCREMENT(_s)
     105             : #endif
     106             : 
     107             : // ---------------------------------------------------------------------------
     108             : 
     109             : void
     110     1274998 : ReleaseData(void* aData, nsAString::DataFlags aFlags)
     111             : {
     112     1274998 :   if (aFlags & nsAString::DataFlags::SHARED) {
     113      118072 :     nsStringBuffer::FromData(aData)->Release();
     114     1156939 :   } else if (aFlags & nsAString::DataFlags::OWNED) {
     115        5357 :     free(aData);
     116        5357 :     STRING_STAT_INCREMENT(AdoptFree);
     117             :     // Treat this as destruction of a "StringAdopt" object for leak
     118             :     // tracking purposes.
     119        5357 :     MOZ_LOG_DTOR(aData, "StringAdopt", 1);
     120             :   }
     121             :   // otherwise, nothing to do.
     122     1275002 : }
     123             : 
     124             : // ---------------------------------------------------------------------------
     125             : 
     126             : // XXX or we could make nsStringBuffer be a friend of nsTAString
     127             : 
     128             : class nsAStringAccessor : public nsAString
     129             : {
     130             : private:
     131             :   nsAStringAccessor(); // NOT IMPLEMENTED
     132             : 
     133             : public:
     134        1281 :   char_type* data() const
     135             :   {
     136        1281 :     return mData;
     137             :   }
     138             :   size_type length() const
     139             :   {
     140             :     return mLength;
     141             :   }
     142        8025 :   DataFlags flags() const
     143             :   {
     144        8025 :     return mDataFlags;
     145             :   }
     146             : 
     147        4675 :   void set(char_type* aData, size_type aLen, DataFlags aDataFlags)
     148             :   {
     149        4675 :     ReleaseData(mData, mDataFlags);
     150        4675 :     mData = aData;
     151        4675 :     mLength = aLen;
     152        4675 :     mDataFlags = aDataFlags;
     153        4675 :   }
     154             : };
     155             : 
     156             : class nsACStringAccessor : public nsACString
     157             : {
     158             : private:
     159             :   nsACStringAccessor(); // NOT IMPLEMENTED
     160             : 
     161             : public:
     162           0 :   char_type* data() const
     163             :   {
     164           0 :     return mData;
     165             :   }
     166             :   size_type length() const
     167             :   {
     168             :     return mLength;
     169             :   }
     170           0 :   DataFlags flags() const
     171             :   {
     172           0 :     return mDataFlags;
     173             :   }
     174             : 
     175           0 :   void set(char_type* aData, size_type aLen, DataFlags aDataFlags)
     176             :   {
     177           0 :     ReleaseData(mData, mDataFlags);
     178           0 :     mData = aData;
     179           0 :     mLength = aLen;
     180           0 :     mDataFlags = aDataFlags;
     181           0 :   }
     182             : };
     183             : 
     184             : // ---------------------------------------------------------------------------
     185             : 
     186             : void
     187       76206 : nsStringBuffer::AddRef()
     188             : {
     189             :   // Memory synchronization is not required when incrementing a
     190             :   // reference count.  The first increment of a reference count on a
     191             :   // thread is not important, since the first use of the object on a
     192             :   // thread can happen before it.  What is important is the transfer
     193             :   // of the pointer to that thread, which may happen prior to the
     194             :   // first increment on that thread.  The necessary memory
     195             :   // synchronization is done by the mechanism that transfers the
     196             :   // pointer between threads.
     197             : #ifdef NS_BUILD_REFCNT_LOGGING
     198             :   uint32_t count =
     199             : #endif
     200      152412 :     mRefCount.fetch_add(1, std::memory_order_relaxed)
     201             : #ifdef NS_BUILD_REFCNT_LOGGING
     202       76206 :     + 1
     203             : #endif
     204             :     ;
     205       76206 :   STRING_STAT_INCREMENT(Share);
     206       76206 :   NS_LOG_ADDREF(this, count, "nsStringBuffer", sizeof(*this));
     207       76206 : }
     208             : 
     209             : void
     210      122013 : nsStringBuffer::Release()
     211             : {
     212             :   // Since this may be the last release on this thread, we need
     213             :   // release semantics so that prior writes on this thread are visible
     214             :   // to the thread that destroys the object when it reads mValue with
     215             :   // acquire semantics.
     216      244026 :   uint32_t count = mRefCount.fetch_sub(1, std::memory_order_release) - 1;
     217      122013 :   NS_LOG_RELEASE(this, count, "nsStringBuffer");
     218      122013 :   if (count == 0) {
     219             :     // We're going to destroy the object on this thread, so we need
     220             :     // acquire semantics to synchronize with the memory released by
     221             :     // the last release on other threads, that is, to ensure that
     222             :     // writes prior to that release are now visible on this thread.
     223      125164 :     count = mRefCount.load(std::memory_order_acquire);
     224             : 
     225       62582 :     STRING_STAT_INCREMENT(Free);
     226       62582 :     free(this); // we were allocated with |malloc|
     227             :   }
     228      122013 : }
     229             : 
     230             : /**
     231             :  * Alloc returns a pointer to a new string header with set capacity.
     232             :  */
     233             : already_AddRefed<nsStringBuffer>
     234       94259 : nsStringBuffer::Alloc(size_t aSize)
     235             : {
     236       94259 :   NS_ASSERTION(aSize != 0, "zero capacity allocation not allowed");
     237       94259 :   NS_ASSERTION(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) &&
     238             :                sizeof(nsStringBuffer) + aSize > aSize,
     239             :                "mStorageSize will truncate");
     240             : 
     241             :   nsStringBuffer* hdr =
     242       94260 :     (nsStringBuffer*)malloc(sizeof(nsStringBuffer) + aSize);
     243       94260 :   if (hdr) {
     244       94260 :     STRING_STAT_INCREMENT(Alloc);
     245             : 
     246       94260 :     hdr->mRefCount = 1;
     247       94260 :     hdr->mStorageSize = aSize;
     248       94260 :     NS_LOG_ADDREF(hdr, 1, "nsStringBuffer", sizeof(*hdr));
     249             :   }
     250       94260 :   return dont_AddRef(hdr);
     251             : }
     252             : 
     253             : nsStringBuffer*
     254        2400 : nsStringBuffer::Realloc(nsStringBuffer* aHdr, size_t aSize)
     255             : {
     256        2400 :   STRING_STAT_INCREMENT(Realloc);
     257             : 
     258        2400 :   NS_ASSERTION(aSize != 0, "zero capacity allocation not allowed");
     259        2400 :   NS_ASSERTION(sizeof(nsStringBuffer) + aSize <= size_t(uint32_t(-1)) &&
     260             :                sizeof(nsStringBuffer) + aSize > aSize,
     261             :                "mStorageSize will truncate");
     262             : 
     263             :   // no point in trying to save ourselves if we hit this assertion
     264        2400 :   NS_ASSERTION(!aHdr->IsReadonly(), "|Realloc| attempted on readonly string");
     265             : 
     266             :   // Treat this as a release and addref for refcounting purposes, since we
     267             :   // just asserted that the refcount is 1.  If we don't do that, refcount
     268             :   // logging will claim we've leaked all sorts of stuff.
     269        2400 :   NS_LOG_RELEASE(aHdr, 0, "nsStringBuffer");
     270             : 
     271        2400 :   aHdr = (nsStringBuffer*)realloc(aHdr, sizeof(nsStringBuffer) + aSize);
     272        2400 :   if (aHdr) {
     273        2400 :     NS_LOG_ADDREF(aHdr, 1, "nsStringBuffer", sizeof(*aHdr));
     274        2400 :     aHdr->mStorageSize = aSize;
     275             :   }
     276             : 
     277        2400 :   return aHdr;
     278             : }
     279             : 
     280             : nsStringBuffer*
     281        8025 : nsStringBuffer::FromString(const nsAString& aStr)
     282             : {
     283             :   const nsAStringAccessor* accessor =
     284        8025 :     static_cast<const nsAStringAccessor*>(&aStr);
     285             : 
     286        8025 :   if (!(accessor->flags() & nsAString::DataFlags::SHARED)) {
     287        6744 :     return nullptr;
     288             :   }
     289             : 
     290        1281 :   return FromData(accessor->data());
     291             : }
     292             : 
     293             : nsStringBuffer*
     294           0 : nsStringBuffer::FromString(const nsACString& aStr)
     295             : {
     296             :   const nsACStringAccessor* accessor =
     297           0 :     static_cast<const nsACStringAccessor*>(&aStr);
     298             : 
     299           0 :   if (!(accessor->flags() & nsACString::DataFlags::SHARED)) {
     300           0 :     return nullptr;
     301             :   }
     302             : 
     303           0 :   return FromData(accessor->data());
     304             : }
     305             : 
     306             : void
     307        4675 : nsStringBuffer::ToString(uint32_t aLen, nsAString& aStr,
     308             :                          bool aMoveOwnership)
     309             : {
     310        4675 :   char16_t* data = static_cast<char16_t*>(Data());
     311             : 
     312        4675 :   nsAStringAccessor* accessor = static_cast<nsAStringAccessor*>(&aStr);
     313        4675 :   MOZ_DIAGNOSTIC_ASSERT(data[aLen] == char16_t(0),
     314             :                         "data should be null terminated");
     315             : 
     316             :   nsAString::DataFlags flags =
     317        4675 :     nsAString::DataFlags::SHARED | nsAString::DataFlags::TERMINATED;
     318             : 
     319        4675 :   if (!aMoveOwnership) {
     320        4675 :     AddRef();
     321             :   }
     322        4675 :   accessor->set(data, aLen, flags);
     323        4675 : }
     324             : 
     325             : void
     326           0 : nsStringBuffer::ToString(uint32_t aLen, nsACString& aStr,
     327             :                          bool aMoveOwnership)
     328             : {
     329           0 :   char* data = static_cast<char*>(Data());
     330             : 
     331           0 :   nsACStringAccessor* accessor = static_cast<nsACStringAccessor*>(&aStr);
     332           0 :   MOZ_DIAGNOSTIC_ASSERT(data[aLen] == char(0),
     333             :                         "data should be null terminated");
     334             : 
     335             :   nsACString::DataFlags flags =
     336           0 :     nsACString::DataFlags::SHARED | nsACString::DataFlags::TERMINATED;
     337             : 
     338           0 :   if (!aMoveOwnership) {
     339           0 :     AddRef();
     340             :   }
     341           0 :   accessor->set(data, aLen, flags);
     342           0 : }
     343             : 
     344             : size_t
     345         177 : nsStringBuffer::SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const
     346             : {
     347         177 :   return IsReadonly() ? 0 : aMallocSizeOf(this);
     348             : }
     349             : 
     350             : size_t
     351           0 : nsStringBuffer::SizeOfIncludingThisEvenIfShared(mozilla::MallocSizeOf aMallocSizeOf) const
     352             : {
     353           0 :   return aMallocSizeOf(this);
     354             : }
     355             : 
     356             : // ---------------------------------------------------------------------------
     357             : 
     358             : // define nsAString
     359             : #include "string-template-def-unichar.h"
     360             : #include "nsTSubstring.cpp"
     361             : #include "string-template-undef.h"
     362             : 
     363             : // define nsACString
     364             : #include "string-template-def-char.h"
     365             : #include "nsTSubstring.cpp"
     366             : #include "string-template-undef.h"
     367             : 
     368             : // Provide rust bindings to the nsA[C]String types
     369             : extern "C" {
     370             : 
     371             : // This is a no-op on release, so we ifdef it out such that using it in release
     372             : // results in a linker error.
     373             : #ifdef DEBUG
     374           0 : void Gecko_IncrementStringAdoptCount(void* aData)
     375             : {
     376           0 :   MOZ_LOG_CTOR(aData, "StringAdopt", 1);
     377           0 : }
     378             : #elif defined(MOZ_DEBUG_RUST)
     379             : void Gecko_IncrementStringAdoptCount(void *aData)
     380             : {
     381             : }
     382             : #endif
     383             : 
     384           0 : void Gecko_FinalizeCString(nsACString* aThis)
     385             : {
     386           0 :   aThis->~nsACString();
     387           0 : }
     388             : 
     389           0 : void Gecko_AssignCString(nsACString* aThis, const nsACString* aOther)
     390             : {
     391           0 :   aThis->Assign(*aOther);
     392           0 : }
     393             : 
     394           0 : void Gecko_AppendCString(nsACString* aThis, const nsACString* aOther)
     395             : {
     396           0 :   aThis->Append(*aOther);
     397           0 : }
     398             : 
     399           0 : void Gecko_SetLengthCString(nsACString* aThis, uint32_t aLength)
     400             : {
     401           0 :   aThis->SetLength(aLength);
     402           0 : }
     403             : 
     404           0 : bool Gecko_FallibleAssignCString(nsACString* aThis, const nsACString* aOther)
     405             : {
     406           0 :   return aThis->Assign(*aOther, mozilla::fallible);
     407             : }
     408             : 
     409           0 : bool Gecko_FallibleAppendCString(nsACString* aThis, const nsACString* aOther)
     410             : {
     411           0 :   return aThis->Append(*aOther, mozilla::fallible);
     412             : }
     413             : 
     414           0 : bool Gecko_FallibleSetLengthCString(nsACString* aThis, uint32_t aLength)
     415             : {
     416           0 :   return aThis->SetLength(aLength, mozilla::fallible);
     417             : }
     418             : 
     419           0 : char* Gecko_BeginWritingCString(nsACString* aThis)
     420             : {
     421           0 :   return aThis->BeginWriting();
     422             : }
     423             : 
     424           0 : char* Gecko_FallibleBeginWritingCString(nsACString* aThis)
     425             : {
     426           0 :   return aThis->BeginWriting(mozilla::fallible);
     427             : }
     428             : 
     429           0 : void Gecko_FinalizeString(nsAString* aThis)
     430             : {
     431           0 :   aThis->~nsAString();
     432           0 : }
     433             : 
     434           0 : void Gecko_AssignString(nsAString* aThis, const nsAString* aOther)
     435             : {
     436           0 :   aThis->Assign(*aOther);
     437           0 : }
     438             : 
     439           0 : void Gecko_AppendString(nsAString* aThis, const nsAString* aOther)
     440             : {
     441           0 :   aThis->Append(*aOther);
     442           0 : }
     443             : 
     444           0 : void Gecko_SetLengthString(nsAString* aThis, uint32_t aLength)
     445             : {
     446           0 :   aThis->SetLength(aLength);
     447           0 : }
     448             : 
     449           0 : bool Gecko_FallibleAssignString(nsAString* aThis, const nsAString* aOther)
     450             : {
     451           0 :   return aThis->Assign(*aOther, mozilla::fallible);
     452             : }
     453             : 
     454           0 : bool Gecko_FallibleAppendString(nsAString* aThis, const nsAString* aOther)
     455             : {
     456           0 :   return aThis->Append(*aOther, mozilla::fallible);
     457             : }
     458             : 
     459          52 : bool Gecko_FallibleSetLengthString(nsAString* aThis, uint32_t aLength)
     460             : {
     461          52 :   return aThis->SetLength(aLength, mozilla::fallible);
     462             : }
     463             : 
     464          26 : char16_t* Gecko_BeginWritingString(nsAString* aThis)
     465             : {
     466          26 :   return aThis->BeginWriting();
     467             : }
     468             : 
     469           0 : char16_t* Gecko_FallibleBeginWritingString(nsAString* aThis)
     470             : {
     471           0 :   return aThis->BeginWriting(mozilla::fallible);
     472             : }
     473             : 
     474             : } // extern "C"

Generated by: LCOV version 1.13