LCOV - code coverage report
Current view: directory - xpcom/base - nsCycleCollector.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1116 739 66.2 %
Date: 2012-06-02 Functions: 202 141 69.8 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* vim: set cindent tabstop=4 expandtab shiftwidth=4: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * The Mozilla Foundation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2006
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : //
      41                 : // This file implements a garbage-cycle collector based on the paper
      42                 : // 
      43                 : //   Concurrent Cycle Collection in Reference Counted Systems
      44                 : //   Bacon & Rajan (2001), ECOOP 2001 / Springer LNCS vol 2072
      45                 : //
      46                 : // We are not using the concurrent or acyclic cases of that paper; so
      47                 : // the green, red and orange colors are not used.
      48                 : //
      49                 : // The collector is based on tracking pointers of four colors:
      50                 : //
      51                 : // Black nodes are definitely live. If we ever determine a node is
      52                 : // black, it's ok to forget about, drop from our records.
      53                 : //
      54                 : // White nodes are definitely garbage cycles. Once we finish with our
      55                 : // scanning, we unlink all the white nodes and expect that by
      56                 : // unlinking them they will self-destruct (since a garbage cycle is
      57                 : // only keeping itself alive with internal links, by definition).
      58                 : //
      59                 : // Grey nodes are being scanned. Nodes that turn grey will turn
      60                 : // either black if we determine that they're live, or white if we
      61                 : // determine that they're a garbage cycle. After the main collection
      62                 : // algorithm there should be no grey nodes.
      63                 : //
      64                 : // Purple nodes are *candidates* for being scanned. They are nodes we
      65                 : // haven't begun scanning yet because they're not old enough, or we're
      66                 : // still partway through the algorithm.
      67                 : //
      68                 : // XPCOM objects participating in garbage-cycle collection are obliged
      69                 : // to inform us when they ought to turn purple; that is, when their
      70                 : // refcount transitions from N+1 -> N, for nonzero N. Furthermore we
      71                 : // require that *after* an XPCOM object has informed us of turning
      72                 : // purple, they will tell us when they either transition back to being
      73                 : // black (incremented refcount) or are ultimately deleted.
      74                 : 
      75                 : 
      76                 : // Safety:
      77                 : //
      78                 : // An XPCOM object is either scan-safe or scan-unsafe, purple-safe or
      79                 : // purple-unsafe.
      80                 : //
      81                 : // An object is scan-safe if:
      82                 : //
      83                 : //  - It can be QI'ed to |nsXPCOMCycleCollectionParticipant|, though this
      84                 : //    operation loses ISupports identity (like nsIClassInfo).
      85                 : //  - The operation |traverse| on the resulting
      86                 : //    nsXPCOMCycleCollectionParticipant does not cause *any* refcount
      87                 : //    adjustment to occur (no AddRef / Release calls).
      88                 : //
      89                 : // An object is purple-safe if it satisfies the following properties:
      90                 : //
      91                 : //  - The object is scan-safe.  
      92                 : //  - If the object calls |nsCycleCollector::suspect(this)|, 
      93                 : //    it will eventually call |nsCycleCollector::forget(this)|, 
      94                 : //    exactly once per call to |suspect|, before being destroyed.
      95                 : //
      96                 : // When we receive a pointer |ptr| via
      97                 : // |nsCycleCollector::suspect(ptr)|, we assume it is purple-safe. We
      98                 : // can check the scan-safety, but have no way to ensure the
      99                 : // purple-safety; objects must obey, or else the entire system falls
     100                 : // apart. Don't involve an object in this scheme if you can't
     101                 : // guarantee its purple-safety.
     102                 : //
     103                 : // When we have a scannable set of purple nodes ready, we begin
     104                 : // our walks. During the walks, the nodes we |traverse| should only
     105                 : // feed us more scan-safe nodes, and should not adjust the refcounts
     106                 : // of those nodes. 
     107                 : //
     108                 : // We do not |AddRef| or |Release| any objects during scanning. We
     109                 : // rely on purple-safety of the roots that call |suspect| and
     110                 : // |forget| to hold, such that we will forget about a purple pointer
     111                 : // before it is destroyed.  The pointers that are merely scan-safe,
     112                 : // we hold only for the duration of scanning, and there should be no
     113                 : // objects released from the scan-safe set during the scan (there
     114                 : // should be no threads involved).
     115                 : //
     116                 : // We *do* call |AddRef| and |Release| on every white object, on
     117                 : // either side of the calls to |Unlink|. This keeps the set of white
     118                 : // objects alive during the unlinking.
     119                 : // 
     120                 : 
     121                 : #if !defined(__MINGW32__)
     122                 : #ifdef WIN32
     123                 : #include <crtdbg.h>
     124                 : #include <errno.h>
     125                 : #endif
     126                 : #endif
     127                 : 
     128                 : #include "base/process_util.h"
     129                 : 
     130                 : /* This must occur *after* base/process_util.h to avoid typedefs conflicts. */
     131                 : #include "mozilla/Util.h"
     132                 : 
     133                 : #include "nsCycleCollectionParticipant.h"
     134                 : #include "nsCycleCollectorUtils.h"
     135                 : #include "nsIProgrammingLanguage.h"
     136                 : #include "nsBaseHashtable.h"
     137                 : #include "nsHashKeys.h"
     138                 : #include "nsDeque.h"
     139                 : #include "nsCycleCollector.h"
     140                 : #include "nsThreadUtils.h"
     141                 : #include "prenv.h"
     142                 : #include "prprf.h"
     143                 : #include "plstr.h"
     144                 : #include "nsPrintfCString.h"
     145                 : #include "nsTArray.h"
     146                 : #include "nsIObserverService.h"
     147                 : #include "nsIConsoleService.h"
     148                 : #include "nsServiceManagerUtils.h"
     149                 : #include "nsThreadUtils.h"
     150                 : #include "nsTArray.h"
     151                 : #include "mozilla/Services.h"
     152                 : #include "nsICycleCollectorListener.h"
     153                 : #include "nsIXPConnect.h"
     154                 : #include "nsIJSRuntimeService.h"
     155                 : #include "nsIMemoryReporter.h"
     156                 : #include "xpcpublic.h"
     157                 : #include "nsXPCOMPrivate.h"
     158                 : #include "sampler.h"
     159                 : #include <stdio.h>
     160                 : #include <string.h>
     161                 : #ifdef WIN32
     162                 : #include <io.h>
     163                 : #include <process.h>
     164                 : #endif
     165                 : 
     166                 : #ifdef XP_WIN
     167                 : #include <windows.h>
     168                 : #endif
     169                 : 
     170                 : #include "mozilla/Mutex.h"
     171                 : #include "mozilla/CondVar.h"
     172                 : #include "mozilla/Telemetry.h"
     173                 : 
     174                 : using namespace mozilla;
     175                 : 
     176                 : //#define COLLECT_TIME_DEBUG
     177                 : 
     178                 : #ifdef DEBUG_CC
     179                 : #define IF_DEBUG_CC_PARAM(_p) , _p
     180                 : #define IF_DEBUG_CC_ONLY_PARAM(_p) _p
     181                 : #else
     182                 : #define IF_DEBUG_CC_PARAM(_p)
     183                 : #define IF_DEBUG_CC_ONLY_PARAM(_p)
     184                 : #endif
     185                 : 
     186                 : #define DEFAULT_SHUTDOWN_COLLECTIONS 5
     187                 : #ifdef DEBUG_CC
     188                 : #define SHUTDOWN_COLLECTIONS(params) params.mShutdownCollections
     189                 : #else
     190                 : #define SHUTDOWN_COLLECTIONS(params) DEFAULT_SHUTDOWN_COLLECTIONS
     191                 : #endif
     192                 : 
     193                 : #if defined(XP_WIN)
     194                 : // Defined in nsThreadManager.cpp.
     195                 : extern DWORD gTLSThreadIDIndex;
     196                 : #elif defined(NS_TLS)
     197                 : // Defined in nsThreadManager.cpp.
     198                 : extern NS_TLS mozilla::threads::ID gTLSThreadID;
     199                 : #else
     200                 : PRThread* gCycleCollectorThread = nsnull;
     201                 : #endif
     202                 : 
     203                 : // If true, always log cycle collector graphs.
     204                 : const bool gAlwaysLogCCGraphs = false;
     205                 : 
     206                 : MOZ_NEVER_INLINE void
     207         4356099 : CC_AbortIfNull(void *ptr)
     208                 : {
     209         4356099 :     if (!ptr)
     210               0 :         MOZ_Assert("ptr was null", __FILE__, __LINE__);
     211         4356099 : }
     212                 : 
     213                 : // Various parameters of this collector can be tuned using environment
     214                 : // variables.
     215                 : 
     216                 : struct nsCycleCollectorParams
     217                 : {
     218                 :     bool mDoNothing;
     219                 :     bool mLogGraphs;
     220                 : #ifdef DEBUG_CC
     221                 :     bool mReportStats;
     222                 :     bool mHookMalloc;
     223                 :     bool mFaultIsFatal;
     224                 :     bool mLogPointers;
     225                 :     PRUint32 mShutdownCollections;
     226                 : #endif
     227                 :     
     228            1419 :     nsCycleCollectorParams() :
     229                 : #ifdef DEBUG_CC
     230                 :         mDoNothing     (PR_GetEnv("XPCOM_CC_DO_NOTHING") != NULL),
     231                 :         mLogGraphs     (gAlwaysLogCCGraphs ||
     232                 :                         PR_GetEnv("XPCOM_CC_DRAW_GRAPHS") != NULL),
     233                 :         mReportStats   (PR_GetEnv("XPCOM_CC_REPORT_STATS") != NULL),
     234                 :         mHookMalloc    (PR_GetEnv("XPCOM_CC_HOOK_MALLOC") != NULL),
     235                 :         mFaultIsFatal  (PR_GetEnv("XPCOM_CC_FAULT_IS_FATAL") != NULL),
     236                 :         mLogPointers   (PR_GetEnv("XPCOM_CC_LOG_POINTERS") != NULL),
     237                 : 
     238                 :         mShutdownCollections(DEFAULT_SHUTDOWN_COLLECTIONS)
     239                 : #else
     240                 :         mDoNothing     (false),
     241            1419 :         mLogGraphs     (gAlwaysLogCCGraphs)
     242                 : #endif
     243                 :     {
     244                 : #ifdef DEBUG_CC
     245                 :         char *s = PR_GetEnv("XPCOM_CC_SHUTDOWN_COLLECTIONS");
     246                 :         if (s)
     247                 :             PR_sscanf(s, "%d", &mShutdownCollections);
     248                 : #endif
     249            1419 :     }
     250                 : };
     251                 : 
     252                 : #ifdef DEBUG_CC
     253                 : // Various operations involving the collector are recorded in a
     254                 : // statistics table. These are for diagnostics.
     255                 : 
     256                 : struct nsCycleCollectorStats
     257                 : {
     258                 :     PRUint32 mFailedQI;
     259                 :     PRUint32 mSuccessfulQI;
     260                 : 
     261                 :     PRUint32 mVisitedNode;
     262                 :     PRUint32 mWalkedGraph;
     263                 :     PRUint32 mCollectedBytes;
     264                 :     PRUint32 mFreeCalls;
     265                 :     PRUint32 mFreedBytes;
     266                 : 
     267                 :     PRUint32 mSetColorGrey;
     268                 :     PRUint32 mSetColorBlack;
     269                 :     PRUint32 mSetColorWhite;
     270                 : 
     271                 :     PRUint32 mFailedUnlink;
     272                 :     PRUint32 mCollectedNode;
     273                 : 
     274                 :     PRUint32 mSuspectNode;
     275                 :     PRUint32 mForgetNode;
     276                 :     PRUint32 mFreedWhilePurple;
     277                 :   
     278                 :     PRUint32 mCollection;
     279                 : 
     280                 :     nsCycleCollectorStats()
     281                 :     {
     282                 :         memset(this, 0, sizeof(nsCycleCollectorStats));
     283                 :     }
     284                 :   
     285                 :     void Dump()
     286                 :     {
     287                 :         fprintf(stderr, "\f\n");
     288                 : #define DUMP(entry) fprintf(stderr, "%30.30s: %-20.20d\n", #entry, entry)
     289                 :         DUMP(mFailedQI);
     290                 :         DUMP(mSuccessfulQI);
     291                 :     
     292                 :         DUMP(mVisitedNode);
     293                 :         DUMP(mWalkedGraph);
     294                 :         DUMP(mCollectedBytes);
     295                 :         DUMP(mFreeCalls);
     296                 :         DUMP(mFreedBytes);
     297                 :     
     298                 :         DUMP(mSetColorGrey);
     299                 :         DUMP(mSetColorBlack);
     300                 :         DUMP(mSetColorWhite);
     301                 :     
     302                 :         DUMP(mFailedUnlink);
     303                 :         DUMP(mCollectedNode);
     304                 :     
     305                 :         DUMP(mSuspectNode);
     306                 :         DUMP(mForgetNode);
     307                 :         DUMP(mFreedWhilePurple);
     308                 :     
     309                 :         DUMP(mCollection);
     310                 : #undef DUMP
     311                 :     }
     312                 : };
     313                 : #endif
     314                 : 
     315                 : #ifdef DEBUG_CC
     316                 : static bool nsCycleCollector_shouldSuppress(nsISupports *s);
     317                 : static void InitMemHook(void);
     318                 : #endif
     319                 : 
     320                 : #ifdef COLLECT_TIME_DEBUG
     321                 : class TimeLog
     322                 : {
     323                 : public:
     324                 :     TimeLog() : mLastCheckpoint(TimeStamp::Now()) {}
     325                 : 
     326                 :     void
     327                 :     Checkpoint(const char* aEvent)
     328                 :     {
     329                 :         TimeStamp now = TimeStamp::Now();
     330                 :         PRUint32 dur = (PRUint32) ((now - mLastCheckpoint).ToMilliseconds());
     331                 :         if (dur > 0) {
     332                 :             printf("cc: %s took %dms\n", aEvent, dur);
     333                 :         }
     334                 :         mLastCheckpoint = now;
     335                 :     }
     336                 : 
     337                 : private:
     338                 :     TimeStamp mLastCheckpoint;
     339                 : };
     340                 : #else
     341                 : class TimeLog
     342                 : {
     343                 : public:
     344            9382 :     TimeLog() {}
     345           26647 :     void Checkpoint(const char* aEvent) {}
     346                 : };
     347                 : #endif
     348                 : 
     349                 : 
     350                 : ////////////////////////////////////////////////////////////////////////
     351                 : // Base types
     352                 : ////////////////////////////////////////////////////////////////////////
     353                 : 
     354                 : struct PtrInfo;
     355                 : 
     356                 : class EdgePool
     357                 : {
     358                 : public:
     359                 :     // EdgePool allocates arrays of void*, primarily to hold PtrInfo*.
     360                 :     // However, at the end of a block, the last two pointers are a null
     361                 :     // and then a void** pointing to the next block.  This allows
     362                 :     // EdgePool::Iterators to be a single word but still capable of crossing
     363                 :     // block boundaries.
     364                 : 
     365            1419 :     EdgePool()
     366                 :     {
     367            1419 :         mSentinelAndBlocks[0].block = nsnull;
     368            1419 :         mSentinelAndBlocks[1].block = nsnull;
     369            1419 :         mNumBlocks = 0;
     370            1419 :     }
     371                 : 
     372            1419 :     ~EdgePool()
     373                 :     {
     374            1419 :         NS_ASSERTION(!mSentinelAndBlocks[0].block &&
     375                 :                      !mSentinelAndBlocks[1].block,
     376                 :                      "Didn't call Clear()?");
     377            1419 :     }
     378                 : 
     379            1925 :     void Clear()
     380                 :     {
     381            1925 :         Block *b = Blocks();
     382            5784 :         while (b) {
     383            1934 :             Block *next = b->Next();
     384                 :             delete b;
     385            1934 :             NS_ASSERTION(mNumBlocks > 0,
     386                 :                          "Expected EdgePool mNumBlocks to be positive.");
     387            1934 :             mNumBlocks--;
     388            1934 :             b = next;
     389                 :         }
     390                 : 
     391            1925 :         mSentinelAndBlocks[0].block = nsnull;
     392            1925 :         mSentinelAndBlocks[1].block = nsnull;
     393            1925 :     }
     394                 : 
     395                 : private:
     396                 :     struct Block;
     397                 :     union PtrInfoOrBlock {
     398                 :         // Use a union to avoid reinterpret_cast and the ensuing
     399                 :         // potential aliasing bugs.
     400                 :         PtrInfo *ptrInfo;
     401                 :         Block *block;
     402                 :     };
     403                 :     struct Block {
     404                 :         enum { BlockSize = 16 * 1024 };
     405                 : 
     406                 :         PtrInfoOrBlock mPointers[BlockSize];
     407            1934 :         Block() {
     408            1934 :             mPointers[BlockSize - 2].block = nsnull; // sentinel
     409            1934 :             mPointers[BlockSize - 1].block = nsnull; // next block pointer
     410            1934 :         }
     411            3868 :         Block*& Next()
     412            3868 :             { return mPointers[BlockSize - 1].block; }
     413            1934 :         PtrInfoOrBlock* Start()
     414            1934 :             { return &mPointers[0]; }
     415            1934 :         PtrInfoOrBlock* End()
     416            1934 :             { return &mPointers[BlockSize - 2]; }
     417                 :     };
     418                 : 
     419                 :     // Store the null sentinel so that we can have valid iterators
     420                 :     // before adding any edges and without adding any blocks.
     421                 :     PtrInfoOrBlock mSentinelAndBlocks[2];
     422                 :     PRUint32 mNumBlocks;
     423                 : 
     424            3850 :     Block*& Blocks() { return mSentinelAndBlocks[1].block; }
     425                 : 
     426                 : public:
     427                 :     class Iterator
     428                 :     {
     429                 :     public:
     430          601885 :         Iterator() : mPointer(nsnull) {}
     431          603812 :         Iterator(PtrInfoOrBlock *aPointer) : mPointer(aPointer) {}
     432         1230322 :         Iterator(const Iterator& aOther) : mPointer(aOther.mPointer) {}
     433                 : 
     434         1739228 :         Iterator& operator++()
     435                 :         {
     436         1739228 :             if (mPointer->ptrInfo == nsnull) {
     437                 :                 // Null pointer is a sentinel for link to the next block.
     438            3844 :                 mPointer = (mPointer + 1)->block->mPointers;
     439                 :             }
     440         1739228 :             ++mPointer;
     441         1739228 :             return *this;
     442                 :         }
     443                 : 
     444         3478456 :         PtrInfo* operator*() const
     445                 :         {
     446         3478456 :             if (mPointer->ptrInfo == nsnull) {
     447                 :                 // Null pointer is a sentinel for link to the next block.
     448            7688 :                 return (mPointer + 1)->block->mPointers->ptrInfo;
     449                 :             }
     450         3470768 :             return mPointer->ptrInfo;
     451                 :         }
     452                 :         bool operator==(const Iterator& aOther) const
     453                 :             { return mPointer == aOther.mPointer; }
     454         2354389 :         bool operator!=(const Iterator& aOther) const
     455         2354389 :             { return mPointer != aOther.mPointer; }
     456                 : 
     457                 :     private:
     458                 :         PtrInfoOrBlock *mPointer;
     459                 :     };
     460                 : 
     461                 :     class Builder;
     462                 :     friend class Builder;
     463                 :     class Builder {
     464                 :     public:
     465            1925 :         Builder(EdgePool &aPool)
     466                 :             : mCurrent(&aPool.mSentinelAndBlocks[0]),
     467                 :               mBlockEnd(&aPool.mSentinelAndBlocks[0]),
     468            1925 :               mNextBlockPtr(&aPool.Blocks()),
     469            3850 :               mNumBlocks(aPool.mNumBlocks)
     470                 :         {
     471            1925 :         }
     472                 : 
     473          603812 :         Iterator Mark() { return Iterator(mCurrent); }
     474                 : 
     475         1725048 :         void Add(PtrInfo* aEdge) {
     476         1725048 :             if (mCurrent == mBlockEnd) {
     477            1934 :                 Block *b = new Block();
     478            1934 :                 if (!b) {
     479                 :                     // This means we just won't collect (some) cycles.
     480               0 :                     NS_NOTREACHED("out of memory, ignoring edges");
     481               0 :                     return;
     482                 :                 }
     483            1934 :                 *mNextBlockPtr = b;
     484            1934 :                 mCurrent = b->Start();
     485            1934 :                 mBlockEnd = b->End();
     486            1934 :                 mNextBlockPtr = &b->Next();
     487            1934 :                 mNumBlocks++;
     488                 :             }
     489         1725048 :             (mCurrent++)->ptrInfo = aEdge;
     490                 :         }
     491                 :     private:
     492                 :         // mBlockEnd points to space for null sentinel
     493                 :         PtrInfoOrBlock *mCurrent, *mBlockEnd;
     494                 :         Block **mNextBlockPtr;
     495                 :         PRUint32 &mNumBlocks;
     496                 :     };
     497                 : 
     498               0 :     size_t BlocksSize() const {
     499               0 :         return sizeof(Block) * mNumBlocks;
     500                 :     }
     501                 : 
     502                 : };
     503                 : 
     504                 : #ifdef DEBUG_CC
     505                 : 
     506                 : struct ReversedEdge {
     507                 :     PtrInfo *mTarget;
     508                 :     nsCString *mEdgeName;
     509                 :     ReversedEdge *mNext;
     510                 : };
     511                 : 
     512                 : #endif
     513                 : 
     514                 : 
     515                 : enum NodeColor { black, white, grey };
     516                 : 
     517                 : // This structure should be kept as small as possible; we may expect
     518                 : // hundreds of thousands of them to be allocated and touched
     519                 : // repeatedly during each cycle collection.
     520                 : 
     521                 : struct PtrInfo
     522                 : {
     523                 :     void *mPointer;
     524                 :     nsCycleCollectionParticipant *mParticipant;
     525                 :     PRUint32 mColor : 2;
     526                 :     PRUint32 mInternalRefs : 30;
     527                 :     PRUint32 mRefCount;
     528                 : private:
     529                 :     EdgePool::Iterator mFirstChild;
     530                 : 
     531                 : public:
     532                 : #ifdef DEBUG_CC
     533                 :     size_t mBytes;
     534                 :     char *mName;
     535                 :     PRUint32 mLangID;
     536                 : 
     537                 :     // For finding roots in ExplainLiveExpectedGarbage (when there are
     538                 :     // missing calls to suspect or failures to unlink).
     539                 :     PRUint32 mSCCIndex; // strongly connected component
     540                 : 
     541                 :     // For finding roots in ExplainLiveExpectedGarbage (when nodes
     542                 :     // expected to be garbage are black).
     543                 :     ReversedEdge* mReversedEdges; // linked list
     544                 :     PtrInfo* mShortestPathToExpectedGarbage;
     545                 :     nsCString* mShortestPathToExpectedGarbageEdgeName;
     546                 : 
     547                 :     nsTArray<nsCString> mEdgeNames;
     548                 : #endif
     549                 : 
     550          601885 :     PtrInfo(void *aPointer, nsCycleCollectionParticipant *aParticipant
     551                 :             IF_DEBUG_CC_PARAM(PRUint32 aLangID)
     552                 :             )
     553                 :         : mPointer(aPointer),
     554                 :           mParticipant(aParticipant),
     555                 :           mColor(grey),
     556                 :           mInternalRefs(0),
     557                 :           mRefCount(0),
     558          601885 :           mFirstChild()
     559                 : #ifdef DEBUG_CC
     560                 :         , mBytes(0),
     561                 :           mName(nsnull),
     562                 :           mLangID(aLangID),
     563                 :           mSCCIndex(0),
     564                 :           mReversedEdges(nsnull),
     565                 :           mShortestPathToExpectedGarbage(nsnull),
     566                 :           mShortestPathToExpectedGarbageEdgeName(nsnull)
     567                 : #endif
     568                 :     {
     569          601885 :     }
     570                 : 
     571                 : #ifdef DEBUG_CC
     572                 :     void Destroy() {
     573                 :         PL_strfree(mName);
     574                 :         mEdgeNames.~nsTArray<nsCString>();
     575                 :     }
     576                 : #endif
     577                 : 
     578                 :     // Allow NodePool::Block's constructor to compile.
     579                 :     PtrInfo() {
     580                 :         NS_NOTREACHED("should never be called");
     581                 :     }
     582                 : 
     583          615161 :     EdgePool::Iterator FirstChild()
     584                 :     {
     585          615161 :         return mFirstChild;
     586                 :     }
     587                 : 
     588                 :     // this PtrInfo must be part of a NodePool
     589          615161 :     EdgePool::Iterator LastChild()
     590                 :     {
     591          615161 :         return (this + 1)->mFirstChild;
     592                 :     }
     593                 : 
     594          601885 :     void SetFirstChild(EdgePool::Iterator aFirstChild)
     595                 :     {
     596          601885 :         mFirstChild = aFirstChild;
     597          601885 :     }
     598                 : 
     599                 :     // this PtrInfo must be part of a NodePool
     600            1927 :     void SetLastChild(EdgePool::Iterator aLastChild)
     601                 :     {
     602            1927 :         (this + 1)->mFirstChild = aLastChild;
     603            1927 :     }
     604                 : };
     605                 : 
     606                 : /**
     607                 :  * A structure designed to be used like a linked list of PtrInfo, except
     608                 :  * that allocates the PtrInfo 32K-at-a-time.
     609                 :  */
     610                 : class NodePool
     611                 : {
     612                 : private:
     613                 :     enum { BlockSize = 8 * 1024 }; // could be int template parameter
     614                 : 
     615                 :     struct Block {
     616                 :         // We create and destroy Block using NS_Alloc/NS_Free rather
     617                 :         // than new and delete to avoid calling its constructor and
     618                 :         // destructor.
     619                 :         Block() { NS_NOTREACHED("should never be called"); }
     620                 :         ~Block() { NS_NOTREACHED("should never be called"); }
     621                 : 
     622                 :         Block* mNext;
     623                 :         PtrInfo mEntries[BlockSize + 1]; // +1 to store last child of last node
     624                 :     };
     625                 : 
     626                 : public:
     627            1419 :     NodePool()
     628                 :         : mBlocks(nsnull),
     629                 :           mLast(nsnull),
     630            1419 :           mNumBlocks(0)
     631                 :     {
     632            1419 :     }
     633                 : 
     634            1419 :     ~NodePool()
     635                 :     {
     636            1419 :         NS_ASSERTION(!mBlocks, "Didn't call Clear()?");
     637            1419 :     }
     638                 : 
     639            1925 :     void Clear()
     640                 :     {
     641                 : #ifdef DEBUG_CC
     642                 :         {
     643                 :             Enumerator queue(*this);
     644                 :             while (!queue.IsDone()) {
     645                 :                 queue.GetNext()->Destroy();
     646                 :             }
     647                 :         }
     648                 : #endif
     649            1925 :         Block *b = mBlocks;
     650            5777 :         while (b) {
     651            1927 :             Block *n = b->mNext;
     652            1927 :             NS_Free(b);
     653            1927 :             NS_ASSERTION(mNumBlocks > 0,
     654                 :                          "Expected NodePool mNumBlocks to be positive.");
     655            1927 :             mNumBlocks--;
     656            1927 :             b = n;
     657                 :         }
     658                 : 
     659            1925 :         mBlocks = nsnull;
     660            1925 :         mLast = nsnull;
     661            1925 :     }
     662                 : 
     663                 :     class Builder;
     664                 :     friend class Builder;
     665                 :     class Builder {
     666                 :     public:
     667            1925 :         Builder(NodePool& aPool)
     668                 :             : mNextBlock(&aPool.mBlocks),
     669                 :               mNext(aPool.mLast),
     670                 :               mBlockEnd(nsnull),
     671            1925 :               mNumBlocks(aPool.mNumBlocks)
     672                 :         {
     673            1925 :             NS_ASSERTION(aPool.mBlocks == nsnull && aPool.mLast == nsnull,
     674                 :                          "pool not empty");
     675            1925 :         }
     676          601885 :         PtrInfo *Add(void *aPointer, nsCycleCollectionParticipant *aParticipant
     677                 :                      IF_DEBUG_CC_PARAM(PRUint32 aLangID)
     678                 :                     )
     679                 :         {
     680          601885 :             if (mNext == mBlockEnd) {
     681                 :                 Block *block;
     682            3854 :                 if (!(*mNextBlock = block =
     683            3854 :                         static_cast<Block*>(NS_Alloc(sizeof(Block)))))
     684               0 :                     return nsnull;
     685            1927 :                 mNext = block->mEntries;
     686            1927 :                 mBlockEnd = block->mEntries + BlockSize;
     687            1927 :                 block->mNext = nsnull;
     688            1927 :                 mNextBlock = &block->mNext;
     689            1927 :                 mNumBlocks++;
     690                 :             }
     691                 :             return new (mNext++) PtrInfo(aPointer, aParticipant
     692                 :                                          IF_DEBUG_CC_PARAM(aLangID)
     693          601885 :                                         );
     694                 :         }
     695                 :     private:
     696                 :         Block **mNextBlock;
     697                 :         PtrInfo *&mNext;
     698                 :         PtrInfo *mBlockEnd;
     699                 :         PRUint32 &mNumBlocks;
     700                 :     };
     701                 : 
     702                 :     class Enumerator;
     703                 :     friend class Enumerator;
     704                 :     class Enumerator {
     705                 :     public:
     706            5745 :         Enumerator(NodePool& aPool)
     707                 :             : mFirstBlock(aPool.mBlocks),
     708                 :               mCurBlock(nsnull),
     709                 :               mNext(nsnull),
     710                 :               mBlockEnd(nsnull),
     711            5745 :               mLast(aPool.mLast)
     712                 :         {
     713            5745 :         }
     714                 : 
     715         2536471 :         bool IsDone() const
     716                 :         {
     717         2536471 :             return mNext == mLast;
     718                 :         }
     719                 : 
     720          601885 :         bool AtBlockEnd() const
     721                 :         {
     722          601885 :             return mNext == mBlockEnd;
     723                 :         }
     724                 : 
     725         1328866 :         PtrInfo* GetNext()
     726                 :         {
     727         1328866 :             NS_ASSERTION(!IsDone(), "calling GetNext when done");
     728         1328866 :             if (mNext == mBlockEnd) {
     729            5766 :                 Block *nextBlock = mCurBlock ? mCurBlock->mNext : mFirstBlock;
     730            5766 :                 mNext = nextBlock->mEntries;
     731            5766 :                 mBlockEnd = mNext + BlockSize;
     732            5766 :                 mCurBlock = nextBlock;
     733                 :             }
     734         1328866 :             return mNext++;
     735                 :         }
     736                 :     private:
     737                 :         Block *mFirstBlock, *mCurBlock;
     738                 :         // mNext is the next value we want to return, unless mNext == mBlockEnd
     739                 :         // NB: mLast is a reference to allow enumerating while building!
     740                 :         PtrInfo *mNext, *mBlockEnd, *&mLast;
     741                 :     };
     742                 : 
     743               0 :     size_t BlocksSize() const {
     744               0 :         return sizeof(Block) * mNumBlocks;
     745                 :     }
     746                 : 
     747                 : private:
     748                 :     Block *mBlocks;
     749                 :     PtrInfo *mLast;
     750                 :     PRUint32 mNumBlocks;
     751                 : };
     752                 : 
     753                 : 
     754                 : struct WeakMapping
     755               0 : {
     756                 :     // map and key will be null if the corresponding objects are GC marked
     757                 :     PtrInfo *mMap;
     758                 :     PtrInfo *mKey;
     759                 :     PtrInfo *mVal;
     760                 : };
     761                 : 
     762                 : class GCGraphBuilder;
     763                 : 
     764                 : struct GCGraph
     765                 : {
     766                 :     NodePool mNodes;
     767                 :     EdgePool mEdges;
     768                 :     nsTArray<WeakMapping> mWeakMaps;
     769                 :     PRUint32 mRootCount;
     770                 : #ifdef DEBUG_CC
     771                 :     ReversedEdge *mReversedEdges;
     772                 : #endif
     773                 : 
     774            1419 :     GCGraph() : mRootCount(0) {
     775            1419 :     }
     776            1419 :     ~GCGraph() { 
     777            1419 :     }
     778                 : 
     779               0 :     size_t BlocksSize() const {
     780               0 :         return mNodes.BlocksSize() + mEdges.BlocksSize();
     781                 :     }
     782                 : 
     783                 : };
     784                 : 
     785                 : // XXX Would be nice to have an nsHashSet<KeyType> API that has
     786                 : // Add/Remove/Has rather than PutEntry/RemoveEntry/GetEntry.
     787                 : typedef nsTHashtable<nsVoidPtrHashKey> PointerSet;
     788                 : 
     789                 : static inline void
     790                 : ToParticipant(nsISupports *s, nsXPCOMCycleCollectionParticipant **cp);
     791                 : 
     792                 : struct nsPurpleBuffer
     793                 : {
     794                 : private:
     795                 :     struct Block {
     796                 :         Block *mNext;
     797                 :         nsPurpleBufferEntry mEntries[255];
     798                 : 
     799            2187 :         Block() : mNext(nsnull) {}
     800                 :     };
     801                 : public:
     802                 :     // This class wraps a linked list of the elements in the purple
     803                 :     // buffer.
     804                 : 
     805                 :     nsCycleCollectorParams &mParams;
     806                 :     PRUint32 mNumBlocksAlloced;
     807                 :     PRUint32 mCount;
     808                 :     Block mFirstBlock;
     809                 :     nsPurpleBufferEntry *mFreeList;
     810                 : 
     811                 :     // For objects compiled against Gecko 1.9 and 1.9.1.
     812                 :     PointerSet mCompatObjects;
     813                 : #ifdef DEBUG_CC
     814                 :     PointerSet mNormalObjects; // duplicates our blocks
     815                 :     nsCycleCollectorStats &mStats;
     816                 : #endif
     817                 :     
     818                 : #ifdef DEBUG_CC
     819                 :     nsPurpleBuffer(nsCycleCollectorParams &params,
     820                 :                    nsCycleCollectorStats &stats) 
     821                 :         : mParams(params),
     822                 :           mStats(stats)
     823                 :     {
     824                 :         InitBlocks();
     825                 :         mNormalObjects.Init();
     826                 :         mCompatObjects.Init();
     827                 :     }
     828                 : #else
     829            1419 :     nsPurpleBuffer(nsCycleCollectorParams &params) 
     830            1419 :         : mParams(params)
     831                 :     {
     832            1419 :         InitBlocks();
     833            1419 :         mCompatObjects.Init();
     834            1419 :     }
     835                 : #endif
     836                 : 
     837            1419 :     ~nsPurpleBuffer()
     838            1419 :     {
     839            1419 :         FreeBlocks();
     840            1419 :     }
     841                 : 
     842            3344 :     void InitBlocks()
     843                 :     {
     844            3344 :         mNumBlocksAlloced = 0;
     845            3344 :         mCount = 0;
     846            3344 :         mFreeList = nsnull;
     847            3344 :         StartBlock(&mFirstBlock);
     848            3344 :     }
     849                 : 
     850            4112 :     void StartBlock(Block *aBlock)
     851                 :     {
     852            4112 :         NS_ABORT_IF_FALSE(!mFreeList, "should not have free list");
     853                 : 
     854                 :         // Put all the entries in the block on the free list.
     855            4112 :         nsPurpleBufferEntry *entries = aBlock->mEntries;
     856            4112 :         mFreeList = entries;
     857         1048560 :         for (PRUint32 i = 1; i < ArrayLength(aBlock->mEntries); ++i) {
     858         1044448 :             entries[i - 1].mNextInFreeList =
     859         1044448 :                 (nsPurpleBufferEntry*)(PRUword(entries + i) | 1);
     860                 :         }
     861            4112 :         entries[ArrayLength(aBlock->mEntries) - 1].mNextInFreeList =
     862            4112 :             (nsPurpleBufferEntry*)1;
     863            4112 :     }
     864                 : 
     865            3344 :     void FreeBlocks()
     866                 :     {
     867            3344 :         if (mCount > 0)
     868               0 :             UnmarkRemainingPurple(&mFirstBlock);
     869            3344 :         Block *b = mFirstBlock.mNext; 
     870            7456 :         while (b) {
     871             768 :             if (mCount > 0)
     872               0 :                 UnmarkRemainingPurple(b);
     873             768 :             Block *next = b->mNext;
     874                 :             delete b;
     875             768 :             b = next;
     876             768 :             NS_ASSERTION(mNumBlocksAlloced > 0,
     877                 :                          "Expected positive mNumBlocksAlloced.");
     878             768 :             mNumBlocksAlloced--;
     879                 :         }
     880            3344 :         mFirstBlock.mNext = nsnull;
     881            3344 :     }
     882                 : 
     883               0 :     void UnmarkRemainingPurple(Block *b)
     884                 :     {
     885               0 :         for (nsPurpleBufferEntry *e = b->mEntries,
     886               0 :                               *eEnd = ArrayEnd(b->mEntries);
     887                 :              e != eEnd; ++e) {
     888               0 :             if (!(PRUword(e->mObject) & PRUword(1))) {
     889                 :                 // This is a real entry (rather than something on the
     890                 :                 // free list).
     891               0 :                 if (e->mObject) {
     892                 :                     nsXPCOMCycleCollectionParticipant *cp;
     893               0 :                     ToParticipant(e->mObject, &cp);
     894                 : 
     895               0 :                     cp->UnmarkIfPurple(e->mObject);
     896                 :                 }
     897                 : 
     898               0 :                 if (--mCount == 0)
     899               0 :                     break;
     900                 :             }
     901                 :         }
     902               0 :     }
     903                 : 
     904                 :     void SelectPointers(GCGraphBuilder &builder);
     905                 : 
     906                 :     // RemoveSkippable removes entries from the purple buffer if
     907                 :     // nsPurpleBufferEntry::mObject is null or if the object's
     908                 :     // nsXPCOMCycleCollectionParticipant::CanSkip() returns true.
     909                 :     // If removeChildlessNodes is true, then any nodes in the purple buffer
     910                 :     // that will have no children in the cycle collector graph will also be
     911                 :     // removed. CanSkip() may be run on these children.
     912                 :     void RemoveSkippable(bool removeChildlessNodes);
     913                 : 
     914                 : #ifdef DEBUG_CC
     915                 :     void NoteAll(GCGraphBuilder &builder);
     916                 : 
     917                 :     bool Exists(void *p) const
     918                 :     {
     919                 :         return mNormalObjects.GetEntry(p) || mCompatObjects.GetEntry(p);
     920                 :     }
     921                 : #endif
     922                 : 
     923         1489498 :     nsPurpleBufferEntry* NewEntry()
     924                 :     {
     925         1489498 :         if (!mFreeList) {
     926             768 :             Block *b = new Block;
     927             768 :             if (!b) {
     928               0 :                 return nsnull;
     929                 :             }
     930             768 :             mNumBlocksAlloced++;
     931             768 :             StartBlock(b);
     932                 : 
     933                 :             // Add the new block as the second block in the list.
     934             768 :             b->mNext = mFirstBlock.mNext;
     935             768 :             mFirstBlock.mNext = b;
     936                 :         }
     937                 : 
     938         1489498 :         nsPurpleBufferEntry *e = mFreeList;
     939                 :         mFreeList = (nsPurpleBufferEntry*)
     940         1489498 :             (PRUword(mFreeList->mNextInFreeList) & ~PRUword(1));
     941         1489498 :         return e;
     942                 :     }
     943                 : 
     944         1489498 :     nsPurpleBufferEntry* Put(nsISupports *p)
     945                 :     {
     946         1489498 :         nsPurpleBufferEntry *e = NewEntry();
     947         1489498 :         if (!e) {
     948               0 :             return nsnull;
     949                 :         }
     950                 : 
     951         1489498 :         ++mCount;
     952                 : 
     953         1489498 :         e->mObject = p;
     954                 : 
     955                 : #ifdef DEBUG_CC
     956                 :         mNormalObjects.PutEntry(p);
     957                 : #endif
     958                 : 
     959                 :         // Caller is responsible for filling in result's mRefCnt.
     960         1489498 :         return e;
     961                 :     }
     962                 : 
     963         1489498 :     void Remove(nsPurpleBufferEntry *e)
     964                 :     {
     965         1489498 :         NS_ASSERTION(mCount != 0, "must have entries");
     966                 : 
     967                 : #ifdef DEBUG_CC
     968                 :         mNormalObjects.RemoveEntry(e->mObject);
     969                 : #endif
     970                 : 
     971                 :         e->mNextInFreeList =
     972         1489498 :             (nsPurpleBufferEntry*)(PRUword(mFreeList) | PRUword(1));
     973         1489498 :         mFreeList = e;
     974                 : 
     975         1489498 :         --mCount;
     976         1489498 :     }
     977                 : 
     978               0 :     bool PutCompatObject(nsISupports *p)
     979                 :     {
     980               0 :         ++mCount;
     981               0 :         return !!mCompatObjects.PutEntry(p);
     982                 :     }
     983                 : 
     984               0 :     void RemoveCompatObject(nsISupports *p)
     985                 :     {
     986               0 :         --mCount;
     987               0 :         mCompatObjects.RemoveEntry(p);
     988               0 :     }
     989                 : 
     990           23251 :     PRUint32 Count() const
     991                 :     {
     992           23251 :         return mCount;
     993                 :     }
     994                 : 
     995               0 :     size_t BlocksSize() const
     996                 :     {
     997               0 :         return sizeof(Block) * mNumBlocksAlloced;
     998                 :     }
     999                 : 
    1000                 : };
    1001                 : 
    1002                 : struct CallbackClosure
    1003                 : {
    1004               0 :     CallbackClosure(nsPurpleBuffer *aPurpleBuffer, GCGraphBuilder &aBuilder)
    1005                 :         : mPurpleBuffer(aPurpleBuffer),
    1006               0 :           mBuilder(aBuilder)
    1007                 :     {
    1008               0 :     }
    1009                 :     nsPurpleBuffer *mPurpleBuffer;
    1010                 :     GCGraphBuilder &mBuilder;
    1011                 : };
    1012                 : 
    1013                 : static bool
    1014                 : AddPurpleRoot(GCGraphBuilder &builder, nsISupports *root);
    1015                 : 
    1016                 : static PLDHashOperator
    1017               0 : selectionCallback(nsVoidPtrHashKey* key, void* userArg)
    1018                 : {
    1019               0 :     CallbackClosure *closure = static_cast<CallbackClosure*>(userArg);
    1020               0 :     if (AddPurpleRoot(closure->mBuilder,
    1021                 :                       static_cast<nsISupports *>(
    1022               0 :                         const_cast<void*>(key->GetKey()))))
    1023               0 :         return PL_DHASH_REMOVE;
    1024                 : 
    1025               0 :     return PL_DHASH_NEXT;
    1026                 : }
    1027                 : 
    1028                 : void
    1029            1925 : nsPurpleBuffer::SelectPointers(GCGraphBuilder &aBuilder)
    1030                 : {
    1031                 : #ifdef DEBUG_CC
    1032                 :     // Can't use mCount here, since it may include null entries.
    1033                 :     PRUint32 realCount = 0;
    1034                 :     for (Block *b = &mFirstBlock; b; b = b->mNext) {
    1035                 :         for (nsPurpleBufferEntry *e = b->mEntries,
    1036                 :                               *eEnd = ArrayEnd(b->mEntries);
    1037                 :             e != eEnd; ++e) {
    1038                 :             if (!(PRUword(e->mObject) & PRUword(1))) {
    1039                 :                 if (e->mObject) {
    1040                 :                     ++realCount;
    1041                 :                 }
    1042                 :             }
    1043                 :         }
    1044                 :     }
    1045                 : 
    1046                 :     NS_ABORT_IF_FALSE(mCompatObjects.Count() + mNormalObjects.Count() ==
    1047                 :                           realCount,
    1048                 :                       "count out of sync");
    1049                 : #endif
    1050                 : 
    1051            1925 :     if (mCompatObjects.Count()) {
    1052               0 :         mCount -= mCompatObjects.Count();
    1053               0 :         CallbackClosure closure(this, aBuilder);
    1054               0 :         mCompatObjects.EnumerateEntries(selectionCallback, &closure);
    1055               0 :         mCount += mCompatObjects.Count(); // in case of allocation failure
    1056                 :     }
    1057                 : 
    1058                 :     // Walk through all the blocks.
    1059            4618 :     for (Block *b = &mFirstBlock; b; b = b->mNext) {
    1060          692101 :         for (nsPurpleBufferEntry *e = b->mEntries,
    1061            2693 :                               *eEnd = ArrayEnd(b->mEntries);
    1062                 :             e != eEnd; ++e) {
    1063          686715 :             if (!(PRUword(e->mObject) & PRUword(1))) {
    1064                 :                 // This is a real entry (rather than something on the
    1065                 :                 // free list).
    1066          115052 :                 if (!e->mObject || AddPurpleRoot(aBuilder, e->mObject)) {
    1067          115052 :                     Remove(e);
    1068                 :                 }
    1069                 :             }
    1070                 :         }
    1071                 :     }
    1072                 : 
    1073            1925 :     NS_WARN_IF_FALSE(mCount == 0, "AddPurpleRoot failed");
    1074            1925 :     if (mCount == 0) {
    1075            1925 :         FreeBlocks();
    1076            1925 :         InitBlocks();
    1077                 :     }
    1078            1925 : }
    1079                 : 
    1080                 : 
    1081                 : 
    1082                 : ////////////////////////////////////////////////////////////////////////
    1083                 : // Implement the LanguageRuntime interface for C++/XPCOM 
    1084                 : ////////////////////////////////////////////////////////////////////////
    1085                 : 
    1086                 : 
    1087                 : struct nsCycleCollectionXPCOMRuntime : 
    1088                 :     public nsCycleCollectionLanguageRuntime 
    1089            1419 : {
    1090            1925 :     nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb,
    1091                 :                                   bool explainLiveExpectedGarbage)
    1092                 :     {
    1093            1925 :         return NS_OK;
    1094                 :     }
    1095                 : 
    1096            1910 :     nsresult FinishTraverse() 
    1097                 :     {
    1098            1910 :         return NS_OK;
    1099                 :     }
    1100                 : 
    1101            1925 :     nsresult FinishCycleCollection() 
    1102                 :     {
    1103            1925 :         return NS_OK;
    1104                 :     }
    1105                 : 
    1106                 :     inline nsCycleCollectionParticipant *ToParticipant(void *p);
    1107                 : 
    1108                 : #ifdef DEBUG_CC
    1109                 :     virtual void PrintAllReferencesTo(void *p) {}
    1110                 : #endif
    1111                 : };
    1112                 : 
    1113                 : struct nsCycleCollector
    1114                 : {
    1115                 :     bool mCollectionInProgress;
    1116                 :     bool mScanInProgress;
    1117                 :     bool mFollowupCollection;
    1118                 :     nsCycleCollectorResults *mResults;
    1119                 :     TimeStamp mCollectionStart;
    1120                 : 
    1121                 :     nsCycleCollectionLanguageRuntime *mRuntimes[nsIProgrammingLanguage::MAX+1];
    1122                 :     nsCycleCollectionXPCOMRuntime mXPCOMRuntime;
    1123                 : 
    1124                 :     GCGraph mGraph;
    1125                 : 
    1126                 :     nsCycleCollectorParams mParams;
    1127                 : 
    1128                 :     nsTArray<PtrInfo*> *mWhiteNodes;
    1129                 :     PRUint32 mWhiteNodeCount;
    1130                 : 
    1131                 :     // mVisitedRefCounted and mVisitedGCed are only used for telemetry
    1132                 :     PRUint32 mVisitedRefCounted;
    1133                 :     PRUint32 mVisitedGCed;
    1134                 : 
    1135                 :     nsPurpleBuffer mPurpleBuf;
    1136                 : 
    1137                 :     CC_BeforeUnlinkCallback mBeforeUnlinkCB;
    1138                 :     CC_ForgetSkippableCallback mForgetSkippableCB;
    1139                 : 
    1140                 :     void RegisterRuntime(PRUint32 langID, 
    1141                 :                          nsCycleCollectionLanguageRuntime *rt);
    1142                 :     nsCycleCollectionLanguageRuntime * GetRuntime(PRUint32 langID);
    1143                 :     void ForgetRuntime(PRUint32 langID);
    1144                 : 
    1145                 :     void SelectPurple(GCGraphBuilder &builder);
    1146                 :     void MarkRoots(GCGraphBuilder &builder);
    1147                 :     void ScanRoots();
    1148                 :     void ScanWeakMaps();
    1149                 : 
    1150                 :     void ForgetSkippable(bool removeChildlessNodes);
    1151                 : 
    1152                 :     // returns whether anything was collected
    1153                 :     bool CollectWhite(nsICycleCollectorListener *aListener);
    1154                 : 
    1155                 :     nsCycleCollector();
    1156                 :     ~nsCycleCollector();
    1157                 : 
    1158                 :     // The first pair of Suspect and Forget functions are only used by
    1159                 :     // old XPCOM binary components.
    1160                 :     bool Suspect(nsISupports *n);
    1161                 :     bool Forget(nsISupports *n);
    1162                 :     nsPurpleBufferEntry* Suspect2(nsISupports *n);
    1163                 :     bool Forget2(nsPurpleBufferEntry *e);
    1164                 : 
    1165                 :     void Collect(nsCycleCollectorResults *aResults,
    1166                 :                  PRUint32 aTryCollections,
    1167                 :                  nsICycleCollectorListener *aListener);
    1168                 : 
    1169                 :     // Prepare for and cleanup after one or more collection(s).
    1170                 :     bool PrepareForCollection(nsCycleCollectorResults *aResults,
    1171                 :                               nsTArray<PtrInfo*> *aWhiteNodes);
    1172                 :     void GCIfNeeded(bool aForceGC);
    1173                 :     void CleanupAfterCollection();
    1174                 : 
    1175                 :     // Start and finish an individual collection.
    1176                 :     bool BeginCollection(nsICycleCollectorListener *aListener);
    1177                 :     bool FinishCollection(nsICycleCollectorListener *aListener);
    1178                 : 
    1179                 :     PRUint32 SuspectedCount();
    1180                 :     void Shutdown();
    1181                 : 
    1182            1925 :     void ClearGraph()
    1183                 :     {
    1184            1925 :         mGraph.mNodes.Clear();
    1185            1925 :         mGraph.mEdges.Clear();
    1186            1925 :         mGraph.mWeakMaps.Clear();
    1187            1925 :         mGraph.mRootCount = 0;
    1188            1925 :     }
    1189                 : 
    1190                 : #ifdef DEBUG_CC
    1191                 :     nsCycleCollectorStats mStats;
    1192                 : 
    1193                 :     FILE *mPtrLog;
    1194                 : 
    1195                 :     void Allocated(void *n, size_t sz);
    1196                 :     void Freed(void *n);
    1197                 : 
    1198                 :     void LogPurpleRemoval(void* aObject);
    1199                 : 
    1200                 :     void ExplainLiveExpectedGarbage();
    1201                 :     bool CreateReversedEdges();
    1202                 :     void DestroyReversedEdges();
    1203                 :     void ShouldBeFreed(nsISupports *n);
    1204                 :     void WasFreed(nsISupports *n);
    1205                 :     PointerSet mExpectedGarbage;
    1206                 : #endif
    1207                 : };
    1208                 : 
    1209                 : 
    1210                 : /**
    1211                 :  * GraphWalker is templatized over a Visitor class that must provide
    1212                 :  * the following two methods:
    1213                 :  *
    1214                 :  * bool ShouldVisitNode(PtrInfo const *pi);
    1215                 :  * void VisitNode(PtrInfo *pi);
    1216                 :  */
    1217                 : template <class Visitor>
    1218                 : class GraphWalker
    1219                 : {
    1220                 : private:
    1221                 :     Visitor mVisitor;
    1222                 : 
    1223                 :     void DoWalk(nsDeque &aQueue);
    1224                 : 
    1225                 : public:
    1226                 :     void Walk(PtrInfo *s0);
    1227                 :     void WalkFromRoots(GCGraph &aGraph);
    1228                 :     // copy-constructing the visitor should be cheap, and less
    1229                 :     // indirection than using a reference
    1230           14693 :     GraphWalker(const Visitor aVisitor) : mVisitor(aVisitor) {}
    1231                 : };
    1232                 : 
    1233                 : 
    1234                 : ////////////////////////////////////////////////////////////////////////
    1235                 : // The static collector object
    1236                 : ////////////////////////////////////////////////////////////////////////
    1237                 : 
    1238                 : 
    1239                 : static nsCycleCollector *sCollector = nsnull;
    1240                 : 
    1241                 : 
    1242                 : ////////////////////////////////////////////////////////////////////////
    1243                 : // Utility functions
    1244                 : ////////////////////////////////////////////////////////////////////////
    1245                 : 
    1246               0 : class CCRunnableFaultReport : public nsRunnable {
    1247                 : public:
    1248               0 :     CCRunnableFaultReport(const nsCString& report)
    1249               0 :     {
    1250               0 :         CopyUTF8toUTF16(report, mReport);
    1251               0 :     }
    1252                 :     
    1253               0 :     NS_IMETHOD Run() {
    1254               0 :         nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    1255               0 :         if (obs) {
    1256               0 :             obs->NotifyObservers(nsnull, "cycle-collector-fault",
    1257               0 :                                  mReport.get());
    1258                 :         }
    1259                 : 
    1260                 :         nsCOMPtr<nsIConsoleService> cons =
    1261               0 :             do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    1262               0 :         if (cons) {
    1263               0 :             cons->LogStringMessage(mReport.get());
    1264                 :         }
    1265               0 :         return NS_OK;
    1266                 :     }
    1267                 : 
    1268                 : private:
    1269                 :     nsString mReport;
    1270                 : };
    1271                 : 
    1272                 : static void
    1273               0 : Fault(const char *msg, const void *ptr=nsnull)
    1274                 : {
    1275                 : #ifdef DEBUG_CC
    1276                 :     // This should be nearly impossible, but just in case.
    1277                 :     if (!sCollector)
    1278                 :         return;
    1279                 : 
    1280                 :     if (sCollector->mParams.mFaultIsFatal) {
    1281                 : 
    1282                 :         if (ptr)
    1283                 :             printf("Fatal fault in cycle collector: %s (ptr: %p)\n", msg, ptr);
    1284                 :         else
    1285                 :             printf("Fatal fault in cycle collector: %s\n", msg);
    1286                 : 
    1287                 :         exit(1);
    1288                 :     }
    1289                 : #endif
    1290                 : 
    1291                 :     nsPrintfCString str(256, "Fault in cycle collector: %s (ptr: %p)\n",
    1292               0 :                         msg, ptr);
    1293               0 :     NS_NOTREACHED(str.get());
    1294                 : 
    1295                 :     // When faults are not fatal, we assume we're running in a
    1296                 :     // production environment and we therefore want to disable the
    1297                 :     // collector on a fault. This will unfortunately cause the browser
    1298                 :     // to leak pretty fast wherever creates cyclical garbage, but it's
    1299                 :     // probably a better user experience than crashing. Besides, we
    1300                 :     // *should* never hit a fault.
    1301                 : 
    1302               0 :     sCollector->mParams.mDoNothing = true;
    1303                 : 
    1304                 :     // Report to observers off an event so we don't run JS under GC
    1305                 :     // (which is where we might be right now).
    1306               0 :     nsCOMPtr<nsIRunnable> ev = new CCRunnableFaultReport(str);
    1307               0 :     NS_DispatchToMainThread(ev);
    1308               0 : }
    1309                 : 
    1310                 : #ifdef DEBUG_CC
    1311                 : static void
    1312                 : Fault(const char *msg, PtrInfo *pi)
    1313                 : {
    1314                 :     printf("Fault in cycle collector: %s\n"
    1315                 :            "  while operating on pointer %p %s\n",
    1316                 :            msg, pi->mPointer, pi->mName);
    1317                 :     if (pi->mInternalRefs) {
    1318                 :         printf("  which has internal references from:\n");
    1319                 :         NodePool::Enumerator queue(sCollector->mGraph.mNodes);
    1320                 :         while (!queue.IsDone()) {
    1321                 :             PtrInfo *ppi = queue.GetNext();
    1322                 :             for (EdgePool::Iterator e = ppi->FirstChild(),
    1323                 :                                 e_end = ppi->LastChild();
    1324                 :                  e != e_end; ++e) {
    1325                 :                 if (*e == pi) {
    1326                 :                     printf("    %p %s\n", ppi->mPointer, ppi->mName);
    1327                 :                 }
    1328                 :             }
    1329                 :         }
    1330                 :     }
    1331                 : 
    1332                 :     Fault(msg, pi->mPointer);
    1333                 : }
    1334                 : #else
    1335                 : inline void
    1336               0 : Fault(const char *msg, PtrInfo *pi)
    1337                 : {
    1338               0 :     Fault(msg, pi->mPointer);
    1339               0 : }
    1340                 : #endif
    1341                 : 
    1342                 : static inline void
    1343         2839968 : AbortIfOffMainThreadIfCheckFast()
    1344                 : {
    1345                 : #if defined(XP_WIN) || defined(NS_TLS)
    1346         2839968 :     if (!NS_IsMainThread() && !NS_IsCycleCollectorThread()) {
    1347               0 :         NS_RUNTIMEABORT("Main-thread-only object used off the main thread");
    1348                 :     }
    1349                 : #endif
    1350         2839968 : }
    1351                 : 
    1352                 : static nsISupports *
    1353          878289 : canonicalize(nsISupports *in)
    1354                 : {
    1355                 :     nsISupports* child;
    1356                 :     in->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
    1357          878289 :                        reinterpret_cast<void**>(&child));
    1358          878289 :     return child;
    1359                 : }
    1360                 : 
    1361                 : static inline void
    1362         2360843 : ToParticipant(nsISupports *s, nsXPCOMCycleCollectionParticipant **cp)
    1363                 : {
    1364                 :     // We use QI to move from an nsISupports to an
    1365                 :     // nsXPCOMCycleCollectionParticipant, which is a per-class singleton helper
    1366                 :     // object that implements traversal and unlinking logic for the nsISupports
    1367                 :     // in question.
    1368         2360843 :     CallQueryInterface(s, cp);
    1369                 : #ifdef DEBUG_CC
    1370                 :     if (cp)
    1371                 :         ++sCollector->mStats.mSuccessfulQI;
    1372                 :     else
    1373                 :         ++sCollector->mStats.mFailedQI;
    1374                 : #endif
    1375         2360843 : }
    1376                 : 
    1377                 : nsCycleCollectionParticipant *
    1378               0 : nsCycleCollectionXPCOMRuntime::ToParticipant(void *p)
    1379                 : {
    1380                 :     nsXPCOMCycleCollectionParticipant *cp;
    1381               0 :     ::ToParticipant(static_cast<nsISupports*>(p), &cp);
    1382               0 :     return cp;
    1383                 : }
    1384                 : 
    1385                 : 
    1386                 : template <class Visitor>
    1387                 : MOZ_NEVER_INLINE void
    1388           12783 : GraphWalker<Visitor>::Walk(PtrInfo *s0)
    1389                 : {
    1390           25566 :     nsDeque queue;
    1391           12783 :     CC_AbortIfNull(s0);
    1392           12783 :     queue.Push(s0);
    1393           12783 :     DoWalk(queue);
    1394           12783 : }
    1395                 : 
    1396                 : template <class Visitor>
    1397                 : MOZ_NEVER_INLINE void
    1398            1910 : GraphWalker<Visitor>::WalkFromRoots(GCGraph& aGraph)
    1399                 : {
    1400            3820 :     nsDeque queue;
    1401            1910 :     NodePool::Enumerator etor(aGraph.mNodes);
    1402          127006 :     for (PRUint32 i = 0; i < aGraph.mRootCount; ++i) {
    1403          125096 :         PtrInfo *pi = etor.GetNext();
    1404          125096 :         CC_AbortIfNull(pi);
    1405          125096 :         queue.Push(pi);
    1406                 :     }
    1407            1910 :     DoWalk(queue);
    1408            1910 : }
    1409                 : 
    1410                 : template <class Visitor>
    1411                 : MOZ_NEVER_INLINE void
    1412           14693 : GraphWalker<Visitor>::DoWalk(nsDeque &aQueue)
    1413                 : {
    1414                 :     // Use a aQueue to match the breadth-first traversal used when we
    1415                 :     // built the graph, for hopefully-better locality.
    1416         1906493 :     while (aQueue.GetSize() > 0) {
    1417         1877107 :         PtrInfo *pi = static_cast<PtrInfo*>(aQueue.PopFront());
    1418         1877107 :         CC_AbortIfNull(pi);
    1419                 : 
    1420         1877107 :         if (mVisitor.ShouldVisitNode(pi)) {
    1421          615161 :             mVisitor.VisitNode(pi);
    1422         2969550 :             for (EdgePool::Iterator child = pi->FirstChild(),
    1423          615161 :                                 child_end = pi->LastChild();
    1424                 :                  child != child_end; ++child) {
    1425         1739228 :                 CC_AbortIfNull(*child);
    1426         1739228 :                 aQueue.Push(*child);
    1427                 :             }
    1428                 :         }
    1429                 :     };
    1430                 : 
    1431                 : #ifdef DEBUG_CC
    1432                 :     sCollector->mStats.mWalkedGraph++;
    1433                 : #endif
    1434           14693 : }
    1435                 : 
    1436                 : struct CCGraphDescriber
    1437               0 : {
    1438               0 :   CCGraphDescriber()
    1439               0 :   : mAddress("0x"), mToAddress("0x"), mCnt(0), mType(eUnknown) {}
    1440                 : 
    1441                 :   enum Type
    1442                 :   {
    1443                 :     eRefCountedObject,
    1444                 :     eGCedObject,
    1445                 :     eGCMarkedObject,
    1446                 :     eEdge,
    1447                 :     eRoot,
    1448                 :     eGarbage,
    1449                 :     eUnknown
    1450                 :   };
    1451                 : 
    1452                 :   nsCString mAddress;
    1453                 :   nsCString mToAddress;
    1454                 :   nsCString mName;
    1455                 :   PRUint32 mCnt;
    1456                 :   Type mType;
    1457                 : };
    1458                 : 
    1459                 : class nsCycleCollectorLogger : public nsICycleCollectorListener
    1460                 : {
    1461                 : public:
    1462               0 :     nsCycleCollectorLogger() :
    1463                 :       mStream(nsnull), mWantAllTraces(false),
    1464                 :       mDisableLog(false), mWantAfterProcessing(false),
    1465               0 :       mNextIndex(0)
    1466                 :     {
    1467               0 :     }
    1468               0 :     ~nsCycleCollectorLogger()
    1469               0 :     {
    1470               0 :         if (mStream) {
    1471               0 :             fclose(mStream);
    1472                 :         }
    1473               0 :     }
    1474                 :     NS_DECL_ISUPPORTS
    1475                 : 
    1476               0 :     NS_IMETHOD AllTraces(nsICycleCollectorListener** aListener)
    1477                 :     {
    1478               0 :         mWantAllTraces = true;
    1479               0 :         NS_ADDREF(*aListener = this);
    1480               0 :         return NS_OK;
    1481                 :     }
    1482                 : 
    1483               0 :     NS_IMETHOD GetWantAllTraces(bool* aAllTraces)
    1484                 :     {
    1485               0 :         *aAllTraces = mWantAllTraces;
    1486               0 :         return NS_OK;
    1487                 :     }
    1488                 : 
    1489               0 :     NS_IMETHOD GetDisableLog(bool* aDisableLog)
    1490                 :     {
    1491               0 :         *aDisableLog = mDisableLog;
    1492               0 :         return NS_OK;
    1493                 :     }
    1494                 : 
    1495               0 :     NS_IMETHOD SetDisableLog(bool aDisableLog)
    1496                 :     {
    1497               0 :         mDisableLog = aDisableLog;
    1498               0 :         return NS_OK;
    1499                 :     }
    1500                 : 
    1501               0 :     NS_IMETHOD GetWantAfterProcessing(bool* aWantAfterProcessing)
    1502                 :     {
    1503               0 :         *aWantAfterProcessing = mWantAfterProcessing;
    1504               0 :         return NS_OK;
    1505                 :     }
    1506                 : 
    1507               0 :     NS_IMETHOD SetWantAfterProcessing(bool aWantAfterProcessing)
    1508                 :     {
    1509               0 :         mWantAfterProcessing = aWantAfterProcessing;
    1510               0 :         return NS_OK;
    1511                 :     }
    1512                 : 
    1513               0 :     NS_IMETHOD Begin()
    1514                 :     {
    1515               0 :         mCurrentAddress.AssignLiteral("0x");
    1516               0 :         mDescribers.Clear();
    1517               0 :         mNextIndex = 0;
    1518               0 :         if (mDisableLog) {
    1519               0 :             return NS_OK;
    1520                 :         }
    1521               0 :         char basename[MAXPATHLEN] = {'\0'};
    1522               0 :         char ccname[MAXPATHLEN] = {'\0'};
    1523                 : #ifdef XP_WIN
    1524                 :         // On Windows, tmpnam returns useless stuff, such as "\\s164.".
    1525                 :         // Therefore we need to call the APIs directly.
    1526                 :         GetTempPathA(mozilla::ArrayLength(basename), basename);
    1527                 : #else
    1528               0 :         tmpnam(basename);
    1529               0 :         char *lastSlash = strrchr(basename, XPCOM_FILE_PATH_SEPARATOR[0]);
    1530               0 :         if (lastSlash) {
    1531               0 :             *lastSlash = '\0';
    1532                 :         }
    1533                 : #endif
    1534                 : 
    1535               0 :         ++gLogCounter;
    1536                 : 
    1537                 : #ifdef DEBUG
    1538                 :         // Dump the JS heap.
    1539               0 :         char gcname[MAXPATHLEN] = {'\0'};
    1540                 :         sprintf(gcname, "%s%sgc-edges-%d.%d.log", basename,
    1541                 :                 XPCOM_FILE_PATH_SEPARATOR,
    1542               0 :                 gLogCounter, base::GetCurrentProcId());
    1543                 : 
    1544               0 :         FILE* gcDumpFile = fopen(gcname, "w");
    1545               0 :         if (!gcDumpFile)
    1546               0 :             return NS_ERROR_FAILURE;
    1547               0 :         xpc::DumpJSHeap(gcDumpFile);
    1548               0 :         fclose(gcDumpFile);
    1549                 : #endif
    1550                 : 
    1551                 :         // Open a file for dumping the CC graph.
    1552                 :         sprintf(ccname, "%s%scc-edges-%d.%d.log", basename,
    1553                 :                 XPCOM_FILE_PATH_SEPARATOR,
    1554               0 :                 gLogCounter, base::GetCurrentProcId());
    1555               0 :         mStream = fopen(ccname, "w");
    1556               0 :         if (!mStream)
    1557               0 :             return NS_ERROR_FAILURE;
    1558                 : 
    1559                 :         nsCOMPtr<nsIConsoleService> cs =
    1560               0 :             do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    1561               0 :         if (cs) {
    1562               0 :             cs->LogStringMessage(NS_ConvertUTF8toUTF16(ccname).get());
    1563                 : #ifdef DEBUG
    1564               0 :             cs->LogStringMessage(NS_ConvertUTF8toUTF16(gcname).get());
    1565                 : #endif
    1566                 :         }
    1567                 : 
    1568               0 :         return NS_OK;
    1569                 :     }
    1570               0 :     NS_IMETHOD NoteRefCountedObject(PRUint64 aAddress, PRUint32 refCount,
    1571                 :                                     const char *aObjectDescription)
    1572                 :     {
    1573               0 :         if (!mDisableLog) {
    1574                 :             fprintf(mStream, "%p [rc=%u] %s\n", (void*)aAddress, refCount,
    1575               0 :                     aObjectDescription);
    1576                 :         }                          
    1577               0 :         if (mWantAfterProcessing) {
    1578               0 :             CCGraphDescriber* d = mDescribers.AppendElement();
    1579               0 :             NS_ENSURE_TRUE(d, NS_ERROR_OUT_OF_MEMORY);
    1580               0 :             mCurrentAddress.AssignLiteral("0x");
    1581               0 :             mCurrentAddress.AppendInt(aAddress, 16);
    1582               0 :             d->mType = CCGraphDescriber::eRefCountedObject;
    1583               0 :             d->mAddress = mCurrentAddress;
    1584               0 :             d->mCnt = refCount;
    1585               0 :             d->mName.Append(aObjectDescription);
    1586                 :         }                     
    1587               0 :         return NS_OK;
    1588                 :     }
    1589               0 :     NS_IMETHOD NoteGCedObject(PRUint64 aAddress, bool aMarked,
    1590                 :                               const char *aObjectDescription)
    1591                 :     {
    1592               0 :         if (!mDisableLog) {
    1593                 :             fprintf(mStream, "%p [gc%s] %s\n", (void*)aAddress,
    1594               0 :                     aMarked ? ".marked" : "", aObjectDescription);
    1595                 :         }
    1596               0 :         if (mWantAfterProcessing) {
    1597               0 :             CCGraphDescriber* d = mDescribers.AppendElement();
    1598               0 :             NS_ENSURE_TRUE(d, NS_ERROR_OUT_OF_MEMORY);
    1599               0 :             mCurrentAddress.AssignLiteral("0x");
    1600               0 :             mCurrentAddress.AppendInt(aAddress, 16);
    1601                 :             d->mType = aMarked ? CCGraphDescriber::eGCMarkedObject :
    1602               0 :                                  CCGraphDescriber::eGCedObject;
    1603               0 :             d->mAddress = mCurrentAddress;
    1604               0 :             d->mName.Append(aObjectDescription);
    1605                 :         }
    1606               0 :         return NS_OK;
    1607                 :     }
    1608               0 :     NS_IMETHOD NoteEdge(PRUint64 aToAddress, const char *aEdgeName)
    1609                 :     {
    1610               0 :         if (!mDisableLog) {
    1611               0 :             fprintf(mStream, "> %p %s\n", (void*)aToAddress, aEdgeName);
    1612                 :         }
    1613               0 :         if (mWantAfterProcessing) {
    1614               0 :             CCGraphDescriber* d = mDescribers.AppendElement();
    1615               0 :             NS_ENSURE_TRUE(d, NS_ERROR_OUT_OF_MEMORY);
    1616               0 :             d->mType = CCGraphDescriber::eEdge;
    1617               0 :             d->mAddress = mCurrentAddress;
    1618               0 :             d->mToAddress.AppendInt(aToAddress, 16);
    1619               0 :             d->mName.Append(aEdgeName);
    1620                 :         }
    1621               0 :         return NS_OK;
    1622                 :     }
    1623               0 :     NS_IMETHOD BeginResults()
    1624                 :     {
    1625               0 :         if (!mDisableLog) {
    1626               0 :             fputs("==========\n", mStream);
    1627                 :         }                     
    1628               0 :         return NS_OK;
    1629                 :     }
    1630               0 :     NS_IMETHOD DescribeRoot(PRUint64 aAddress, PRUint32 aKnownEdges)
    1631                 :     {
    1632               0 :         if (!mDisableLog) {
    1633               0 :             fprintf(mStream, "%p [known=%u]\n", (void*)aAddress, aKnownEdges);
    1634                 :         }
    1635               0 :         if (mWantAfterProcessing) {
    1636               0 :             CCGraphDescriber* d = mDescribers.AppendElement();
    1637               0 :             NS_ENSURE_TRUE(d, NS_ERROR_OUT_OF_MEMORY);
    1638               0 :             d->mType = CCGraphDescriber::eRoot;
    1639               0 :             d->mAddress.AppendInt(aAddress, 16);
    1640               0 :             d->mCnt = aKnownEdges;
    1641                 :         }
    1642               0 :         return NS_OK;
    1643                 :     }
    1644               0 :     NS_IMETHOD DescribeGarbage(PRUint64 aAddress)
    1645                 :     {
    1646               0 :         if (!mDisableLog) {
    1647               0 :             fprintf(mStream, "%p [garbage]\n", (void*)aAddress);
    1648                 :         }
    1649               0 :         if (mWantAfterProcessing) {
    1650               0 :             CCGraphDescriber* d = mDescribers.AppendElement();
    1651               0 :             NS_ENSURE_TRUE(d, NS_ERROR_OUT_OF_MEMORY);
    1652               0 :             d->mType = CCGraphDescriber::eGarbage;
    1653               0 :             d->mAddress.AppendInt(aAddress, 16);
    1654                 :         }
    1655               0 :         return NS_OK;
    1656                 :     }
    1657               0 :     NS_IMETHOD End()
    1658                 :     {
    1659               0 :         if (!mDisableLog) {
    1660               0 :             fclose(mStream);
    1661               0 :             mStream = nsnull;
    1662                 :         }
    1663               0 :         return NS_OK;
    1664                 :     }
    1665                 : 
    1666               0 :     NS_IMETHOD ProcessNext(nsICycleCollectorHandler* aHandler,
    1667                 :                            bool* aCanContinue)
    1668                 :     {
    1669               0 :         NS_ENSURE_STATE(aHandler && mWantAfterProcessing);
    1670               0 :         if (mNextIndex < mDescribers.Length()) {
    1671               0 :             CCGraphDescriber& d = mDescribers[mNextIndex++];
    1672               0 :             switch (d.mType) {
    1673                 :                 case CCGraphDescriber::eRefCountedObject:
    1674                 :                     aHandler->NoteRefCountedObject(d.mAddress,
    1675                 :                                                    d.mCnt,
    1676               0 :                                                    d.mName);
    1677               0 :                     break;
    1678                 :                 case CCGraphDescriber::eGCedObject:
    1679                 :                 case CCGraphDescriber::eGCMarkedObject:
    1680                 :                     aHandler->NoteGCedObject(d.mAddress,
    1681                 :                                              d.mType ==
    1682                 :                                                CCGraphDescriber::eGCMarkedObject,
    1683               0 :                                              d.mName);
    1684               0 :                     break;
    1685                 :                 case CCGraphDescriber::eEdge:
    1686                 :                     aHandler->NoteEdge(d.mAddress,
    1687                 :                                        d.mToAddress,
    1688               0 :                                        d.mName);
    1689               0 :                     break;
    1690                 :                 case CCGraphDescriber::eRoot:
    1691                 :                     aHandler->DescribeRoot(d.mAddress,
    1692               0 :                                            d.mCnt);
    1693               0 :                     break;
    1694                 :                 case CCGraphDescriber::eGarbage:
    1695               0 :                     aHandler->DescribeGarbage(d.mAddress);
    1696               0 :                     break;
    1697                 :                 case CCGraphDescriber::eUnknown:
    1698               0 :                     NS_NOTREACHED("CCGraphDescriber::eUnknown");
    1699               0 :                     break;
    1700                 :             }
    1701                 :         }
    1702               0 :         if (!(*aCanContinue = mNextIndex < mDescribers.Length())) {
    1703               0 :             mCurrentAddress.AssignLiteral("0x");
    1704               0 :             mDescribers.Clear();
    1705               0 :             mNextIndex = 0;
    1706                 :         }
    1707               0 :         return NS_OK;
    1708                 :     }
    1709                 : private:
    1710                 :     FILE *mStream;
    1711                 :     bool mWantAllTraces;
    1712                 :     bool mDisableLog;
    1713                 :     bool mWantAfterProcessing;
    1714                 :     nsCString mCurrentAddress; 
    1715                 :     nsTArray<CCGraphDescriber> mDescribers;
    1716                 :     PRUint32 mNextIndex;
    1717                 :     static PRUint32 gLogCounter;
    1718                 : };
    1719                 : 
    1720               0 : NS_IMPL_ISUPPORTS1(nsCycleCollectorLogger, nsICycleCollectorListener)
    1721                 : 
    1722                 : PRUint32 nsCycleCollectorLogger::gLogCounter = 0;
    1723                 : 
    1724                 : nsresult
    1725               0 : nsCycleCollectorLoggerConstructor(nsISupports* aOuter,
    1726                 :                                   const nsIID& aIID,
    1727                 :                                   void* *aInstancePtr)
    1728                 : {
    1729               0 :     NS_ENSURE_TRUE(!aOuter, NS_ERROR_NO_AGGREGATION);
    1730                 : 
    1731               0 :     nsISupports *logger = new nsCycleCollectorLogger();
    1732                 : 
    1733               0 :     return logger->QueryInterface(aIID, aInstancePtr);
    1734                 : }
    1735                 : 
    1736                 : ////////////////////////////////////////////////////////////////////////
    1737                 : // Bacon & Rajan's |MarkRoots| routine.
    1738                 : ////////////////////////////////////////////////////////////////////////
    1739                 : 
    1740                 : struct PtrToNodeEntry : public PLDHashEntryHdr
    1741                 : {
    1742                 :     // The key is mNode->mPointer
    1743                 :     PtrInfo *mNode;
    1744                 : };
    1745                 : 
    1746                 : static bool
    1747         1248881 : PtrToNodeMatchEntry(PLDHashTable *table,
    1748                 :                     const PLDHashEntryHdr *entry,
    1749                 :                     const void *key)
    1750                 : {
    1751         1248881 :     const PtrToNodeEntry *n = static_cast<const PtrToNodeEntry*>(entry);
    1752         1248881 :     return n->mNode->mPointer == key;
    1753                 : }
    1754                 : 
    1755                 : static PLDHashTableOps PtrNodeOps = {
    1756                 :     PL_DHashAllocTable,
    1757                 :     PL_DHashFreeTable,
    1758                 :     PL_DHashVoidPtrKeyStub,
    1759                 :     PtrToNodeMatchEntry,
    1760                 :     PL_DHashMoveEntryStub,
    1761                 :     PL_DHashClearEntryStub,
    1762                 :     PL_DHashFinalizeStub,
    1763                 :     nsnull
    1764                 : };
    1765                 : 
    1766                 : class GCGraphBuilder : public nsCycleCollectionTraversalCallback
    1767                 : {
    1768                 : private:
    1769                 :     NodePool::Builder mNodeBuilder;
    1770                 :     EdgePool::Builder mEdgeBuilder;
    1771                 :     nsTArray<WeakMapping> &mWeakMaps;
    1772                 :     PLDHashTable mPtrToNodeMap;
    1773                 :     PtrInfo *mCurrPi;
    1774                 :     nsCycleCollectionLanguageRuntime **mRuntimes; // weak, from nsCycleCollector
    1775                 :     nsCString mNextEdgeName;
    1776                 :     nsICycleCollectorListener *mListener;
    1777                 : 
    1778                 : public:
    1779                 :     GCGraphBuilder(GCGraph &aGraph,
    1780                 :                    nsCycleCollectionLanguageRuntime **aRuntimes,
    1781                 :                    nsICycleCollectorListener *aListener);
    1782                 :     ~GCGraphBuilder();
    1783                 :     bool Initialized();
    1784                 : 
    1785            3835 :     PRUint32 Count() const { return mPtrToNodeMap.entryCount; }
    1786                 : 
    1787                 : #ifdef DEBUG_CC
    1788                 :     PtrInfo* AddNode(void *s, nsCycleCollectionParticipant *aParticipant,
    1789                 :                      PRUint32 aLangID);
    1790                 : #else
    1791                 :     PtrInfo* AddNode(void *s, nsCycleCollectionParticipant *aParticipant);
    1792         1850766 :     PtrInfo* AddNode(void *s, nsCycleCollectionParticipant *aParticipant,
    1793                 :                      PRUint32 aLangID)
    1794                 :     {
    1795         1850766 :         return AddNode(s, aParticipant);
    1796                 :     }
    1797                 : #endif
    1798                 :     PtrInfo* AddWeakMapNode(void* node);
    1799                 :     void Traverse(PtrInfo* aPtrInfo);
    1800                 :     void SetLastChild();
    1801                 : 
    1802                 :     // nsCycleCollectionTraversalCallback methods.
    1803                 :     NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root);
    1804                 : 
    1805                 : private:
    1806          601885 :     void DescribeNode(PRUint32 refCount,
    1807                 :                       size_t objSz,
    1808                 :                       const char *objName)
    1809                 :     {
    1810          601885 :         mCurrPi->mRefCount = refCount;
    1811                 : #ifdef DEBUG_CC
    1812                 :         mCurrPi->mBytes = objSz;
    1813                 :         mCurrPi->mName = PL_strdup(objName);
    1814                 :         sCollector->mStats.mVisitedNode++;
    1815                 : #endif
    1816          601885 :     }
    1817                 : 
    1818                 :     NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refCount, size_t objSz,
    1819                 :                                              const char *objName);
    1820                 :     NS_IMETHOD_(void) DescribeGCedNode(bool isMarked, size_t objSz,
    1821                 :                                        const char *objName);
    1822                 :     NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void *child,
    1823                 :                                nsCycleCollectionParticipant* participant);
    1824                 :     NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child);
    1825                 :     NS_IMETHOD_(void) NoteNativeChild(void *child,
    1826                 :                                       nsCycleCollectionParticipant *participant);
    1827                 :     NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void *child);
    1828                 :     NS_IMETHOD_(void) NoteNextEdgeName(const char* name);
    1829                 :     NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *val);
    1830                 : private:
    1831         1725048 :     NS_IMETHOD_(void) NoteChild(void *child, nsCycleCollectionParticipant *cp,
    1832                 :                                 PRUint32 langID, nsCString edgeName)
    1833                 :     {
    1834         1725048 :         PtrInfo *childPi = AddNode(child, cp, langID);
    1835         1725048 :         if (!childPi)
    1836               0 :             return;
    1837         1725048 :         mEdgeBuilder.Add(childPi);
    1838                 : #ifdef DEBUG_CC
    1839                 :         mCurrPi->mEdgeNames.AppendElement(edgeName);
    1840                 : #endif
    1841         1725048 :         if (mListener) {
    1842               0 :             mListener->NoteEdge((PRUint64)child, edgeName.get());
    1843                 :         }
    1844         1725048 :         ++childPi->mInternalRefs;
    1845                 :     }
    1846                 : };
    1847                 : 
    1848            1925 : GCGraphBuilder::GCGraphBuilder(GCGraph &aGraph,
    1849                 :                                nsCycleCollectionLanguageRuntime **aRuntimes,
    1850                 :                                nsICycleCollectorListener *aListener)
    1851                 :     : mNodeBuilder(aGraph.mNodes),
    1852                 :       mEdgeBuilder(aGraph.mEdges),
    1853                 :       mWeakMaps(aGraph.mWeakMaps),
    1854                 :       mRuntimes(aRuntimes),
    1855            1925 :       mListener(aListener)
    1856                 : {
    1857            1925 :     if (!PL_DHashTableInit(&mPtrToNodeMap, &PtrNodeOps, nsnull,
    1858            1925 :                            sizeof(PtrToNodeEntry), 32768))
    1859               0 :         mPtrToNodeMap.ops = nsnull;
    1860                 : 
    1861            1925 :     PRUint32 flags = 0;
    1862                 : #ifdef DEBUG_CC
    1863                 :     flags = nsCycleCollectionTraversalCallback::WANT_DEBUG_INFO |
    1864                 :             nsCycleCollectionTraversalCallback::WANT_ALL_TRACES;
    1865                 : #endif
    1866            1925 :     if (!flags && mListener) {
    1867               0 :         flags = nsCycleCollectionTraversalCallback::WANT_DEBUG_INFO;
    1868               0 :         bool all = false;
    1869               0 :         mListener->GetWantAllTraces(&all);
    1870               0 :         if (all) {
    1871               0 :             flags |= nsCycleCollectionTraversalCallback::WANT_ALL_TRACES;
    1872                 :         }
    1873                 :     }
    1874                 : 
    1875            1925 :     mFlags |= flags;
    1876            1925 : }
    1877                 : 
    1878            3850 : GCGraphBuilder::~GCGraphBuilder()
    1879                 : {
    1880            1925 :     if (mPtrToNodeMap.ops)
    1881            1925 :         PL_DHashTableFinish(&mPtrToNodeMap);
    1882            1925 : }
    1883                 : 
    1884                 : bool
    1885            1925 : GCGraphBuilder::Initialized()
    1886                 : {
    1887            1925 :     return !!mPtrToNodeMap.ops;
    1888                 : }
    1889                 : 
    1890                 : PtrInfo*
    1891         1850766 : GCGraphBuilder::AddNode(void *s, nsCycleCollectionParticipant *aParticipant
    1892                 :                         IF_DEBUG_CC_PARAM(PRUint32 aLangID)
    1893                 :                        )
    1894                 : {
    1895         1850766 :     PtrToNodeEntry *e = static_cast<PtrToNodeEntry*>(PL_DHashTableOperate(&mPtrToNodeMap, s, PL_DHASH_ADD));
    1896         1850766 :     if (!e)
    1897               0 :         return nsnull;
    1898                 : 
    1899                 :     PtrInfo *result;
    1900         1850766 :     if (!e->mNode) {
    1901                 :         // New entry.
    1902                 :         result = mNodeBuilder.Add(s, aParticipant
    1903                 :                                   IF_DEBUG_CC_PARAM(aLangID)
    1904          601885 :                                  );
    1905          601885 :         if (!result) {
    1906               0 :             PL_DHashTableRawRemove(&mPtrToNodeMap, e);
    1907               0 :             return nsnull;
    1908                 :         }
    1909          601885 :         e->mNode = result;
    1910                 :     } else {
    1911         1248881 :         result = e->mNode;
    1912         1248881 :         NS_ASSERTION(result->mParticipant == aParticipant,
    1913                 :                      "nsCycleCollectionParticipant shouldn't change!");
    1914                 :     }
    1915         1850766 :     return result;
    1916                 : }
    1917                 : 
    1918                 : MOZ_NEVER_INLINE void
    1919          601885 : GCGraphBuilder::Traverse(PtrInfo* aPtrInfo)
    1920                 : {
    1921          601885 :     mCurrPi = aPtrInfo;
    1922                 : 
    1923                 : #ifdef DEBUG_CC
    1924                 :     if (!mCurrPi->mParticipant) {
    1925                 :         Fault("unknown pointer during walk", aPtrInfo);
    1926                 :         return;
    1927                 :     }
    1928                 : #endif
    1929                 : 
    1930          601885 :     mCurrPi->SetFirstChild(mEdgeBuilder.Mark());
    1931                 : 
    1932          601885 :     nsresult rv = aPtrInfo->mParticipant->Traverse(aPtrInfo->mPointer, *this);
    1933          601885 :     if (NS_FAILED(rv)) {
    1934               0 :         Fault("script pointer traversal failed", aPtrInfo);
    1935                 :     }
    1936          601885 : }
    1937                 : 
    1938                 : void
    1939            1927 : GCGraphBuilder::SetLastChild()
    1940                 : {
    1941            1927 :     mCurrPi->SetLastChild(mEdgeBuilder.Mark());
    1942            1927 : }
    1943                 : 
    1944                 : NS_IMETHODIMP_(void)
    1945            7322 : GCGraphBuilder::NoteXPCOMRoot(nsISupports *root)
    1946                 : {
    1947            7322 :     root = canonicalize(root);
    1948            7322 :     NS_ASSERTION(root,
    1949                 :                  "Don't add objects that don't participate in collection!");
    1950                 : 
    1951                 : #ifdef DEBUG_CC
    1952                 :     if (nsCycleCollector_shouldSuppress(root))
    1953                 :         return;
    1954                 : #endif
    1955                 :     
    1956                 :     nsXPCOMCycleCollectionParticipant *cp;
    1957            7322 :     ToParticipant(root, &cp);
    1958                 : 
    1959            7322 :     NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, root, cp);
    1960            7322 : }
    1961                 : 
    1962                 : 
    1963                 : NS_IMETHODIMP_(void)
    1964           13298 : GCGraphBuilder::NoteRoot(PRUint32 langID, void *root,
    1965                 :                          nsCycleCollectionParticipant* participant)
    1966                 : {
    1967           13298 :     NS_ASSERTION(root, "Don't add a null root!");
    1968                 : 
    1969           13298 :     if (langID > nsIProgrammingLanguage::MAX || !mRuntimes[langID]) {
    1970               0 :         Fault("adding root for unregistered language", root);
    1971               0 :         return;
    1972                 :     }
    1973                 : 
    1974           13298 :     if (!participant->CanSkipThis(root) || WantAllTraces()) {
    1975           13298 :         AddNode(root, participant, langID);
    1976                 :     }
    1977                 : }
    1978                 : 
    1979                 : NS_IMETHODIMP_(void)
    1980          149511 : GCGraphBuilder::DescribeRefCountedNode(nsrefcnt refCount, size_t objSz,
    1981                 :                                        const char *objName)
    1982                 : {
    1983          149511 :     if (refCount == 0)
    1984               0 :         Fault("zero refcount", mCurrPi);
    1985          149511 :     if (refCount == PR_UINT32_MAX)
    1986               0 :         Fault("overflowing refcount", mCurrPi);
    1987          149511 :     sCollector->mVisitedRefCounted++;
    1988                 : 
    1989          149511 :     if (mListener) {
    1990                 :         mListener->NoteRefCountedObject((PRUint64)mCurrPi->mPointer, refCount,
    1991               0 :                                         objName);
    1992                 :     }
    1993                 : 
    1994          149511 :     DescribeNode(refCount, objSz, objName);
    1995          149511 : }
    1996                 : 
    1997                 : NS_IMETHODIMP_(void)
    1998          452374 : GCGraphBuilder::DescribeGCedNode(bool isMarked, size_t objSz,
    1999                 :                                  const char *objName)
    2000                 : {
    2001          452374 :     PRUint32 refCount = isMarked ? PR_UINT32_MAX : 0;
    2002          452374 :     sCollector->mVisitedGCed++;
    2003                 : 
    2004          452374 :     if (mListener) {
    2005                 :         mListener->NoteGCedObject((PRUint64)mCurrPi->mPointer, isMarked,
    2006               0 :                                   objName);
    2007                 :     }
    2008                 : 
    2009          452374 :     DescribeNode(refCount, objSz, objName);
    2010          452374 : }
    2011                 : 
    2012                 : NS_IMETHODIMP_(void)
    2013          423319 : GCGraphBuilder::NoteXPCOMChild(nsISupports *child) 
    2014                 : {
    2015          846638 :     nsCString edgeName;
    2016          423319 :     if (WantDebugInfo()) {
    2017               0 :         edgeName.Assign(mNextEdgeName);
    2018               0 :         mNextEdgeName.Truncate();
    2019                 :     }
    2020          423319 :     if (!child || !(child = canonicalize(child)))
    2021                 :         return; 
    2022                 : 
    2023                 : #ifdef DEBUG_CC
    2024                 :     if (nsCycleCollector_shouldSuppress(child))
    2025                 :         return;
    2026                 : #endif
    2027                 :     
    2028                 :     nsXPCOMCycleCollectionParticipant *cp;
    2029          360393 :     ToParticipant(child, &cp);
    2030          360393 :     if (cp && (!cp->CanSkipThis(child) || WantAllTraces())) {
    2031          360377 :         NoteChild(child, cp, nsIProgrammingLanguage::CPLUSPLUS, edgeName);
    2032                 :     }
    2033                 : }
    2034                 : 
    2035                 : NS_IMETHODIMP_(void)
    2036           14084 : GCGraphBuilder::NoteNativeChild(void *child,
    2037                 :                                 nsCycleCollectionParticipant *participant)
    2038                 : {
    2039           28168 :     nsCString edgeName;
    2040           14084 :     if (WantDebugInfo()) {
    2041               0 :         edgeName.Assign(mNextEdgeName);
    2042               0 :         mNextEdgeName.Truncate();
    2043                 :     }
    2044           14084 :     if (!child)
    2045                 :         return;
    2046                 : 
    2047           12488 :     NS_ASSERTION(participant, "Need a nsCycleCollectionParticipant!");
    2048           12488 :     NoteChild(child, participant, nsIProgrammingLanguage::CPLUSPLUS, edgeName);
    2049                 : }
    2050                 : 
    2051                 : NS_IMETHODIMP_(void)
    2052         1357231 : GCGraphBuilder::NoteScriptChild(PRUint32 langID, void *child) 
    2053                 : {
    2054         2714462 :     nsCString edgeName;
    2055         1357231 :     if (WantDebugInfo()) {
    2056               0 :         edgeName.Assign(mNextEdgeName);
    2057               0 :         mNextEdgeName.Truncate();
    2058                 :     }
    2059         1357231 :     if (!child)
    2060                 :         return;
    2061                 : 
    2062         1357230 :     if (langID > nsIProgrammingLanguage::MAX) {
    2063               0 :         Fault("traversing pointer for unknown language", child);
    2064                 :         return;
    2065                 :     }
    2066                 : 
    2067         1357230 :     if (!mRuntimes[langID]) {
    2068                 :         NS_WARNING("Not collecting cycles involving objects for scripting "
    2069               0 :                    "languages that don't participate in cycle collection.");
    2070                 :         return;
    2071                 :     }
    2072                 : 
    2073                 :     // skip over non-grey JS children
    2074         2719507 :     if (langID == nsIProgrammingLanguage::JAVASCRIPT &&
    2075         1362277 :         !xpc_GCThingIsGrayCCThing(child) && !WantAllTraces()) {
    2076                 :         return;
    2077                 :     }
    2078                 : 
    2079         1352183 :     nsCycleCollectionParticipant *cp = mRuntimes[langID]->ToParticipant(child);
    2080         1352183 :     if (cp)
    2081         1352183 :         NoteChild(child, cp, langID, edgeName);
    2082                 : }
    2083                 : 
    2084                 : NS_IMETHODIMP_(void)
    2085               0 : GCGraphBuilder::NoteNextEdgeName(const char* name)
    2086                 : {
    2087               0 :     if (WantDebugInfo()) {
    2088               0 :         mNextEdgeName = name;
    2089                 :     }
    2090               0 : }
    2091                 : 
    2092                 : PtrInfo*
    2093               0 : GCGraphBuilder::AddWeakMapNode(void *node)
    2094                 : {
    2095                 :     nsCycleCollectionParticipant *cp;
    2096               0 :     NS_ASSERTION(node, "Weak map node should be non-null.");
    2097                 : 
    2098               0 :     if (!xpc_GCThingIsGrayCCThing(node) && !WantAllTraces())
    2099               0 :         return nsnull;
    2100                 : 
    2101               0 :     cp = mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]->ToParticipant(node);
    2102               0 :     NS_ASSERTION(cp, "Javascript runtime participant should be non-null.");
    2103               0 :     return AddNode(node, cp, nsIProgrammingLanguage::JAVASCRIPT);
    2104                 : }
    2105                 : 
    2106                 : NS_IMETHODIMP_(void)
    2107               0 : GCGraphBuilder::NoteWeakMapping(void *map, void *key, void *val)
    2108                 : {
    2109               0 :     PtrInfo *valNode = AddWeakMapNode(val);
    2110                 : 
    2111               0 :     if (!valNode)
    2112               0 :         return;
    2113                 : 
    2114               0 :     WeakMapping *mapping = mWeakMaps.AppendElement();
    2115               0 :     mapping->mMap = map ? AddWeakMapNode(map) : nsnull;
    2116               0 :     mapping->mKey = key ? AddWeakMapNode(key) : nsnull;
    2117               0 :     mapping->mVal = valNode;
    2118                 : }
    2119                 : 
    2120                 : // MayHaveChild() will be false after a Traverse if the object does
    2121                 : // not have any children the CC will visit.
    2122                 : class ChildFinder : public nsCycleCollectionTraversalCallback
    2123                 : {
    2124                 : public:
    2125           25631 :     ChildFinder() : mMayHaveChild(false) {}
    2126                 : 
    2127                 :     // The logic of the Note*Child functions must mirror that of their
    2128                 :     // respective functions in GCGraphBuilder.
    2129                 :     NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child);
    2130                 :     NS_IMETHOD_(void) NoteNativeChild(void *child,
    2131                 :                                       nsCycleCollectionParticipant *helper);
    2132                 :     NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void *child);
    2133                 : 
    2134           25631 :     NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refcount,
    2135                 :                                              size_t objsz,
    2136           25631 :                                              const char *objname) {};
    2137               0 :     NS_IMETHOD_(void) DescribeGCedNode(bool ismarked,
    2138                 :                                        size_t objsz,
    2139               0 :                                        const char *objname) {};
    2140               0 :     NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) {};
    2141               0 :     NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void *root,
    2142               0 :                                nsCycleCollectionParticipant* helper) {};
    2143               0 :     NS_IMETHOD_(void) NoteNextEdgeName(const char* name) {};
    2144               0 :     NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *val) {};
    2145           25631 :     bool MayHaveChild() {
    2146           25631 :         return mMayHaveChild;
    2147                 :     };
    2148                 : private:
    2149                 :     bool mMayHaveChild;
    2150                 : };
    2151                 : 
    2152                 : NS_IMETHODIMP_(void)
    2153           75351 : ChildFinder::NoteXPCOMChild(nsISupports *child)
    2154                 : {
    2155           75351 :     if (!child || !(child = canonicalize(child)))
    2156            5241 :         return; 
    2157                 :     nsXPCOMCycleCollectionParticipant *cp;
    2158           70110 :     ToParticipant(child, &cp);
    2159           70110 :     if (cp && !cp->CanSkip(child, true))
    2160           69934 :         mMayHaveChild = true;
    2161                 : };
    2162                 : 
    2163                 : NS_IMETHODIMP_(void)
    2164            2274 : ChildFinder::NoteNativeChild(void *child,
    2165                 :                              nsCycleCollectionParticipant *helper)
    2166                 : {
    2167            2274 :     if (child)
    2168            2078 :         mMayHaveChild = true;
    2169            2274 : };
    2170                 : 
    2171                 : NS_IMETHODIMP_(void)
    2172               1 : ChildFinder::NoteScriptChild(PRUint32 langID, void *child)
    2173                 : {
    2174               1 :     if (!child)
    2175               1 :         return;
    2176               0 :     if (langID == nsIProgrammingLanguage::JAVASCRIPT &&
    2177               0 :         !xpc_GCThingIsGrayCCThing(child)) {
    2178               0 :         return;
    2179                 :     }
    2180               0 :     mMayHaveChild = true;
    2181                 : };
    2182                 : 
    2183                 : static bool
    2184          115052 : AddPurpleRoot(GCGraphBuilder &builder, nsISupports *root)
    2185                 : {
    2186          115052 :     root = canonicalize(root);
    2187          115052 :     NS_ASSERTION(root,
    2188                 :                  "Don't add objects that don't participate in collection!");
    2189                 : 
    2190                 :     nsXPCOMCycleCollectionParticipant *cp;
    2191          115052 :     ToParticipant(root, &cp);
    2192                 : 
    2193          115052 :     if (builder.WantAllTraces() || !cp->CanSkipInCC(root)) {
    2194                 :         PtrInfo *pinfo = builder.AddNode(root, cp,
    2195          112420 :                                          nsIProgrammingLanguage::CPLUSPLUS);
    2196          112420 :         if (!pinfo) {
    2197               0 :             return false;
    2198                 :         }
    2199                 :     }
    2200                 : 
    2201          115052 :     cp->UnmarkIfPurple(root);
    2202                 : 
    2203          115052 :     return true;
    2204                 : }
    2205                 : 
    2206                 : static bool
    2207           25631 : MayHaveChild(nsISupports *o, nsXPCOMCycleCollectionParticipant* cp)
    2208                 : {
    2209           25631 :     ChildFinder cf;
    2210           25631 :     cp->Traverse(o, cf);
    2211           25631 :     return cf.MayHaveChild();
    2212                 : }
    2213                 : 
    2214                 : void
    2215             276 : nsPurpleBuffer::RemoveSkippable(bool removeChildlessNodes)
    2216                 : {
    2217                 :     // Walk through all the blocks.
    2218            1882 :     for (Block *b = &mFirstBlock; b; b = b->mNext) {
    2219          412742 :         for (nsPurpleBufferEntry *e = b->mEntries,
    2220            1606 :                               *eEnd = ArrayEnd(b->mEntries);
    2221                 :             e != eEnd; ++e) {
    2222          409530 :             if (!(PRUword(e->mObject) & PRUword(1))) {
    2223                 :                 // This is a real entry (rather than something on the
    2224                 :                 // free list).
    2225          318755 :                 if (e->mObject) {
    2226          318468 :                     nsISupports* o = canonicalize(e->mObject);
    2227                 :                     nsXPCOMCycleCollectionParticipant* cp;
    2228          318468 :                     ToParticipant(o, &cp);
    2229          638932 :                     if (!cp->CanSkip(o, false) &&
    2230          320464 :                         (!removeChildlessNodes || MayHaveChild(o, cp))) {
    2231          294779 :                         continue;
    2232                 :                     }
    2233           23689 :                     cp->UnmarkIfPurple(o);
    2234                 :                 }
    2235           23976 :                 Remove(e);
    2236                 :             }
    2237                 :         }
    2238                 :     }
    2239             276 : }
    2240                 : 
    2241                 : #ifdef DEBUG_CC
    2242                 : static PLDHashOperator
    2243                 : noteAllCallback(nsVoidPtrHashKey* key, void* userArg)
    2244                 : {
    2245                 :     GCGraphBuilder *builder = static_cast<GCGraphBuilder*>(userArg);
    2246                 :     builder->NoteXPCOMRoot(
    2247                 :       static_cast<nsISupports *>(const_cast<void*>(key->GetKey())));
    2248                 :     return PL_DHASH_NEXT;
    2249                 : }
    2250                 : 
    2251                 : void
    2252                 : nsPurpleBuffer::NoteAll(GCGraphBuilder &builder)
    2253                 : {
    2254                 :     mCompatObjects.EnumerateEntries(noteAllCallback, &builder);
    2255                 : 
    2256                 :     for (Block *b = &mFirstBlock; b; b = b->mNext) {
    2257                 :         for (nsPurpleBufferEntry *e = b->mEntries,
    2258                 :                               *eEnd = ArrayEnd(b->mEntries);
    2259                 :             e != eEnd; ++e) {
    2260                 :             if (!(PRUword(e->mObject) & PRUword(1)) && e->mObject) {
    2261                 :                 builder.NoteXPCOMRoot(e->mObject);
    2262                 :             }
    2263                 :         }
    2264                 :     }
    2265                 : }
    2266                 : #endif
    2267                 : 
    2268                 : void 
    2269            1925 : nsCycleCollector::SelectPurple(GCGraphBuilder &builder)
    2270                 : {
    2271            1925 :     mPurpleBuf.SelectPointers(builder);
    2272            1925 : }
    2273                 : 
    2274                 : void 
    2275             276 : nsCycleCollector::ForgetSkippable(bool removeChildlessNodes)
    2276                 : {
    2277             552 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    2278             276 :     if (obs) {
    2279             276 :         obs->NotifyObservers(nsnull, "cycle-collector-forget-skippable", nsnull);
    2280                 :     }
    2281             276 :     mPurpleBuf.RemoveSkippable(removeChildlessNodes);
    2282             276 :     if (mForgetSkippableCB) {
    2283             276 :         mForgetSkippableCB();
    2284                 :     }
    2285             276 : }
    2286                 : 
    2287                 : MOZ_NEVER_INLINE void
    2288            1910 : nsCycleCollector::MarkRoots(GCGraphBuilder &builder)
    2289                 : {
    2290            1910 :     mGraph.mRootCount = builder.Count();
    2291                 : 
    2292                 :     // read the PtrInfo out of the graph that we are building
    2293            1910 :     NodePool::Enumerator queue(mGraph.mNodes);
    2294          605705 :     while (!queue.IsDone()) {
    2295          601885 :         PtrInfo *pi = queue.GetNext();
    2296          601885 :         CC_AbortIfNull(pi);
    2297          601885 :         builder.Traverse(pi);
    2298          601885 :         if (queue.AtBlockEnd())
    2299              17 :             builder.SetLastChild();
    2300                 :     }
    2301            1910 :     if (mGraph.mRootCount > 0)
    2302            1910 :         builder.SetLastChild();
    2303            1910 : }
    2304                 : 
    2305                 : 
    2306                 : ////////////////////////////////////////////////////////////////////////
    2307                 : // Bacon & Rajan's |ScanRoots| routine.
    2308                 : ////////////////////////////////////////////////////////////////////////
    2309                 : 
    2310                 : 
    2311                 : struct ScanBlackVisitor
    2312                 : {
    2313           12783 :     ScanBlackVisitor(PRUint32 &aWhiteNodeCount)
    2314           12783 :         : mWhiteNodeCount(aWhiteNodeCount)
    2315                 :     {
    2316           12783 :     }
    2317                 : 
    2318         1285245 :     bool ShouldVisitNode(PtrInfo const *pi)
    2319                 :     { 
    2320         1285245 :         return pi->mColor != black;
    2321                 :     }
    2322                 : 
    2323          440370 :     MOZ_NEVER_INLINE void VisitNode(PtrInfo *pi)
    2324                 :     {
    2325          440370 :         if (pi->mColor == white)
    2326             493 :             --mWhiteNodeCount;
    2327          440370 :         pi->mColor = black;
    2328                 : #ifdef DEBUG_CC
    2329                 :         sCollector->mStats.mSetColorBlack++;
    2330                 : #endif
    2331          440370 :     }
    2332                 : 
    2333                 :     PRUint32 &mWhiteNodeCount;
    2334                 : };
    2335                 : 
    2336                 : 
    2337                 : struct scanVisitor
    2338                 : {
    2339            1910 :     scanVisitor(PRUint32 &aWhiteNodeCount) : mWhiteNodeCount(aWhiteNodeCount)
    2340                 :     {
    2341            1910 :     }
    2342                 : 
    2343          591862 :     bool ShouldVisitNode(PtrInfo const *pi)
    2344                 :     { 
    2345          591862 :         return pi->mColor == grey;
    2346                 :     }
    2347                 : 
    2348          174791 :     MOZ_NEVER_INLINE void VisitNode(PtrInfo *pi)
    2349                 :     {
    2350          174791 :         if (pi->mInternalRefs > pi->mRefCount && pi->mRefCount > 0)
    2351               0 :             Fault("traversed refs exceed refcount", pi);
    2352                 : 
    2353          174791 :         if (pi->mInternalRefs == pi->mRefCount || pi->mRefCount == 0) {
    2354          162008 :             pi->mColor = white;
    2355          162008 :             ++mWhiteNodeCount;
    2356                 : #ifdef DEBUG_CC
    2357                 :             sCollector->mStats.mSetColorWhite++;
    2358                 : #endif
    2359                 :         } else {
    2360           12783 :             GraphWalker<ScanBlackVisitor>(ScanBlackVisitor(mWhiteNodeCount)).Walk(pi);
    2361           12783 :             NS_ASSERTION(pi->mColor == black,
    2362                 :                          "Why didn't ScanBlackVisitor make pi black?");
    2363                 :         }
    2364          174791 :     }
    2365                 : 
    2366                 :     PRUint32 &mWhiteNodeCount;
    2367                 : };
    2368                 : 
    2369                 : // Iterate over the WeakMaps.  If we mark anything while iterating
    2370                 : // over the WeakMaps, we must iterate over all of the WeakMaps again.
    2371                 : void
    2372            1910 : nsCycleCollector::ScanWeakMaps()
    2373                 : {
    2374                 :     bool anyChanged;
    2375            1910 :     do {
    2376            1910 :         anyChanged = false;
    2377            1910 :         for (PRUint32 i = 0; i < mGraph.mWeakMaps.Length(); i++) {
    2378               0 :             WeakMapping *wm = &mGraph.mWeakMaps[i];
    2379                 : 
    2380                 :             // If mMap or mKey are null, the original object was marked black.
    2381               0 :             uint32 mColor = wm->mMap ? wm->mMap->mColor : black;
    2382               0 :             uint32 kColor = wm->mKey ? wm->mKey->mColor : black;
    2383               0 :             PtrInfo *v = wm->mVal;
    2384                 : 
    2385                 :             // All non-null weak mapping maps, keys and values are
    2386                 :             // roots (in the sense of WalkFromRoots) in the cycle
    2387                 :             // collector graph, and thus should have been colored
    2388                 :             // either black or white in ScanRoots().
    2389               0 :             NS_ASSERTION(mColor != grey, "Uncolored weak map");
    2390               0 :             NS_ASSERTION(kColor != grey, "Uncolored weak map key");
    2391               0 :             NS_ASSERTION(v->mColor != grey, "Uncolored weak map value");
    2392                 : 
    2393               0 :             if (mColor == black && kColor == black && v->mColor != black) {
    2394               0 :                 GraphWalker<ScanBlackVisitor>(ScanBlackVisitor(mWhiteNodeCount)).Walk(v);
    2395               0 :                 anyChanged = true;
    2396                 :             }
    2397                 :         }
    2398                 :     } while (anyChanged);
    2399            1910 : }
    2400                 : 
    2401                 : void
    2402            1910 : nsCycleCollector::ScanRoots()
    2403                 : {
    2404            1910 :     mWhiteNodeCount = 0;
    2405                 : 
    2406                 :     // On the assumption that most nodes will be black, it's
    2407                 :     // probably faster to use a GraphWalker than a
    2408                 :     // NodePool::Enumerator.
    2409            1910 :     GraphWalker<scanVisitor>(scanVisitor(mWhiteNodeCount)).WalkFromRoots(mGraph); 
    2410                 : 
    2411            1910 :     ScanWeakMaps();
    2412                 : 
    2413                 : #ifdef DEBUG_CC
    2414                 :     // Sanity check: scan should have colored all grey nodes black or
    2415                 :     // white. So we ensure we have no grey nodes at this point.
    2416                 :     NodePool::Enumerator etor(mGraph.mNodes);
    2417                 :     while (!etor.IsDone())
    2418                 :     {
    2419                 :         PtrInfo *pinfo = etor.GetNext();
    2420                 :         if (pinfo->mColor == grey) {
    2421                 :             Fault("valid grey node after scanning", pinfo);
    2422                 :         }
    2423                 :     }
    2424                 : #endif
    2425            1910 : }
    2426                 : 
    2427                 : 
    2428                 : ////////////////////////////////////////////////////////////////////////
    2429                 : // Bacon & Rajan's |CollectWhite| routine, somewhat modified.
    2430                 : ////////////////////////////////////////////////////////////////////////
    2431                 : 
    2432                 : bool
    2433            1925 : nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
    2434                 : {
    2435                 :     // Explanation of "somewhat modified": we have no way to collect the
    2436                 :     // set of whites "all at once", we have to ask each of them to drop
    2437                 :     // their outgoing links and assume this will cause the garbage cycle
    2438                 :     // to *mostly* self-destruct (except for the reference we continue
    2439                 :     // to hold). 
    2440                 :     // 
    2441                 :     // To do this "safely" we must make sure that the white nodes we're
    2442                 :     // operating on are stable for the duration of our operation. So we
    2443                 :     // make 3 sets of calls to language runtimes:
    2444                 :     //
    2445                 :     //   - Root(whites), which should pin the whites in memory.
    2446                 :     //   - Unlink(whites), which drops outgoing links on each white.
    2447                 :     //   - Unroot(whites), which returns the whites to normal GC.
    2448                 : 
    2449                 :     nsresult rv;
    2450            1925 :     TimeLog timeLog;
    2451                 : 
    2452            1925 :     NS_ASSERTION(mWhiteNodes->IsEmpty(),
    2453                 :                  "FinishCollection wasn't called?");
    2454                 : 
    2455            1925 :     mWhiteNodes->SetCapacity(mWhiteNodeCount);
    2456            1925 :     PRUint32 numWhiteGCed = 0;
    2457                 : 
    2458            1925 :     NodePool::Enumerator etor(mGraph.mNodes);
    2459          605735 :     while (!etor.IsDone())
    2460                 :     {
    2461          601885 :         PtrInfo *pinfo = etor.GetNext();
    2462          601885 :         if (pinfo->mColor == white && mWhiteNodes->AppendElement(pinfo)) {
    2463          161515 :             rv = pinfo->mParticipant->Root(pinfo->mPointer);
    2464          161515 :             if (NS_FAILED(rv)) {
    2465               0 :                 Fault("Failed root call while unlinking", pinfo);
    2466               0 :                 mWhiteNodes->RemoveElementAt(mWhiteNodes->Length() - 1);
    2467          161515 :             } else if (pinfo->mRefCount == 0) {
    2468                 :                 // only JS objects have a refcount of 0
    2469           25671 :                 ++numWhiteGCed;
    2470                 :             }
    2471                 :         }
    2472                 :     }
    2473                 : 
    2474            1925 :     PRUint32 count = mWhiteNodes->Length();
    2475            1925 :     NS_ASSERTION(numWhiteGCed <= count,
    2476                 :                  "More freed GCed nodes than total freed nodes.");
    2477            1925 :     if (mResults) {
    2478              48 :         mResults->mFreedRefCounted += count - numWhiteGCed;
    2479              48 :         mResults->mFreedGCed += numWhiteGCed;
    2480                 :     }
    2481                 : 
    2482            1925 :     timeLog.Checkpoint("CollectWhite::Root");
    2483                 : 
    2484            1925 :     if (mBeforeUnlinkCB) {
    2485            1910 :         mBeforeUnlinkCB();
    2486            1910 :         timeLog.Checkpoint("CollectWhite::BeforeUnlinkCB");
    2487                 :     }
    2488                 : #if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
    2489                 :     struct _CrtMemState ms1, ms2;
    2490                 :     _CrtMemCheckpoint(&ms1);
    2491                 : #endif
    2492                 : 
    2493            1925 :     if (aListener) {
    2494               0 :         for (PRUint32 i = 0; i < count; ++i) {
    2495               0 :             PtrInfo *pinfo = mWhiteNodes->ElementAt(i);
    2496               0 :             aListener->DescribeGarbage((PRUint64)pinfo->mPointer);
    2497                 :         }
    2498               0 :         aListener->End();
    2499                 :     }
    2500                 : 
    2501          163440 :     for (PRUint32 i = 0; i < count; ++i) {
    2502          161515 :         PtrInfo *pinfo = mWhiteNodes->ElementAt(i);
    2503          161515 :         rv = pinfo->mParticipant->Unlink(pinfo->mPointer);
    2504          161515 :         if (NS_FAILED(rv)) {
    2505               0 :             Fault("Failed unlink call while unlinking", pinfo);
    2506                 : #ifdef DEBUG_CC
    2507                 :             mStats.mFailedUnlink++;
    2508                 : #endif
    2509                 :         }
    2510                 :         else {
    2511                 : #ifdef DEBUG_CC
    2512                 :             ++mStats.mCollectedNode;
    2513                 : #endif
    2514                 :         }
    2515                 :     }
    2516            1925 :     timeLog.Checkpoint("CollectWhite::Unlink");
    2517                 : 
    2518          163440 :     for (PRUint32 i = 0; i < count; ++i) {
    2519          161515 :         PtrInfo *pinfo = mWhiteNodes->ElementAt(i);
    2520          161515 :         rv = pinfo->mParticipant->Unroot(pinfo->mPointer);
    2521          161515 :         if (NS_FAILED(rv))
    2522               0 :             Fault("Failed unroot call while unlinking", pinfo);
    2523                 :     }
    2524            1925 :     timeLog.Checkpoint("CollectWhite::Unroot");
    2525                 : 
    2526                 : #if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
    2527                 :     _CrtMemCheckpoint(&ms2);
    2528                 :     if (ms2.lTotalCount < ms1.lTotalCount)
    2529                 :         mStats.mFreedBytes += (ms1.lTotalCount - ms2.lTotalCount);
    2530                 : #endif
    2531                 : 
    2532            1925 :     return count > 0;
    2533                 : }
    2534                 : 
    2535                 : 
    2536                 : #ifdef DEBUG_CC
    2537                 : ////////////////////////////////////////////////////////////////////////
    2538                 : // Memory-hooking stuff
    2539                 : // When debugging wild pointers, it sometimes helps to hook malloc and
    2540                 : // free. This stuff is disabled unless you set an environment variable.
    2541                 : ////////////////////////////////////////////////////////////////////////
    2542                 : 
    2543                 : static bool hookedMalloc = false;
    2544                 : 
    2545                 : #if defined(__GLIBC__) && !defined(__UCLIBC__)
    2546                 : #include <malloc.h>
    2547                 : 
    2548                 : static void* (*old_memalign_hook)(size_t, size_t, const void *);
    2549                 : static void* (*old_realloc_hook)(void *, size_t, const void *);
    2550                 : static void* (*old_malloc_hook)(size_t, const void *);
    2551                 : static void (*old_free_hook)(void *, const void *);
    2552                 : 
    2553                 : static void* my_memalign_hook(size_t, size_t, const void *);
    2554                 : static void* my_realloc_hook(void *, size_t, const void *);
    2555                 : static void* my_malloc_hook(size_t, const void *);
    2556                 : static void my_free_hook(void *, const void *);
    2557                 : 
    2558                 : static inline void 
    2559                 : install_old_hooks()
    2560                 : {
    2561                 :     __memalign_hook = old_memalign_hook;
    2562                 :     __realloc_hook = old_realloc_hook;
    2563                 :     __malloc_hook = old_malloc_hook;
    2564                 :     __free_hook = old_free_hook;
    2565                 : }
    2566                 : 
    2567                 : static inline void 
    2568                 : save_old_hooks()
    2569                 : {
    2570                 :     // Glibc docs recommend re-saving old hooks on
    2571                 :     // return from recursive calls. Strangely when 
    2572                 :     // we do this, we find ourselves in infinite
    2573                 :     // recursion.
    2574                 : 
    2575                 :     //     old_memalign_hook = __memalign_hook;
    2576                 :     //     old_realloc_hook = __realloc_hook;
    2577                 :     //     old_malloc_hook = __malloc_hook;
    2578                 :     //     old_free_hook = __free_hook;
    2579                 : }
    2580                 : 
    2581                 : static inline void 
    2582                 : install_new_hooks()
    2583                 : {
    2584                 :     __memalign_hook = my_memalign_hook;
    2585                 :     __realloc_hook = my_realloc_hook;
    2586                 :     __malloc_hook = my_malloc_hook;
    2587                 :     __free_hook = my_free_hook;
    2588                 : }
    2589                 : 
    2590                 : static void*
    2591                 : my_realloc_hook(void *ptr, size_t size, const void *caller)
    2592                 : {
    2593                 :     void *result;    
    2594                 : 
    2595                 :     install_old_hooks();
    2596                 :     result = realloc(ptr, size);
    2597                 :     save_old_hooks();
    2598                 : 
    2599                 :     if (sCollector) {
    2600                 :         sCollector->Freed(ptr);
    2601                 :         sCollector->Allocated(result, size);
    2602                 :     }
    2603                 : 
    2604                 :     install_new_hooks();
    2605                 : 
    2606                 :     return result;
    2607                 : }
    2608                 : 
    2609                 : 
    2610                 : static void* 
    2611                 : my_memalign_hook(size_t size, size_t alignment, const void *caller)
    2612                 : {
    2613                 :     void *result;    
    2614                 : 
    2615                 :     install_old_hooks();
    2616                 :     result = memalign(size, alignment);
    2617                 :     save_old_hooks();
    2618                 : 
    2619                 :     if (sCollector)
    2620                 :         sCollector->Allocated(result, size);
    2621                 : 
    2622                 :     install_new_hooks();
    2623                 : 
    2624                 :     return result;
    2625                 : }
    2626                 : 
    2627                 : 
    2628                 : static void 
    2629                 : my_free_hook (void *ptr, const void *caller)
    2630                 : {
    2631                 :     install_old_hooks();
    2632                 :     free(ptr);
    2633                 :     save_old_hooks();
    2634                 : 
    2635                 :     if (sCollector)
    2636                 :         sCollector->Freed(ptr);
    2637                 : 
    2638                 :     install_new_hooks();
    2639                 : }      
    2640                 : 
    2641                 : 
    2642                 : static void*
    2643                 : my_malloc_hook (size_t size, const void *caller)
    2644                 : {
    2645                 :     void *result;
    2646                 : 
    2647                 :     install_old_hooks();
    2648                 :     result = malloc (size);
    2649                 :     save_old_hooks();
    2650                 : 
    2651                 :     if (sCollector)
    2652                 :         sCollector->Allocated(result, size);
    2653                 : 
    2654                 :     install_new_hooks();
    2655                 : 
    2656                 :     return result;
    2657                 : }
    2658                 : 
    2659                 : 
    2660                 : static void 
    2661                 : InitMemHook(void)
    2662                 : {
    2663                 :     if (!hookedMalloc) {
    2664                 :         save_old_hooks();
    2665                 :         install_new_hooks();
    2666                 :         hookedMalloc = true;        
    2667                 :     }
    2668                 : }
    2669                 : 
    2670                 : #elif defined(WIN32)
    2671                 : #ifndef __MINGW32__
    2672                 : 
    2673                 : static int 
    2674                 : AllocHook(int allocType, void *userData, size_t size, int 
    2675                 :           blockType, long requestNumber, const unsigned char *filename, int 
    2676                 :           lineNumber)
    2677                 : {
    2678                 :     if (allocType == _HOOK_FREE)
    2679                 :         sCollector->Freed(userData);
    2680                 :     return 1;
    2681                 : }
    2682                 : 
    2683                 : 
    2684                 : static void InitMemHook(void)
    2685                 : {
    2686                 :     if (!hookedMalloc) {
    2687                 :         _CrtSetAllocHook (AllocHook);
    2688                 :         hookedMalloc = true;        
    2689                 :     }
    2690                 : }
    2691                 : #endif // __MINGW32__
    2692                 : 
    2693                 : #elif 0 // defined(XP_MACOSX)
    2694                 : 
    2695                 : #include <malloc/malloc.h>
    2696                 : 
    2697                 : static void (*old_free)(struct _malloc_zone_t *zone, void *ptr);
    2698                 : 
    2699                 : static void
    2700                 : freehook(struct _malloc_zone_t *zone, void *ptr)
    2701                 : {
    2702                 :     if (sCollector)
    2703                 :         sCollector->Freed(ptr);
    2704                 :     old_free(zone, ptr);
    2705                 : }
    2706                 : 
    2707                 : 
    2708                 : static void
    2709                 : InitMemHook(void)
    2710                 : {
    2711                 :     if (!hookedMalloc) {
    2712                 :         malloc_zone_t *default_zone = malloc_default_zone();
    2713                 :         old_free = default_zone->free;
    2714                 :         default_zone->free = freehook;
    2715                 :         hookedMalloc = true;
    2716                 :     }
    2717                 : }
    2718                 : 
    2719                 : 
    2720                 : #else
    2721                 : 
    2722                 : static void
    2723                 : InitMemHook(void)
    2724                 : {
    2725                 : }
    2726                 : 
    2727                 : #endif // GLIBC / WIN32 / OSX
    2728                 : #endif // DEBUG_CC
    2729                 : 
    2730                 : ////////////////////////////////////////////////////////////////////////
    2731                 : // Collector implementation
    2732                 : ////////////////////////////////////////////////////////////////////////
    2733                 : 
    2734            1419 : nsCycleCollector::nsCycleCollector() :
    2735                 :     mCollectionInProgress(false),
    2736                 :     mScanInProgress(false),
    2737                 :     mResults(nsnull),
    2738                 :     mWhiteNodes(nsnull),
    2739                 :     mWhiteNodeCount(0),
    2740                 :     mVisitedRefCounted(0),
    2741                 :     mVisitedGCed(0),
    2742                 : #ifdef DEBUG_CC
    2743                 :     mPurpleBuf(mParams, mStats),
    2744                 :     mPtrLog(nsnull),
    2745                 : #else
    2746                 :     mPurpleBuf(mParams),
    2747                 : #endif
    2748                 :    mBeforeUnlinkCB(nsnull),
    2749            1419 :    mForgetSkippableCB(nsnull)
    2750                 : {
    2751                 : #ifdef DEBUG_CC
    2752                 :     mExpectedGarbage.Init();
    2753                 : #endif
    2754                 : 
    2755            1419 :     memset(mRuntimes, 0, sizeof(mRuntimes));
    2756            1419 :     mRuntimes[nsIProgrammingLanguage::CPLUSPLUS] = &mXPCOMRuntime;
    2757            1419 : }
    2758                 : 
    2759                 : 
    2760            1419 : nsCycleCollector::~nsCycleCollector()
    2761                 : {
    2762            1419 : }
    2763                 : 
    2764                 : 
    2765                 : void 
    2766            1404 : nsCycleCollector::RegisterRuntime(PRUint32 langID, 
    2767                 :                                   nsCycleCollectionLanguageRuntime *rt)
    2768                 : {
    2769            1404 :     if (mParams.mDoNothing)
    2770               0 :         return;
    2771                 : 
    2772            1404 :     if (langID > nsIProgrammingLanguage::MAX)
    2773               0 :         Fault("unknown language runtime in registration");
    2774                 : 
    2775            1404 :     if (mRuntimes[langID])
    2776               0 :         Fault("multiple registrations of language runtime", rt);
    2777                 : 
    2778            1404 :     mRuntimes[langID] = rt;
    2779                 : }
    2780                 : 
    2781                 : nsCycleCollectionLanguageRuntime *
    2782               0 : nsCycleCollector::GetRuntime(PRUint32 langID)
    2783                 : {
    2784               0 :     if (langID > nsIProgrammingLanguage::MAX)
    2785               0 :         return nsnull;
    2786                 : 
    2787               0 :     return mRuntimes[langID];
    2788                 : }
    2789                 : 
    2790                 : void 
    2791               0 : nsCycleCollector::ForgetRuntime(PRUint32 langID)
    2792                 : {
    2793               0 :     if (mParams.mDoNothing)
    2794               0 :         return;
    2795                 : 
    2796               0 :     if (langID > nsIProgrammingLanguage::MAX)
    2797               0 :         Fault("unknown language runtime in deregistration");
    2798                 : 
    2799               0 :     if (! mRuntimes[langID])
    2800               0 :         Fault("forgetting non-registered language runtime");
    2801                 : 
    2802               0 :     mRuntimes[langID] = nsnull;
    2803                 : }
    2804                 : 
    2805                 : #ifdef DEBUG_CC
    2806                 : 
    2807                 : class Suppressor :
    2808                 :     public nsCycleCollectionTraversalCallback
    2809                 : {
    2810                 : protected:
    2811                 :     static char *sSuppressionList;
    2812                 :     static bool sInitialized;
    2813                 :     bool mSuppressThisNode;
    2814                 : public:
    2815                 :     Suppressor()
    2816                 :     {
    2817                 :     }
    2818                 : 
    2819                 :     bool shouldSuppress(nsISupports *s)
    2820                 :     {
    2821                 :         if (!sInitialized) {
    2822                 :             sSuppressionList = PR_GetEnv("XPCOM_CC_SUPPRESS");
    2823                 :             sInitialized = true;
    2824                 :         }
    2825                 :         if (sSuppressionList == nsnull) {
    2826                 :             mSuppressThisNode = false;
    2827                 :         } else {
    2828                 :             nsresult rv;
    2829                 :             nsXPCOMCycleCollectionParticipant *cp;
    2830                 :             rv = CallQueryInterface(s, &cp);
    2831                 :             if (NS_FAILED(rv)) {
    2832                 :                 Fault("checking suppression on wrong type of pointer", s);
    2833                 :                 return true;
    2834                 :             }
    2835                 :             cp->Traverse(s, *this);
    2836                 :         }
    2837                 :         return mSuppressThisNode;
    2838                 :     }
    2839                 : 
    2840                 :     NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refCount, size_t objSz,
    2841                 :                                              const char *objName)
    2842                 :     {
    2843                 :         mSuppressThisNode = (PL_strstr(sSuppressionList, objName) != nsnull);
    2844                 :     }
    2845                 : 
    2846                 :     NS_IMETHOD_(void) DescribeGCedNode(bool isMarked, size_t objSz,
    2847                 :                                        const char *objName)
    2848                 :     {
    2849                 :         mSuppressThisNode = (PL_strstr(sSuppressionList, objName) != nsnull);
    2850                 :     }
    2851                 : 
    2852                 :     NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) {};
    2853                 :     NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void *root,
    2854                 :                                nsCycleCollectionParticipant* participant) {};
    2855                 :     NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child) {}
    2856                 :     NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void *child) {}
    2857                 :     NS_IMETHOD_(void) NoteNativeChild(void *child,
    2858                 :                                      nsCycleCollectionParticipant *participant) {}
    2859                 :     NS_IMETHOD_(void) NoteNextEdgeName(const char* name) {}
    2860                 :     NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *val) {}
    2861                 : };
    2862                 : 
    2863                 : char *Suppressor::sSuppressionList = nsnull;
    2864                 : bool Suppressor::sInitialized = false;
    2865                 : 
    2866                 : static bool
    2867                 : nsCycleCollector_shouldSuppress(nsISupports *s)
    2868                 : {
    2869                 :     Suppressor supp;
    2870                 :     return supp.shouldSuppress(s);
    2871                 : }
    2872                 : #endif
    2873                 : 
    2874                 : #ifdef DEBUG
    2875                 : static bool
    2876         1489498 : nsCycleCollector_isScanSafe(nsISupports *s)
    2877                 : {
    2878         1489498 :     if (!s)
    2879               0 :         return false;
    2880                 : 
    2881                 :     nsXPCOMCycleCollectionParticipant *cp;
    2882         1489498 :     ToParticipant(s, &cp);
    2883                 : 
    2884         1489498 :     return cp != nsnull;
    2885                 : }
    2886                 : #endif
    2887                 : 
    2888                 : bool
    2889               0 : nsCycleCollector::Suspect(nsISupports *n)
    2890                 : {
    2891               0 :     AbortIfOffMainThreadIfCheckFast();
    2892                 : 
    2893                 :     // Re-entering ::Suspect during collection used to be a fault, but
    2894                 :     // we are canonicalizing nsISupports pointers using QI, so we will
    2895                 :     // see some spurious refcount traffic here. 
    2896                 : 
    2897               0 :     if (mScanInProgress)
    2898               0 :         return false;
    2899                 : 
    2900               0 :     NS_ASSERTION(nsCycleCollector_isScanSafe(n),
    2901                 :                  "suspected a non-scansafe pointer");
    2902                 : 
    2903               0 :     if (mParams.mDoNothing)
    2904               0 :         return false;
    2905                 : 
    2906                 : #ifdef DEBUG_CC
    2907                 :     mStats.mSuspectNode++;
    2908                 : 
    2909                 :     if (nsCycleCollector_shouldSuppress(n))
    2910                 :         return false;
    2911                 : 
    2912                 : #ifndef __MINGW32__
    2913                 :     if (mParams.mHookMalloc)
    2914                 :         InitMemHook();
    2915                 : #endif
    2916                 : 
    2917                 :     if (mParams.mLogPointers) {
    2918                 :         if (!mPtrLog)
    2919                 :             mPtrLog = fopen("pointer_log", "w");
    2920                 :         fprintf(mPtrLog, "S %p\n", static_cast<void*>(n));
    2921                 :     }
    2922                 : #endif
    2923                 : 
    2924               0 :     return mPurpleBuf.PutCompatObject(n);
    2925                 : }
    2926                 : 
    2927                 : 
    2928                 : bool
    2929               0 : nsCycleCollector::Forget(nsISupports *n)
    2930                 : {
    2931               0 :     AbortIfOffMainThreadIfCheckFast();
    2932                 : 
    2933                 :     // Re-entering ::Forget during collection used to be a fault, but
    2934                 :     // we are canonicalizing nsISupports pointers using QI, so we will
    2935                 :     // see some spurious refcount traffic here. 
    2936                 : 
    2937               0 :     if (mScanInProgress)
    2938               0 :         return false;
    2939                 : 
    2940               0 :     if (mParams.mDoNothing)
    2941               0 :         return true; // it's as good as forgotten
    2942                 : 
    2943                 : #ifdef DEBUG_CC
    2944                 :     mStats.mForgetNode++;
    2945                 : 
    2946                 : #ifndef __MINGW32__
    2947                 :     if (mParams.mHookMalloc)
    2948                 :         InitMemHook();
    2949                 : #endif
    2950                 : 
    2951                 :     if (mParams.mLogPointers) {
    2952                 :         if (!mPtrLog)
    2953                 :             mPtrLog = fopen("pointer_log", "w");
    2954                 :         fprintf(mPtrLog, "F %p\n", static_cast<void*>(n));
    2955                 :     }
    2956                 : #endif
    2957                 : 
    2958               0 :     mPurpleBuf.RemoveCompatObject(n);
    2959               0 :     return true;
    2960                 : }
    2961                 : 
    2962                 : nsPurpleBufferEntry*
    2963         1489498 : nsCycleCollector::Suspect2(nsISupports *n)
    2964                 : {
    2965         1489498 :     AbortIfOffMainThreadIfCheckFast();
    2966                 : 
    2967                 :     // Re-entering ::Suspect during collection used to be a fault, but
    2968                 :     // we are canonicalizing nsISupports pointers using QI, so we will
    2969                 :     // see some spurious refcount traffic here. 
    2970                 : 
    2971         1489498 :     if (mScanInProgress)
    2972               0 :         return nsnull;
    2973                 : 
    2974         1489498 :     NS_ASSERTION(nsCycleCollector_isScanSafe(n),
    2975                 :                  "suspected a non-scansafe pointer");
    2976                 : 
    2977         1489498 :     if (mParams.mDoNothing)
    2978               0 :         return nsnull;
    2979                 : 
    2980                 : #ifdef DEBUG_CC
    2981                 :     mStats.mSuspectNode++;
    2982                 : 
    2983                 :     if (nsCycleCollector_shouldSuppress(n))
    2984                 :         return nsnull;
    2985                 : 
    2986                 : #ifndef __MINGW32__
    2987                 :     if (mParams.mHookMalloc)
    2988                 :         InitMemHook();
    2989                 : #endif
    2990                 : 
    2991                 :     if (mParams.mLogPointers) {
    2992                 :         if (!mPtrLog)
    2993                 :             mPtrLog = fopen("pointer_log", "w");
    2994                 :         fprintf(mPtrLog, "S %p\n", static_cast<void*>(n));
    2995                 :     }
    2996                 : #endif
    2997                 : 
    2998                 :     // Caller is responsible for filling in result's mRefCnt.
    2999         1489498 :     return mPurpleBuf.Put(n);
    3000                 : }
    3001                 : 
    3002                 : 
    3003                 : bool
    3004         1350470 : nsCycleCollector::Forget2(nsPurpleBufferEntry *e)
    3005                 : {
    3006         1350470 :     AbortIfOffMainThreadIfCheckFast();
    3007                 : 
    3008                 :     // Re-entering ::Forget during collection used to be a fault, but
    3009                 :     // we are canonicalizing nsISupports pointers using QI, so we will
    3010                 :     // see some spurious refcount traffic here. 
    3011                 : 
    3012         1350470 :     if (mScanInProgress)
    3013               0 :         return false;
    3014                 : 
    3015                 : #ifdef DEBUG_CC
    3016                 :     LogPurpleRemoval(e->mObject);
    3017                 : #endif
    3018                 : 
    3019         1350470 :     mPurpleBuf.Remove(e);
    3020         1350470 :     return true;
    3021                 : }
    3022                 : 
    3023                 : #ifdef DEBUG_CC
    3024                 : void
    3025                 : nsCycleCollector_logPurpleRemoval(void* aObject)
    3026                 : {
    3027                 :     if (sCollector) {
    3028                 :         sCollector->LogPurpleRemoval(aObject);
    3029                 :     }
    3030                 : }
    3031                 : 
    3032                 : void
    3033                 : nsCycleCollector::LogPurpleRemoval(void* aObject)
    3034                 : {
    3035                 :     AbortIfOffMainThreadIfCheckFast();
    3036                 : 
    3037                 :     mStats.mForgetNode++;
    3038                 : 
    3039                 : #ifndef __MINGW32__
    3040                 :     if (mParams.mHookMalloc)
    3041                 :         InitMemHook();
    3042                 : #endif
    3043                 : 
    3044                 :     if (mParams.mLogPointers) {
    3045                 :         if (!mPtrLog)
    3046                 :             mPtrLog = fopen("pointer_log", "w");
    3047                 :         fprintf(mPtrLog, "F %p\n", aObject);
    3048                 :     }
    3049                 :     mPurpleBuf.mNormalObjects.RemoveEntry(aObject);
    3050                 : }
    3051                 : 
    3052                 : void 
    3053                 : nsCycleCollector::Allocated(void *n, size_t sz)
    3054                 : {
    3055                 : }
    3056                 : 
    3057                 : void 
    3058                 : nsCycleCollector::Freed(void *n)
    3059                 : {
    3060                 :     mStats.mFreeCalls++;
    3061                 : 
    3062                 :     if (!n) {
    3063                 :         // Ignore null pointers coming through
    3064                 :         return;
    3065                 :     }
    3066                 : 
    3067                 :     if (mPurpleBuf.Exists(n)) {
    3068                 :         mStats.mForgetNode++;
    3069                 :         mStats.mFreedWhilePurple++;
    3070                 :         Fault("freed while purple", n);
    3071                 :         
    3072                 :         if (mParams.mLogPointers) {
    3073                 :             if (!mPtrLog)
    3074                 :                 mPtrLog = fopen("pointer_log", "w");
    3075                 :             fprintf(mPtrLog, "R %p\n", n);
    3076                 :         }
    3077                 :     }
    3078                 : }
    3079                 : #endif
    3080                 : 
    3081                 : // The cycle collector uses the mark bitmap to discover what JS objects
    3082                 : // were reachable only from XPConnect roots that might participate in
    3083                 : // cycles. We ask the JS runtime whether we need to force a GC before
    3084                 : // this CC. It returns true on startup (before the mark bits have been set),
    3085                 : // and also when UnmarkGray has run out of stack.  We also force GCs on shut 
    3086                 : // down to collect cycles involving both DOM and JS.
    3087                 : void
    3088            1925 : nsCycleCollector::GCIfNeeded(bool aForceGC)
    3089                 : {
    3090            1925 :     NS_ASSERTION(NS_IsMainThread(),
    3091                 :                  "nsCycleCollector::GCIfNeeded() must be called on the main thread.");
    3092                 : 
    3093            1925 :     if (mParams.mDoNothing)
    3094               0 :         return;
    3095                 : 
    3096            1925 :     if (!mRuntimes[nsIProgrammingLanguage::JAVASCRIPT])
    3097              15 :         return;
    3098                 : 
    3099                 :     nsCycleCollectionJSRuntime* rt =
    3100                 :         static_cast<nsCycleCollectionJSRuntime*>
    3101            1910 :             (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]);
    3102            1910 :     if (!aForceGC) {
    3103              48 :         bool needGC = rt->NeedCollect();
    3104                 :         // Only do a telemetry ping for non-shutdown CCs.
    3105              48 :         Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_NEED_GC, needGC);
    3106              48 :         if (!needGC)
    3107              46 :             return;
    3108               2 :         if (mResults)
    3109               0 :             mResults->mForcedGC = true;
    3110                 :     }
    3111                 : 
    3112            1864 :     TimeLog timeLog;
    3113                 : 
    3114                 :     // rt->Collect() must be called from the main thread,
    3115                 :     // because it invokes XPCJSRuntime::GCCallback(cx, JSGC_BEGIN)
    3116                 :     // which returns false if not in the main thread.
    3117            1864 :     rt->Collect(js::gcreason::CC_FORCED, nsGCNormal);
    3118            1864 :     timeLog.Checkpoint("GC()");
    3119                 : }
    3120                 : 
    3121                 : bool
    3122            1467 : nsCycleCollector::PrepareForCollection(nsCycleCollectorResults *aResults,
    3123                 :                                        nsTArray<PtrInfo*> *aWhiteNodes)
    3124                 : {
    3125                 : #if defined(DEBUG_CC) && !defined(__MINGW32__)
    3126                 :     if (!mParams.mDoNothing && mParams.mHookMalloc)
    3127                 :         InitMemHook();
    3128                 : #endif
    3129                 : 
    3130                 :     // This can legitimately happen in a few cases. See bug 383651.
    3131            1467 :     if (mCollectionInProgress)
    3132               0 :         return false;
    3133                 : 
    3134            1467 :     TimeLog timeLog;
    3135                 : 
    3136            1467 :     mCollectionStart = TimeStamp::Now();
    3137            1467 :     mVisitedRefCounted = 0;
    3138            1467 :     mVisitedGCed = 0;
    3139                 : 
    3140            1467 :     mCollectionInProgress = true;
    3141                 : 
    3142                 :     nsCOMPtr<nsIObserverService> obs =
    3143            2934 :         mozilla::services::GetObserverService();
    3144            1467 :     if (obs)
    3145              48 :         obs->NotifyObservers(nsnull, "cycle-collector-begin", nsnull);
    3146                 : 
    3147            1467 :     mFollowupCollection = false;
    3148                 : 
    3149            1467 :     mResults = aResults;
    3150            1467 :     mWhiteNodes = aWhiteNodes;
    3151                 : 
    3152            1467 :     timeLog.Checkpoint("PrepareForCollection()");
    3153                 : 
    3154            1467 :     return true;
    3155                 : }
    3156                 : 
    3157                 : void
    3158            1467 : nsCycleCollector::CleanupAfterCollection()
    3159                 : {
    3160            1467 :     mWhiteNodes = nsnull;
    3161            1467 :     mCollectionInProgress = false;
    3162                 : 
    3163                 : #ifdef XP_OS2
    3164                 :     // Now that the cycle collector has freed some memory, we can try to
    3165                 :     // force the C library to give back as much memory to the system as
    3166                 :     // possible.
    3167                 :     _heapmin();
    3168                 : #endif
    3169                 : 
    3170            1467 :     PRUint32 interval = (PRUint32) ((TimeStamp::Now() - mCollectionStart).ToMilliseconds());
    3171                 : #ifdef COLLECT_TIME_DEBUG
    3172                 :     printf("cc: total cycle collector time was %ums\n", interval);
    3173                 :     if (mResults) {
    3174                 :         printf("cc: visited %u ref counted and %u GCed objects, freed %d ref counted and %d GCed objects.\n",
    3175                 :                mVisitedRefCounted, mVisitedGCed,
    3176                 :                mResults->mFreedRefCounted, mResults->mFreedGCed);
    3177                 :     } else {
    3178                 :         printf("cc: visited %u ref counted and %u GCed objects, freed %d.\n",
    3179                 :                mVisitedRefCounted, mVisitedGCed, mWhiteNodeCount);
    3180                 :     }
    3181                 :     printf("cc: \n");
    3182                 : #endif
    3183            1467 :     if (mResults) {
    3184              48 :         mResults->mVisitedRefCounted = mVisitedRefCounted;
    3185              48 :         mResults->mVisitedGCed = mVisitedGCed;
    3186              48 :         mResults = nsnull;
    3187                 :     }
    3188            1467 :     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR, interval);
    3189            1467 :     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_VISITED_REF_COUNTED, mVisitedRefCounted);
    3190            1467 :     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_VISITED_GCED, mVisitedGCed);
    3191            1467 :     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_COLLECTED, mWhiteNodeCount);
    3192                 : 
    3193                 : #ifdef DEBUG_CC
    3194                 :     ExplainLiveExpectedGarbage();
    3195                 : #endif
    3196            1467 : }
    3197                 : 
    3198                 : void
    3199            1419 : nsCycleCollector::Collect(nsCycleCollectorResults *aResults,
    3200                 :                           PRUint32 aTryCollections,
    3201                 :                           nsICycleCollectorListener *aListener)
    3202                 : {
    3203            2838 :     nsAutoTArray<PtrInfo*, 4000> whiteNodes;
    3204                 : 
    3205            1419 :     if (!PrepareForCollection(aResults, &whiteNodes))
    3206                 :         return;
    3207                 : 
    3208            1419 :     PRUint32 totalCollections = 0;
    3209            3296 :     while (aTryCollections > totalCollections) {
    3210                 :         // Synchronous cycle collection. Always force a JS GC beforehand.
    3211            1877 :         GCIfNeeded(true);
    3212            1877 :         if (aListener && NS_FAILED(aListener->Begin()))
    3213               0 :             aListener = nsnull;
    3214            3296 :         if (!(BeginCollection(aListener) &&
    3215            1877 :               FinishCollection(aListener)))
    3216            1419 :             break;
    3217                 : 
    3218             458 :         ++totalCollections;
    3219                 :     }
    3220                 : 
    3221            1419 :     CleanupAfterCollection();
    3222                 : }
    3223                 : 
    3224                 : bool
    3225            1925 : nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
    3226                 : {
    3227                 :     // aListener should be Begin()'d before this
    3228            1925 :     TimeLog timeLog;
    3229                 : 
    3230            1925 :     if (mParams.mDoNothing)
    3231               0 :         return false;
    3232                 : 
    3233            3850 :     GCGraphBuilder builder(mGraph, mRuntimes, aListener);
    3234            1925 :     if (!builder.Initialized())
    3235               0 :         return false;
    3236                 : 
    3237           23100 :     for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) {
    3238           21175 :         if (mRuntimes[i])
    3239            3835 :             mRuntimes[i]->BeginCycleCollection(builder, false);
    3240                 :     }
    3241                 : 
    3242            1925 :     timeLog.Checkpoint("mRuntimes[*]->BeginCycleCollection()");
    3243                 : 
    3244                 : #ifdef DEBUG_CC
    3245                 :     PRUint32 purpleStart = builder.Count();
    3246                 : #endif
    3247            1925 :     mScanInProgress = true;
    3248            1925 :     SelectPurple(builder);
    3249                 : #ifdef DEBUG_CC
    3250                 :     PRUint32 purpleEnd = builder.Count();
    3251                 : 
    3252                 :     if (purpleStart != purpleEnd) {
    3253                 : #ifndef __MINGW32__
    3254                 :         if (mParams.mHookMalloc)
    3255                 :             InitMemHook();
    3256                 : #endif
    3257                 :         if (mParams.mLogPointers && !mPtrLog)
    3258                 :             mPtrLog = fopen("pointer_log", "w");
    3259                 : 
    3260                 :         PRUint32 i = 0;
    3261                 :         NodePool::Enumerator queue(mGraph.mNodes);
    3262                 :         while (i++ < purpleStart) {
    3263                 :             queue.GetNext();
    3264                 :         }
    3265                 :         while (i++ < purpleEnd) {
    3266                 :             mStats.mForgetNode++;
    3267                 :             if (mParams.mLogPointers)
    3268                 :                 fprintf(mPtrLog, "F %p\n", queue.GetNext()->mPointer);
    3269                 :         }
    3270                 :     }
    3271                 : #endif
    3272                 : 
    3273            1925 :     timeLog.Checkpoint("SelectPurple()");
    3274                 : 
    3275            1925 :     if (builder.Count() > 0) {
    3276                 :         // The main Bacon & Rajan collection algorithm.
    3277                 : 
    3278            1910 :         MarkRoots(builder);
    3279            1910 :         timeLog.Checkpoint("MarkRoots()");
    3280                 : 
    3281            1910 :         ScanRoots();
    3282            1910 :         timeLog.Checkpoint("ScanRoots()");
    3283                 : 
    3284            1910 :         mScanInProgress = false;
    3285                 : 
    3286            1910 :         if (aListener) {
    3287               0 :             aListener->BeginResults();
    3288                 : 
    3289               0 :             NodePool::Enumerator etor(mGraph.mNodes);
    3290               0 :             while (!etor.IsDone()) {
    3291               0 :                 PtrInfo *pi = etor.GetNext();
    3292               0 :                 if (pi->mColor == black &&
    3293                 :                     pi->mRefCount > 0 && pi->mRefCount < PR_UINT32_MAX &&
    3294                 :                     pi->mInternalRefs != pi->mRefCount) {
    3295                 :                     aListener->DescribeRoot((PRUint64)pi->mPointer,
    3296               0 :                                             pi->mInternalRefs);
    3297                 :                 }
    3298                 :             }
    3299                 :         }
    3300                 : 
    3301                 : #ifdef DEBUG_CC
    3302                 :         if (mFollowupCollection && purpleStart != purpleEnd) {
    3303                 :             PRUint32 i = 0;
    3304                 :             NodePool::Enumerator queue(mGraph.mNodes);
    3305                 :             while (i++ < purpleStart) {
    3306                 :                 queue.GetNext();
    3307                 :             }
    3308                 :             while (i++ < purpleEnd) {
    3309                 :                 PtrInfo *pi = queue.GetNext();
    3310                 :                 if (pi->mColor == white) {
    3311                 :                     printf("nsCycleCollector: a later shutdown collection collected the additional\n"
    3312                 :                            "  suspect %p %s\n"
    3313                 :                            "  (which could be fixed by improving traversal)\n",
    3314                 :                            pi->mPointer, pi->mName);
    3315                 :                 }
    3316                 :             }
    3317                 :         }
    3318                 : #endif
    3319                 : 
    3320           22920 :         for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) {
    3321           21010 :             if (mRuntimes[i])
    3322            3820 :                 mRuntimes[i]->FinishTraverse();
    3323                 :         }
    3324            1910 :         timeLog.Checkpoint("mRuntimes[*]->FinishTraverse()");
    3325                 :     }
    3326                 :     else {
    3327              15 :         mScanInProgress = false;
    3328                 :     }
    3329                 : 
    3330            1925 :     return true;
    3331                 : }
    3332                 : 
    3333                 : bool
    3334            1925 : nsCycleCollector::FinishCollection(nsICycleCollectorListener *aListener)
    3335                 : {
    3336            1925 :     TimeLog timeLog;
    3337            1925 :     bool collected = CollectWhite(aListener);
    3338            1925 :     timeLog.Checkpoint("CollectWhite()");
    3339                 : 
    3340                 : #ifdef DEBUG_CC
    3341                 :     mStats.mCollection++;
    3342                 :     if (mParams.mReportStats)
    3343                 :         mStats.Dump();
    3344                 : #endif
    3345                 : 
    3346           23100 :     for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) {
    3347           21175 :         if (mRuntimes[i])
    3348            3835 :             mRuntimes[i]->FinishCycleCollection();
    3349                 :     }
    3350            1925 :     timeLog.Checkpoint("mRuntimes[*]->FinishCycleCollection()");
    3351                 : 
    3352            1925 :     mFollowupCollection = true;
    3353                 : 
    3354                 : #ifdef DEBUG_CC
    3355                 :     // We wait until after FinishCollection to check the white nodes because
    3356                 :     // some objects may outlive CollectWhite but then be freed by
    3357                 :     // FinishCycleCollection (like XPConnect's deferred release of native
    3358                 :     // objects).
    3359                 :     PRUint32 i, count = mWhiteNodes->Length();
    3360                 :     for (i = 0; i < count; ++i) {
    3361                 :         PtrInfo *pinfo = mWhiteNodes->ElementAt(i);
    3362                 :         if (pinfo->mLangID == nsIProgrammingLanguage::CPLUSPLUS &&
    3363                 :             mPurpleBuf.Exists(pinfo->mPointer)) {
    3364                 :             printf("nsCycleCollector: %s object @%p is still alive after\n"
    3365                 :                    "  calling RootAndUnlinkJSObjects, Unlink, and Unroot on"
    3366                 :                    " it!  This probably\n"
    3367                 :                    "  means the Unlink implementation was insufficient.\n",
    3368                 :                    pinfo->mName, pinfo->mPointer);
    3369                 :         }
    3370                 :     }
    3371                 : #endif
    3372                 : 
    3373            1925 :     mWhiteNodes->Clear();
    3374            1925 :     ClearGraph();
    3375            1925 :     timeLog.Checkpoint("ClearGraph()");
    3376                 : 
    3377            1925 :     mParams.mDoNothing = false;
    3378                 : 
    3379            1925 :     return collected;
    3380                 : }
    3381                 : 
    3382                 : PRUint32
    3383           23251 : nsCycleCollector::SuspectedCount()
    3384                 : {
    3385           23251 :     return mPurpleBuf.Count();
    3386                 : }
    3387                 : 
    3388                 : void
    3389            1419 : nsCycleCollector::Shutdown()
    3390                 : {
    3391                 :     // Here we want to run a final collection and then permanently
    3392                 :     // disable the collector because the program is shutting down.
    3393                 : 
    3394            2838 :     nsCOMPtr<nsCycleCollectorLogger> listener;
    3395            1419 :     if (mParams.mLogGraphs) {
    3396               0 :         listener = new nsCycleCollectorLogger();
    3397                 :     }
    3398            1419 :     Collect(nsnull, SHUTDOWN_COLLECTIONS(mParams), listener);
    3399                 : 
    3400                 : #ifdef DEBUG_CC
    3401                 :     GCGraphBuilder builder(mGraph, mRuntimes, nsnull);
    3402                 :     mScanInProgress = true;
    3403                 :     SelectPurple(builder);
    3404                 :     mScanInProgress = false;
    3405                 :     if (builder.Count() != 0) {
    3406                 :         printf("Might have been able to release more cycles if the cycle collector would "
    3407                 :                "run once more at shutdown.\n");
    3408                 :     }
    3409                 :     ClearGraph();
    3410                 : #endif
    3411            1419 :     mParams.mDoNothing = true;
    3412            1419 : }
    3413                 : 
    3414                 : #ifdef DEBUG_CC
    3415                 : 
    3416                 : static PLDHashOperator
    3417                 : AddExpectedGarbage(nsVoidPtrHashKey *p, void *arg)
    3418                 : {
    3419                 :     GCGraphBuilder *builder = static_cast<GCGraphBuilder*>(arg);
    3420                 :     nsISupports *root =
    3421                 :       static_cast<nsISupports*>(const_cast<void*>(p->GetKey()));
    3422                 :     builder->NoteXPCOMRoot(root);
    3423                 :     return PL_DHASH_NEXT;
    3424                 : }
    3425                 : 
    3426                 : struct SetSCCVisitor
    3427                 : {
    3428                 :     SetSCCVisitor(PRUint32 aIndex) : mIndex(aIndex) {}
    3429                 :     bool ShouldVisitNode(PtrInfo const *pi) { return pi->mSCCIndex == 0; }
    3430                 :     void VisitNode(PtrInfo *pi) { pi->mSCCIndex = mIndex; }
    3431                 : private:
    3432                 :     PRUint32 mIndex;
    3433                 : };
    3434                 : 
    3435                 : struct SetNonRootGreyVisitor
    3436                 : {
    3437                 :     bool ShouldVisitNode(PtrInfo const *pi) { return pi->mColor == white; }
    3438                 :     void VisitNode(PtrInfo *pi) { pi->mColor = grey; }
    3439                 : };
    3440                 : 
    3441                 : static void
    3442                 : PrintPathToExpectedGarbage(PtrInfo *pi)
    3443                 : {
    3444                 :     printf("  An object expected to be garbage could be "
    3445                 :            "reached from it by the path:\n");
    3446                 :     for (PtrInfo *path = pi, *prev = nsnull; prev != path;
    3447                 :          prev = path,
    3448                 :          path = path->mShortestPathToExpectedGarbage) {
    3449                 :         if (prev) {
    3450                 :             nsCString *edgeName = prev
    3451                 :                 ->mShortestPathToExpectedGarbageEdgeName;
    3452                 :             printf("        via %s\n",
    3453                 :                    edgeName->IsEmpty() ? "<unknown edge>"
    3454                 :                                        : edgeName->get());
    3455                 :         }
    3456                 :         printf("    %s %p\n", path->mName, path->mPointer);
    3457                 :     }
    3458                 : }
    3459                 : 
    3460                 : void
    3461                 : nsCycleCollector::ExplainLiveExpectedGarbage()
    3462                 : {
    3463                 :     if (mScanInProgress || mCollectionInProgress)
    3464                 :         Fault("can't explain expected garbage during collection itself");
    3465                 : 
    3466                 :     if (mParams.mDoNothing) {
    3467                 :         printf("nsCycleCollector: not explaining expected garbage since\n"
    3468                 :                "  cycle collection disabled\n");
    3469                 :         return;
    3470                 :     }
    3471                 : 
    3472                 :     mCollectionInProgress = true;
    3473                 :     mScanInProgress = true;
    3474                 : 
    3475                 :     {
    3476                 :         GCGraphBuilder builder(mGraph, mRuntimes, nsnull);
    3477                 : 
    3478                 :         // Instead of adding roots from the purple buffer, we add them
    3479                 :         // from the list of nodes we were expected to collect.
    3480                 :         // Put the expected garbage in *before* calling
    3481                 :         // BeginCycleCollection so that we can separate the expected
    3482                 :         // garbage from the NoteRoot calls in such a way that something
    3483                 :         // that's in both is considered expected garbage.
    3484                 :         mExpectedGarbage.EnumerateEntries(&AddExpectedGarbage, &builder);
    3485                 : 
    3486                 :         PRUint32 expectedGarbageCount = builder.Count();
    3487                 : 
    3488                 :         for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) {
    3489                 :             if (mRuntimes[i])
    3490                 :                 mRuntimes[i]->BeginCycleCollection(builder, true);
    3491                 :         }
    3492                 : 
    3493                 :         // But just for extra information, add entries from the purple
    3494                 :         // buffer too, since it may give us extra information about
    3495                 :         // traversal deficiencies.
    3496                 :         mPurpleBuf.NoteAll(builder);
    3497                 : 
    3498                 :         MarkRoots(builder);
    3499                 :         ScanRoots();
    3500                 : 
    3501                 :         mScanInProgress = false;
    3502                 : 
    3503                 :         for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) {
    3504                 :             if (mRuntimes[i]) {
    3505                 :                 mRuntimes[i]->FinishTraverse();
    3506                 :             }
    3507                 :         }
    3508                 : 
    3509                 :         bool describeExtraRefcounts = false;
    3510                 :         bool findCycleRoots = false;
    3511                 :         {
    3512                 :             NodePool::Enumerator queue(mGraph.mNodes);
    3513                 :             PRUint32 i = 0;
    3514                 :             while (!queue.IsDone()) {
    3515                 :                 PtrInfo *pi = queue.GetNext();
    3516                 :                 if (pi->mColor == white) {
    3517                 :                     findCycleRoots = true;
    3518                 :                 }
    3519                 : 
    3520                 :                 if (pi->mInternalRefs != pi->mRefCount &&
    3521                 :                     (i < expectedGarbageCount || i >= mGraph.mRootCount)) {
    3522                 :                     // This check isn't particularly useful anymore
    3523                 :                     // given that we need to enter this part for i >=
    3524                 :                     // mGraph.mRootCount and there are plenty of
    3525                 :                     // NoteRoot roots.
    3526                 :                     describeExtraRefcounts = true;
    3527                 :                 }
    3528                 :                 ++i;
    3529                 :             }
    3530                 :         }
    3531                 : 
    3532                 :         if ((describeExtraRefcounts || findCycleRoots) &&
    3533                 :             CreateReversedEdges()) {
    3534                 :             // Note that the external references may have been external
    3535                 :             // to a different node in the cycle collection that just
    3536                 :             // happened, if that different node was purple and then
    3537                 :             // black.
    3538                 : 
    3539                 :             // Use mSCCIndex temporarily to track whether we've reached
    3540                 :             // nodes in the breadth-first search.
    3541                 :             const PRUint32 INDEX_UNREACHED = 0;
    3542                 :             const PRUint32 INDEX_REACHED = 1;
    3543                 :             NodePool::Enumerator etor_clear(mGraph.mNodes);
    3544                 :             while (!etor_clear.IsDone()) {
    3545                 :                 PtrInfo *pi = etor_clear.GetNext();
    3546                 :                 pi->mSCCIndex = INDEX_UNREACHED;
    3547                 :             }
    3548                 : 
    3549                 :             nsDeque queue; // for breadth-first search
    3550                 :             NodePool::Enumerator etor_roots(mGraph.mNodes);
    3551                 :             for (PRUint32 i = 0; i < mGraph.mRootCount; ++i) {
    3552                 :                 PtrInfo *root_pi = etor_roots.GetNext();
    3553                 :                 if (i < expectedGarbageCount) {
    3554                 :                     root_pi->mSCCIndex = INDEX_REACHED;
    3555                 :                     root_pi->mShortestPathToExpectedGarbage = root_pi;
    3556                 :                     queue.Push(root_pi);
    3557                 :                 }
    3558                 :             }
    3559                 : 
    3560                 :             while (queue.GetSize() > 0) {
    3561                 :                 PtrInfo *pi = (PtrInfo*)queue.PopFront();
    3562                 :                 for (ReversedEdge *e = pi->mReversedEdges; e; e = e->mNext) {
    3563                 :                     if (e->mTarget->mSCCIndex == INDEX_UNREACHED) {
    3564                 :                         e->mTarget->mSCCIndex = INDEX_REACHED;
    3565                 :                         PtrInfo *target = e->mTarget;
    3566                 :                         if (!target->mShortestPathToExpectedGarbage) {
    3567                 :                             target->mShortestPathToExpectedGarbage = pi;
    3568                 :                             target->mShortestPathToExpectedGarbageEdgeName =
    3569                 :                                 e->mEdgeName;
    3570                 :                         }
    3571                 :                         queue.Push(target);
    3572                 :                     }
    3573                 :                 }
    3574                 : 
    3575                 :                 if (pi->mRefCount == PR_UINT32_MAX ||
    3576                 :                     (pi->mInternalRefs != pi->mRefCount && pi->mRefCount > 0)) {
    3577                 :                     if (pi->mRefCount == PR_UINT32_MAX) {
    3578                 :                         printf("nsCycleCollector: %s %p was not collected due "
    3579                 :                            "to \n"
    3580                 :                            "  external references\n",
    3581                 :                            pi->mName, pi->mPointer);
    3582                 :                     }
    3583                 :                     else {
    3584                 :                         printf("nsCycleCollector: %s %p was not collected due "
    3585                 :                                "to %d\n"
    3586                 :                                "  external references (%d total - %d known)\n",
    3587                 :                                pi->mName, pi->mPointer,
    3588                 :                                pi->mRefCount - pi->mInternalRefs,
    3589                 :                                pi->mRefCount, pi->mInternalRefs);
    3590                 :                     }
    3591                 : 
    3592                 :                     PrintPathToExpectedGarbage(pi);
    3593                 : 
    3594                 :                     if (pi->mRefCount == PR_UINT32_MAX) {
    3595                 :                         printf("  The known references to it were from:\n");
    3596                 :                     }
    3597                 :                     else {
    3598                 :                         printf("  The %d known references to it were from:\n",
    3599                 :                                pi->mInternalRefs);
    3600                 :                     }
    3601                 :                     for (ReversedEdge *e = pi->mReversedEdges;
    3602                 :                          e; e = e->mNext) {
    3603                 :                         printf("    %s %p",
    3604                 :                                e->mTarget->mName, e->mTarget->mPointer);
    3605                 :                         if (!e->mEdgeName->IsEmpty()) {
    3606                 :                             printf(" via %s", e->mEdgeName->get());
    3607                 :                         }
    3608                 :                         printf("\n");
    3609                 :                     }
    3610                 :                     mRuntimes[pi->mLangID]->PrintAllReferencesTo(pi->mPointer);
    3611                 :                 }
    3612                 :             }
    3613                 : 
    3614                 :             if (findCycleRoots) {
    3615                 :                 // NOTE: This code changes the white nodes that are not
    3616                 :                 // roots to gray.
    3617                 : 
    3618                 :                 // Put the nodes in post-order traversal order from a
    3619                 :                 // depth-first search.
    3620                 :                 nsDeque DFSPostOrder;
    3621                 : 
    3622                 :                 {
    3623                 :                     // Use mSCCIndex temporarily to track the DFS numbering:
    3624                 :                     const PRUint32 INDEX_UNREACHED = 0;
    3625                 :                     const PRUint32 INDEX_TRAVERSING = 1;
    3626                 :                     const PRUint32 INDEX_NUMBERED = 2;
    3627                 : 
    3628                 :                     NodePool::Enumerator etor_clear(mGraph.mNodes);
    3629                 :                     while (!etor_clear.IsDone()) {
    3630                 :                         PtrInfo *pi = etor_clear.GetNext();
    3631                 :                         pi->mSCCIndex = INDEX_UNREACHED;
    3632                 :                     }
    3633                 : 
    3634                 :                     nsDeque stack;
    3635                 : 
    3636                 :                     NodePool::Enumerator etor_roots(mGraph.mNodes);
    3637                 :                     for (PRUint32 i = 0; i < mGraph.mRootCount; ++i) {
    3638                 :                         PtrInfo *root_pi = etor_roots.GetNext();
    3639                 :                         stack.Push(root_pi);
    3640                 :                     }
    3641                 : 
    3642                 :                     while (stack.GetSize() > 0) {
    3643                 :                         PtrInfo *pi = (PtrInfo*)stack.Peek();
    3644                 :                         if (pi->mSCCIndex == INDEX_UNREACHED) {
    3645                 :                             pi->mSCCIndex = INDEX_TRAVERSING;
    3646                 :                             for (EdgePool::Iterator child = pi->FirstChild(),
    3647                 :                                                 child_end = pi->LastChild();
    3648                 :                                  child != child_end; ++child) {
    3649                 :                                 stack.Push(*child);
    3650                 :                             }
    3651                 :                         } else {
    3652                 :                             stack.Pop();
    3653                 :                             // Somebody else might have numbered it already
    3654                 :                             // (since this is depth-first, not breadth-first).
    3655                 :                             // This happens if a node is pushed on the stack
    3656                 :                             // a second time while it is on the stack in
    3657                 :                             // UNREACHED state.
    3658                 :                             if (pi->mSCCIndex == INDEX_TRAVERSING) {
    3659                 :                                 pi->mSCCIndex = INDEX_NUMBERED;
    3660                 :                                 DFSPostOrder.Push(pi);
    3661                 :                             }
    3662                 :                         }
    3663                 :                     }
    3664                 :                 }
    3665                 : 
    3666                 :                 // Put the nodes into strongly-connected components.
    3667                 :                 {
    3668                 :                     NodePool::Enumerator etor_clear(mGraph.mNodes);
    3669                 :                     while (!etor_clear.IsDone()) {
    3670                 :                         PtrInfo *pi = etor_clear.GetNext();
    3671                 :                         pi->mSCCIndex = 0;
    3672                 :                     }
    3673                 : 
    3674                 :                     PRUint32 currentSCC = 1;
    3675                 : 
    3676                 :                     while (DFSPostOrder.GetSize() > 0) {
    3677                 :                         GraphWalker<SetSCCVisitor>(SetSCCVisitor(currentSCC)).Walk((PtrInfo*)DFSPostOrder.PopFront());
    3678                 :                         ++currentSCC;
    3679                 :                     }
    3680                 :                 }
    3681                 : 
    3682                 :                 // Mark any white nodes reachable from other components as
    3683                 :                 // grey.
    3684                 :                 {
    3685                 :                     NodePool::Enumerator queue(mGraph.mNodes);
    3686                 :                     while (!queue.IsDone()) {
    3687                 :                         PtrInfo *pi = queue.GetNext();
    3688                 :                         if (pi->mColor != white)
    3689                 :                             continue;
    3690                 :                         for (EdgePool::Iterator child = pi->FirstChild(),
    3691                 :                                             child_end = pi->LastChild();
    3692                 :                              child != child_end; ++child) {
    3693                 :                             if ((*child)->mSCCIndex != pi->mSCCIndex) {
    3694                 :                                 GraphWalker<SetNonRootGreyVisitor>(SetNonRootGreyVisitor()).Walk(*child);
    3695                 :                             }
    3696                 :                         }
    3697                 :                     }
    3698                 :                 }
    3699                 : 
    3700                 :                 {
    3701                 :                     NodePool::Enumerator queue(mGraph.mNodes);
    3702                 :                     while (!queue.IsDone()) {
    3703                 :                         PtrInfo *pi = queue.GetNext();
    3704                 :                         if (pi->mColor == white) {
    3705                 :                             if (pi->mLangID ==
    3706                 :                                     nsIProgrammingLanguage::CPLUSPLUS &&
    3707                 :                                 mPurpleBuf.Exists(pi->mPointer)) {
    3708                 :                                 printf(
    3709                 : "nsCycleCollector: %s %p in component %d\n"
    3710                 : "  which was reference counted during the root/unlink/unroot phase of the\n"
    3711                 : "  last collection was not collected due to failure to unlink (see other\n"
    3712                 : "  warnings) or deficiency in traverse that causes cycles referenced only\n"
    3713                 : "  from other cycles to require multiple rounds of cycle collection in which\n"
    3714                 : "  this object was likely the reachable object\n",
    3715                 :                                        pi->mName, pi->mPointer, pi->mSCCIndex);
    3716                 :                             } else {
    3717                 :                                 printf(
    3718                 : "nsCycleCollector: %s %p in component %d\n"
    3719                 : "  was not collected due to missing call to suspect, failure to unlink (see\n"
    3720                 : "  other warnings), or deficiency in traverse that causes cycles referenced\n"
    3721                 : "  only from other cycles to require multiple rounds of cycle collection\n",
    3722                 :                                        pi->mName, pi->mPointer, pi->mSCCIndex);
    3723                 :                             }
    3724                 :                             if (pi->mShortestPathToExpectedGarbage)
    3725                 :                                 PrintPathToExpectedGarbage(pi);
    3726                 :                         }
    3727                 :                     }
    3728                 :                 }
    3729                 :             }
    3730                 : 
    3731                 :             DestroyReversedEdges();
    3732                 :         }
    3733                 :     }
    3734                 : 
    3735                 :     ClearGraph();
    3736                 : 
    3737                 :     mCollectionInProgress = false;
    3738                 : 
    3739                 :     for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) {
    3740                 :         if (mRuntimes[i])
    3741                 :             mRuntimes[i]->FinishCycleCollection();
    3742                 :     }    
    3743                 : }
    3744                 : 
    3745                 : bool
    3746                 : nsCycleCollector::CreateReversedEdges()
    3747                 : {
    3748                 :     // Count the edges in the graph.
    3749                 :     PRUint32 edgeCount = 0;
    3750                 :     NodePool::Enumerator countQueue(mGraph.mNodes);
    3751                 :     while (!countQueue.IsDone()) {
    3752                 :         PtrInfo *pi = countQueue.GetNext();
    3753                 :         for (EdgePool::Iterator e = pi->FirstChild(), e_end = pi->LastChild();
    3754                 :              e != e_end; ++e, ++edgeCount) {
    3755                 :         }
    3756                 :     }
    3757                 : 
    3758                 :     // Allocate a pool to hold all of the edges.
    3759                 :     mGraph.mReversedEdges = new ReversedEdge[edgeCount];
    3760                 :     if (mGraph.mReversedEdges == nsnull) {
    3761                 :         NS_NOTREACHED("allocation failure creating reversed edges");
    3762                 :         return false;
    3763                 :     }
    3764                 : 
    3765                 :     // Fill in the reversed edges by scanning all forward edges.
    3766                 :     ReversedEdge *current = mGraph.mReversedEdges;
    3767                 :     NodePool::Enumerator buildQueue(mGraph.mNodes);
    3768                 :     while (!buildQueue.IsDone()) {
    3769                 :         PtrInfo *pi = buildQueue.GetNext();
    3770                 :         PRInt32 i = 0;
    3771                 :         for (EdgePool::Iterator e = pi->FirstChild(), e_end = pi->LastChild();
    3772                 :              e != e_end; ++e) {
    3773                 :             current->mTarget = pi;
    3774                 :             current->mEdgeName = &pi->mEdgeNames[i];
    3775                 :             current->mNext = (*e)->mReversedEdges;
    3776                 :             (*e)->mReversedEdges = current;
    3777                 :             ++current;
    3778                 :             ++i;
    3779                 :         }
    3780                 :     }
    3781                 :     NS_ASSERTION(current - mGraph.mReversedEdges == ptrdiff_t(edgeCount),
    3782                 :                  "misallocation");
    3783                 :     return true;
    3784                 : }
    3785                 : 
    3786                 : void
    3787                 : nsCycleCollector::DestroyReversedEdges()
    3788                 : {
    3789                 :     NodePool::Enumerator queue(mGraph.mNodes);
    3790                 :     while (!queue.IsDone()) {
    3791                 :         PtrInfo *pi = queue.GetNext();
    3792                 :         pi->mReversedEdges = nsnull;
    3793                 :     }
    3794                 : 
    3795                 :     delete mGraph.mReversedEdges;
    3796                 :     mGraph.mReversedEdges = nsnull;
    3797                 : }
    3798                 : 
    3799                 : void
    3800                 : nsCycleCollector::ShouldBeFreed(nsISupports *n)
    3801                 : {
    3802                 :     if (n) {
    3803                 :         mExpectedGarbage.PutEntry(n);
    3804                 :     }
    3805                 : }
    3806                 : 
    3807                 : void
    3808                 : nsCycleCollector::WasFreed(nsISupports *n)
    3809                 : {
    3810                 :     if (n) {
    3811                 :         mExpectedGarbage.RemoveEntry(n);
    3812                 :     }
    3813                 : }
    3814                 : #endif
    3815                 : 
    3816                 : 
    3817                 : ////////////////////////
    3818                 : // Memory reporter
    3819                 : ////////////////////////
    3820                 : 
    3821                 : static PRInt64
    3822               0 : ReportCycleCollectorMem()
    3823                 : {
    3824               0 :     if (!sCollector)
    3825               0 :         return 0;
    3826                 :     PRInt64 size = sizeof(nsCycleCollector) + 
    3827               0 :         sCollector->mPurpleBuf.BlocksSize() +
    3828               0 :         sCollector->mGraph.BlocksSize();
    3829               0 :     if (sCollector->mWhiteNodes)
    3830               0 :         size += sCollector->mWhiteNodes->Capacity() * sizeof(PtrInfo*);
    3831               0 :     return size;
    3832                 : }
    3833                 : 
    3834            1413 : NS_MEMORY_REPORTER_IMPLEMENT(CycleCollector,
    3835                 :                              "explicit/cycle-collector",
    3836                 :                              KIND_HEAP,
    3837                 :                              UNITS_BYTES,
    3838                 :                              ReportCycleCollectorMem,
    3839                 :                              "Memory used by the cycle collector.  This "
    3840                 :                              "includes the cycle collector structure, the "
    3841                 :                              "purple buffer, the graph, and the white nodes.  "
    3842                 :                              "The latter two are expected to be empty when the "
    3843            4278 :                              "cycle collector is idle.")
    3844                 : 
    3845                 : 
    3846                 : ////////////////////////////////////////////////////////////////////////
    3847                 : // Module public API (exported in nsCycleCollector.h)
    3848                 : // Just functions that redirect into the singleton, once it's built.
    3849                 : ////////////////////////////////////////////////////////////////////////
    3850                 : 
    3851                 : void 
    3852            1404 : nsCycleCollector_registerRuntime(PRUint32 langID, 
    3853                 :                                  nsCycleCollectionLanguageRuntime *rt)
    3854                 : {
    3855                 :     static bool regMemReport = true;
    3856            1404 :     if (sCollector)
    3857            1404 :         sCollector->RegisterRuntime(langID, rt);
    3858            1404 :     if (regMemReport) {
    3859            1404 :         regMemReport = false;
    3860            1404 :         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(CycleCollector));
    3861                 :     }
    3862            1404 : }
    3863                 : 
    3864                 : nsCycleCollectionLanguageRuntime *
    3865               0 : nsCycleCollector_getRuntime(PRUint32 langID)
    3866                 : {
    3867               0 :     if (sCollector)
    3868               0 :         sCollector->GetRuntime(langID);
    3869               0 :     return nsnull;
    3870                 : }
    3871                 : 
    3872                 : void 
    3873            1403 : nsCycleCollector_forgetRuntime(PRUint32 langID)
    3874                 : {
    3875            1403 :     if (sCollector)
    3876               0 :         sCollector->ForgetRuntime(langID);
    3877            1403 : }
    3878                 : 
    3879                 : 
    3880                 : bool
    3881               0 : NS_CycleCollectorSuspect(nsISupports *n)
    3882                 : {
    3883               0 :     if (sCollector)
    3884               0 :         return sCollector->Suspect(n);
    3885               0 :     return false;
    3886                 : }
    3887                 : 
    3888                 : bool
    3889               0 : NS_CycleCollectorForget(nsISupports *n)
    3890                 : {
    3891               0 :     return sCollector ? sCollector->Forget(n) : true;
    3892                 : }
    3893                 : 
    3894                 : nsPurpleBufferEntry*
    3895         1489498 : NS_CycleCollectorSuspect2(nsISupports *n)
    3896                 : {
    3897         1489498 :     if (sCollector)
    3898         1489498 :         return sCollector->Suspect2(n);
    3899               0 :     return nsnull;
    3900                 : }
    3901                 : 
    3902                 : bool
    3903         1350470 : NS_CycleCollectorForget2(nsPurpleBufferEntry *e)
    3904                 : {
    3905         1350470 :     return sCollector ? sCollector->Forget2(e) : true;
    3906                 : }
    3907                 : 
    3908                 : PRUint32
    3909           23251 : nsCycleCollector_suspectedCount()
    3910                 : {
    3911           23251 :     return sCollector ? sCollector->SuspectedCount() : 0;
    3912                 : }
    3913                 : 
    3914                 : #ifdef DEBUG
    3915                 : void
    3916               0 : nsCycleCollector_DEBUG_shouldBeFreed(nsISupports *n)
    3917                 : {
    3918                 : #ifdef DEBUG_CC
    3919                 :     if (sCollector)
    3920                 :         sCollector->ShouldBeFreed(n);
    3921                 : #endif
    3922               0 : }
    3923                 : 
    3924                 : void
    3925            1271 : nsCycleCollector_DEBUG_wasFreed(nsISupports *n)
    3926                 : {
    3927                 : #ifdef DEBUG_CC
    3928                 :     if (sCollector)
    3929                 :         sCollector->WasFreed(n);
    3930                 : #endif
    3931            1271 : }
    3932                 : #endif
    3933                 : 
    3934                 : class nsCycleCollectorRunner : public nsRunnable
    3935            5676 : {
    3936                 :     nsCycleCollector *mCollector;
    3937                 :     nsICycleCollectorListener *mListener;
    3938                 :     Mutex mLock;
    3939                 :     CondVar mRequest;
    3940                 :     CondVar mReply;
    3941                 :     bool mRunning;
    3942                 :     bool mShutdown;
    3943                 :     bool mCollected;
    3944                 : 
    3945              57 :     nsCycleCollectionJSRuntime *GetJSRuntime()
    3946                 :     {
    3947                 :         return static_cast<nsCycleCollectionJSRuntime*>
    3948              57 :                  (mCollector->mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]);
    3949                 :     }
    3950                 : 
    3951                 : public:
    3952            1419 :     NS_IMETHOD Run()
    3953                 :     {
    3954                 : #ifdef XP_WIN
    3955                 :         TlsSetValue(gTLSThreadIDIndex,
    3956                 :                     (void*) mozilla::threads::CycleCollector);
    3957                 : #elif defined(NS_TLS)
    3958            1419 :         gTLSThreadID = mozilla::threads::CycleCollector;
    3959                 : #else
    3960                 :         gCycleCollectorThread = PR_GetCurrentThread();
    3961                 : #endif
    3962                 : 
    3963            1419 :         NS_ASSERTION(NS_IsCycleCollectorThread() && !NS_IsMainThread(),
    3964                 :                      "Wrong thread!");
    3965                 : 
    3966            2838 :         MutexAutoLock autoLock(mLock);
    3967                 : 
    3968            1419 :         if (mShutdown)
    3969               0 :             return NS_OK;
    3970                 : 
    3971            1419 :         mRunning = true;
    3972                 : 
    3973               3 :         while (1) {
    3974            1422 :             mRequest.Wait();
    3975                 : 
    3976            1422 :             if (!mRunning) {
    3977            1419 :                 mReply.Notify();
    3978            1419 :                 return NS_OK;
    3979                 :             }
    3980                 : 
    3981               3 :             GetJSRuntime()->NotifyEnterCycleCollectionThread();
    3982               3 :             mCollected = mCollector->BeginCollection(mListener);
    3983               3 :             GetJSRuntime()->NotifyLeaveCycleCollectionThread();
    3984                 : 
    3985               3 :             mReply.Notify();
    3986                 :         }
    3987                 : 
    3988                 :         return NS_OK;
    3989                 :     }
    3990                 : 
    3991            1419 :     nsCycleCollectorRunner(nsCycleCollector *collector)
    3992                 :         : mCollector(collector),
    3993                 :           mListener(nsnull),
    3994                 :           mLock("cycle collector lock"),
    3995                 :           mRequest(mLock, "cycle collector request condvar"),
    3996                 :           mReply(mLock, "cycle collector reply condvar"),
    3997                 :           mRunning(false),
    3998                 :           mShutdown(false),
    3999            1419 :           mCollected(false)
    4000                 :     {
    4001            1419 :         NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    4002            1419 :     }
    4003                 : 
    4004              48 :     void Collect(nsCycleCollectorResults *aResults,
    4005                 :                  nsICycleCollectorListener *aListener)
    4006                 :     {
    4007              48 :         NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    4008                 : 
    4009                 :         // On a WantAllTraces CC, force a synchronous global GC to prevent
    4010                 :         // hijinks from ForgetSkippable and compartmental GCs.
    4011              48 :         bool wantAllTraces = false;
    4012              48 :         if (aListener) {
    4013               0 :             aListener->GetWantAllTraces(&wantAllTraces);
    4014                 :         }
    4015              48 :         mCollector->GCIfNeeded(wantAllTraces);
    4016                 : 
    4017              96 :         MutexAutoLock autoLock(mLock);
    4018                 : 
    4019              48 :         if (!mRunning)
    4020                 :             return;
    4021                 : 
    4022              96 :         nsAutoTArray<PtrInfo*, 4000> whiteNodes;
    4023              48 :         if (!mCollector->PrepareForCollection(aResults, &whiteNodes))
    4024                 :             return;
    4025                 : 
    4026              48 :         NS_ASSERTION(!mListener, "Should have cleared this already!");
    4027              48 :         if (aListener && NS_FAILED(aListener->Begin()))
    4028               0 :             aListener = nsnull;
    4029              48 :         mListener = aListener;
    4030                 : 
    4031              48 :         if (GetJSRuntime()->NotifyLeaveMainThread()) {
    4032               3 :             mRequest.Notify();
    4033               3 :             mReply.Wait();
    4034               3 :             GetJSRuntime()->NotifyEnterMainThread();
    4035                 :         } else {
    4036              45 :             mCollected = mCollector->BeginCollection(mListener);
    4037                 :         }
    4038                 : 
    4039              48 :         mListener = nsnull;
    4040                 : 
    4041              48 :         if (mCollected) {
    4042              48 :             mCollector->FinishCollection(aListener);
    4043              48 :             mCollector->CleanupAfterCollection();
    4044                 :         }
    4045                 :     }
    4046                 : 
    4047            1419 :     void Shutdown()
    4048                 :     {
    4049            1419 :         NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    4050                 : 
    4051            2838 :         MutexAutoLock autoLock(mLock);
    4052                 : 
    4053            1419 :         mShutdown = true;
    4054                 : 
    4055            1419 :         if (!mRunning)
    4056                 :             return;
    4057                 : 
    4058            1419 :         mRunning = false;
    4059            1419 :         mRequest.Notify();
    4060            1419 :         mReply.Wait();
    4061                 :     }
    4062                 : };
    4063                 : 
    4064                 : // Holds a reference.
    4065                 : static nsCycleCollectorRunner* sCollectorRunner;
    4066                 : 
    4067                 : // Holds a reference.
    4068                 : static nsIThread* sCollectorThread;
    4069                 : 
    4070                 : nsresult
    4071            1419 : nsCycleCollector_startup()
    4072                 : {
    4073            1419 :     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    4074            1419 :     NS_ASSERTION(!sCollector, "Forgot to call nsCycleCollector_shutdown?");
    4075                 : 
    4076            1419 :     sCollector = new nsCycleCollector();
    4077                 : 
    4078                 :     nsRefPtr<nsCycleCollectorRunner> runner =
    4079            2838 :         new nsCycleCollectorRunner(sCollector);
    4080                 : 
    4081            2838 :     nsCOMPtr<nsIThread> thread;
    4082            1419 :     nsresult rv = NS_NewThread(getter_AddRefs(thread), runner);
    4083            1419 :     NS_ENSURE_SUCCESS(rv, rv);
    4084                 : 
    4085            1419 :     runner.swap(sCollectorRunner);
    4086            1419 :     thread.swap(sCollectorThread);
    4087                 : 
    4088            1419 :     return rv;
    4089                 : }
    4090                 : 
    4091                 : void
    4092            1404 : nsCycleCollector_setBeforeUnlinkCallback(CC_BeforeUnlinkCallback aCB)
    4093                 : {
    4094            1404 :     if (sCollector) {
    4095            1404 :         sCollector->mBeforeUnlinkCB = aCB;
    4096                 :     }
    4097            1404 : }
    4098                 : 
    4099                 : void
    4100            1404 : nsCycleCollector_setForgetSkippableCallback(CC_ForgetSkippableCallback aCB)
    4101                 : {
    4102            1404 :     if (sCollector) {
    4103            1404 :         sCollector->mForgetSkippableCB = aCB;
    4104                 :     }
    4105            1404 : }
    4106                 : 
    4107                 : void
    4108             276 : nsCycleCollector_forgetSkippable(bool aRemoveChildlessNodes)
    4109                 : {
    4110             276 :     if (sCollector) {
    4111             552 :         SAMPLE_LABEL("CC", "nsCycleCollector_forgetSkippable");
    4112             276 :         TimeLog timeLog;
    4113             276 :         sCollector->ForgetSkippable(aRemoveChildlessNodes);
    4114             276 :         timeLog.Checkpoint("ForgetSkippable()");
    4115                 :     }
    4116             276 : }
    4117                 : 
    4118                 : void
    4119              48 : nsCycleCollector_collect(nsCycleCollectorResults *aResults,
    4120                 :                          nsICycleCollectorListener *aListener)
    4121                 : {
    4122              48 :     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    4123              96 :     SAMPLE_LABEL("CC", "nsCycleCollector_collect");
    4124              96 :     nsCOMPtr<nsICycleCollectorListener> listener(aListener);
    4125              48 :     if (!aListener && sCollector && sCollector->mParams.mLogGraphs) {
    4126               0 :         listener = new nsCycleCollectorLogger();
    4127                 :     }
    4128                 : 
    4129              48 :     if (sCollectorRunner) {
    4130              48 :         sCollectorRunner->Collect(aResults, listener);
    4131               0 :     } else if (sCollector) {
    4132               0 :         sCollector->Collect(aResults, 1, listener);
    4133                 :     }
    4134              48 : }
    4135                 : 
    4136                 : void
    4137            1419 : nsCycleCollector_shutdownThreads()
    4138                 : {
    4139            1419 :     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    4140            1419 :     if (sCollectorRunner) {
    4141            2838 :         nsRefPtr<nsCycleCollectorRunner> runner;
    4142            1419 :         runner.swap(sCollectorRunner);
    4143            1419 :         runner->Shutdown();
    4144                 :     }
    4145                 : 
    4146            1419 :     if (sCollectorThread) {
    4147            2838 :         nsCOMPtr<nsIThread> thread;
    4148            1419 :         thread.swap(sCollectorThread);
    4149            1419 :         thread->Shutdown();
    4150                 :     }
    4151            1419 : }
    4152                 : 
    4153                 : void
    4154            1419 : nsCycleCollector_shutdown()
    4155                 : {
    4156            1419 :     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    4157            1419 :     NS_ASSERTION(!sCollectorRunner, "Should have finished before!");
    4158            1419 :     NS_ASSERTION(!sCollectorThread, "Should have finished before!");
    4159                 : 
    4160            1419 :     if (sCollector) {
    4161            2838 :         SAMPLE_LABEL("CC", "nsCycleCollector_shutdown");
    4162            1419 :         sCollector->Shutdown();
    4163            1419 :         delete sCollector;
    4164            1419 :         sCollector = nsnull;
    4165                 :     }
    4166            1419 : }

Generated by: LCOV version 1.7