LCOV - code coverage report
Current view: directory - js/xpconnect/src - XPCJSRuntime.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 804 638 79.4 %
Date: 2012-06-02 Functions: 131 105 80.2 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       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 Communicator client code, released
      17                 :  * March 31, 1998.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   John Bandhauer <jband@netscape.com> (original author)
      26                 :  *   Nicholas Nethercote <nnethercote@mozilla.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : /* Per JSRuntime object */
      43                 : 
      44                 : #include "mozilla/Util.h"
      45                 : 
      46                 : #include "xpcprivate.h"
      47                 : #include "xpcpublic.h"
      48                 : #include "WrapperFactory.h"
      49                 : #include "dom_quickstubs.h"
      50                 : 
      51                 : #include "nsIMemoryReporter.h"
      52                 : #include "nsPrintfCString.h"
      53                 : #include "mozilla/FunctionTimer.h"
      54                 : #include "prsystem.h"
      55                 : #include "mozilla/Preferences.h"
      56                 : #include "mozilla/Telemetry.h"
      57                 : 
      58                 : #include "nsContentUtils.h"
      59                 : #include "nsCCUncollectableMarker.h"
      60                 : #include "jsfriendapi.h"
      61                 : #include "js/MemoryMetrics.h"
      62                 : 
      63                 : #include "nsJSPrincipals.h"
      64                 : 
      65                 : #ifdef MOZ_CRASHREPORTER
      66                 : #include "nsExceptionHandler.h"
      67                 : #endif
      68                 : 
      69                 : using namespace mozilla;
      70                 : using namespace mozilla::xpconnect::memory;
      71                 : 
      72                 : /***************************************************************************/
      73                 : 
      74                 : const char* XPCJSRuntime::mStrings[] = {
      75                 :     "constructor",          // IDX_CONSTRUCTOR
      76                 :     "toString",             // IDX_TO_STRING
      77                 :     "toSource",             // IDX_TO_SOURCE
      78                 :     "lastResult",           // IDX_LAST_RESULT
      79                 :     "returnCode",           // IDX_RETURN_CODE
      80                 :     "value",                // IDX_VALUE
      81                 :     "QueryInterface",       // IDX_QUERY_INTERFACE
      82                 :     "Components",           // IDX_COMPONENTS
      83                 :     "wrappedJSObject",      // IDX_WRAPPED_JSOBJECT
      84                 :     "Object",               // IDX_OBJECT
      85                 :     "Function",             // IDX_FUNCTION
      86                 :     "prototype",            // IDX_PROTOTYPE
      87                 :     "createInstance",       // IDX_CREATE_INSTANCE
      88                 :     "item",                 // IDX_ITEM
      89                 :     "__proto__",            // IDX_PROTO
      90                 :     "__iterator__",         // IDX_ITERATOR
      91                 :     "__exposedProps__",     // IDX_EXPOSEDPROPS
      92                 :     "__scriptOnly__",       // IDX_SCRIPTONLY
      93                 :     "baseURIObject",        // IDX_BASEURIOBJECT
      94                 :     "nodePrincipal",        // IDX_NODEPRINCIPAL
      95                 :     "documentURIObject"     // IDX_DOCUMENTURIOBJECT
      96                 : };
      97                 : 
      98                 : /***************************************************************************/
      99                 : 
     100                 : static JSDHashOperator
     101          198117 : WrappedJSDyingJSObjectFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
     102                 :                              uint32_t number, void *arg)
     103                 : {
     104          198117 :     nsTArray<nsXPCWrappedJS*>* array = static_cast<nsTArray<nsXPCWrappedJS*>*>(arg);
     105          198117 :     nsXPCWrappedJS* wrapper = ((JSObject2WrappedJSMap::Entry*)hdr)->value;
     106          198117 :     NS_ASSERTION(wrapper, "found a null JS wrapper!");
     107                 : 
     108                 :     // walk the wrapper chain and find any whose JSObject is to be finalized
     109          613385 :     while (wrapper) {
     110          217151 :         if (wrapper->IsSubjectToFinalization()) {
     111           65038 :             if (JS_IsAboutToBeFinalized(wrapper->GetJSObjectPreserveColor()))
     112            5503 :                 array->AppendElement(wrapper);
     113                 :         }
     114          217151 :         wrapper = wrapper->GetNextWrapper();
     115                 :     }
     116          198117 :     return JS_DHASH_NEXT;
     117                 : }
     118                 : 
     119                 : struct CX_AND_XPCRT_Data
     120                 : {
     121                 :     JSContext* cx;
     122                 :     XPCJSRuntime* rt;
     123                 : };
     124                 : 
     125                 : static JSDHashOperator
     126          403369 : NativeInterfaceSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
     127                 :                        uint32_t number, void *arg)
     128                 : {
     129          403369 :     XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
     130          403369 :     if (iface->IsMarked()) {
     131          275830 :         iface->Unmark();
     132          275830 :         return JS_DHASH_NEXT;
     133                 :     }
     134                 : 
     135                 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
     136                 :     fputs("- Destroying XPCNativeInterface for ", stdout);
     137                 :     JS_PutString(JSVAL_TO_STRING(iface->GetName()), stdout);
     138                 :     putc('\n', stdout);
     139                 : #endif
     140                 : 
     141          127539 :     XPCNativeInterface::DestroyInstance(iface);
     142          127539 :     return JS_DHASH_REMOVE;
     143                 : }
     144                 : 
     145                 : // *Some* NativeSets are referenced from mClassInfo2NativeSetMap.
     146                 : // *All* NativeSets are referenced from mNativeSetMap.
     147                 : // So, in mClassInfo2NativeSetMap we just clear references to the unmarked.
     148                 : // In mNativeSetMap we clear the references to the unmarked *and* delete them.
     149                 : 
     150                 : static JSDHashOperator
     151          716870 : NativeUnMarkedSetRemover(JSDHashTable *table, JSDHashEntryHdr *hdr,
     152                 :                          uint32_t number, void *arg)
     153                 : {
     154          716870 :     XPCNativeSet* set = ((ClassInfo2NativeSetMap::Entry*)hdr)->value;
     155          716870 :     if (set->IsMarked())
     156          680511 :         return JS_DHASH_NEXT;
     157           36359 :     return JS_DHASH_REMOVE;
     158                 : }
     159                 : 
     160                 : static JSDHashOperator
     161          337018 : NativeSetSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
     162                 :                  uint32_t number, void *arg)
     163                 : {
     164          337018 :     XPCNativeSet* set = ((NativeSetMap::Entry*)hdr)->key_value;
     165          337018 :     if (set->IsMarked()) {
     166          221767 :         set->Unmark();
     167          221767 :         return JS_DHASH_NEXT;
     168                 :     }
     169                 : 
     170                 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
     171                 :     printf("- Destroying XPCNativeSet for:\n");
     172                 :     PRUint16 count = set->GetInterfaceCount();
     173                 :     for (PRUint16 k = 0; k < count; k++) {
     174                 :         XPCNativeInterface* iface = set->GetInterfaceAt(k);
     175                 :         fputs("    ", stdout);
     176                 :         JS_PutString(JSVAL_TO_STRING(iface->GetName()), stdout);
     177                 :         putc('\n', stdout);
     178                 :     }
     179                 : #endif
     180                 : 
     181          115251 :     XPCNativeSet::DestroyInstance(set);
     182          115251 :     return JS_DHASH_REMOVE;
     183                 : }
     184                 : 
     185                 : static JSDHashOperator
     186          122164 : JSClassSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
     187                 :                uint32_t number, void *arg)
     188                 : {
     189                 :     XPCNativeScriptableShared* shared =
     190          122164 :         ((XPCNativeScriptableSharedMap::Entry*) hdr)->key;
     191          122164 :     if (shared->IsMarked()) {
     192                 : #ifdef off_XPC_REPORT_JSCLASS_FLUSHING
     193                 :         printf("+ Marked XPCNativeScriptableShared for: %s @ %x\n",
     194                 :                shared->GetJSClass()->name,
     195                 :                shared->GetJSClass());
     196                 : #endif
     197          101050 :         shared->Unmark();
     198          101050 :         return JS_DHASH_NEXT;
     199                 :     }
     200                 : 
     201                 : #ifdef XPC_REPORT_JSCLASS_FLUSHING
     202                 :     printf("- Destroying XPCNativeScriptableShared for: %s @ %x\n",
     203                 :            shared->GetJSClass()->name,
     204                 :            shared->GetJSClass());
     205                 : #endif
     206                 : 
     207           21114 :     delete shared;
     208           21114 :     return JS_DHASH_REMOVE;
     209                 : }
     210                 : 
     211                 : static JSDHashOperator
     212          186781 : DyingProtoKiller(JSDHashTable *table, JSDHashEntryHdr *hdr,
     213                 :                  uint32_t number, void *arg)
     214                 : {
     215                 :     XPCWrappedNativeProto* proto =
     216          186781 :         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
     217          186781 :     delete proto;
     218          186781 :     return JS_DHASH_REMOVE;
     219                 : }
     220                 : 
     221                 : static JSDHashOperator
     222               0 : DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
     223                 :                                  uint32_t number, void *arg)
     224                 : {
     225                 :     XPCWrappedNativeProto* proto =
     226               0 :         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
     227                 : 
     228               0 :     proto->Mark();
     229               0 :     return JS_DHASH_NEXT;
     230                 : }
     231                 : 
     232                 : // GCCallback calls are chained
     233                 : static JSBool
     234           15428 : ContextCallback(JSContext *cx, unsigned operation)
     235                 : {
     236           15428 :     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     237           15428 :     if (self) {
     238           15428 :         if (operation == JSCONTEXT_NEW) {
     239            7715 :             if (!self->OnJSContextNew(cx))
     240               0 :                 return false;
     241            7713 :         } else if (operation == JSCONTEXT_DESTROY) {
     242            7713 :             delete XPCContext::GetXPCContext(cx);
     243                 :         }
     244                 :     }
     245           15428 :     return true;
     246                 : }
     247                 : 
     248            6734 : xpc::CompartmentPrivate::~CompartmentPrivate()
     249                 : {
     250            3367 :     MOZ_COUNT_DTOR(xpc::CompartmentPrivate);
     251            3367 : }
     252                 : 
     253                 : static JSBool
     254            3647 : CompartmentCallback(JSContext *cx, JSCompartment *compartment, unsigned op)
     255                 : {
     256            3647 :     JS_ASSERT(op == JSCOMPARTMENT_DESTROY);
     257                 : 
     258            3647 :     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     259            3647 :     if (!self)
     260               0 :         return true;
     261                 : 
     262                 :     nsAutoPtr<xpc::CompartmentPrivate>
     263            7294 :         priv(static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment)));
     264            3647 :     if (!priv)
     265             280 :         return true;
     266                 : 
     267            3367 :     JS_SetCompartmentPrivate(compartment, nsnull);
     268                 : 
     269            3367 :     xpc::PtrAndPrincipalHashKey *key = priv->key;
     270            3367 :     XPCCompartmentMap &map = self->GetCompartmentMap();
     271                 : #ifdef DEBUG
     272            3367 :     JSCompartment *current = NULL;
     273            3367 :     NS_ASSERTION(map.Get(key, &current), "no compartment?");
     274            3367 :     NS_ASSERTION(current == compartment, "compartment mismatch");
     275                 : #endif
     276            3367 :     map.Remove(key);
     277                 : 
     278            3367 :     return true;
     279                 : }
     280                 : 
     281                 : struct ObjectHolder : public JSDHashEntryHdr
     282                 : {
     283                 :     void *holder;
     284                 :     nsScriptObjectTracer* tracer;
     285                 : };
     286                 : 
     287                 : nsresult
     288            7458 : XPCJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer)
     289                 : {
     290            7458 :     if (!mJSHolders.ops)
     291               0 :         return NS_ERROR_OUT_OF_MEMORY;
     292                 : 
     293                 :     ObjectHolder *entry =
     294                 :         reinterpret_cast<ObjectHolder*>(JS_DHashTableOperate(&mJSHolders,
     295                 :                                                              aHolder,
     296            7458 :                                                              JS_DHASH_ADD));
     297            7458 :     if (!entry)
     298               0 :         return NS_ERROR_OUT_OF_MEMORY;
     299                 : 
     300            7458 :     entry->holder = aHolder;
     301            7458 :     entry->tracer = aTracer;
     302                 : 
     303            7458 :     return NS_OK;
     304                 : }
     305                 : 
     306                 : nsresult
     307            7456 : XPCJSRuntime::RemoveJSHolder(void* aHolder)
     308                 : {
     309            7456 :     if (!mJSHolders.ops)
     310               0 :         return NS_ERROR_OUT_OF_MEMORY;
     311                 : 
     312            7456 :     JS_DHashTableOperate(&mJSHolders, aHolder, JS_DHASH_REMOVE);
     313                 : 
     314            7456 :     return NS_OK;
     315                 : }
     316                 : 
     317                 : // static
     318           14728 : void XPCJSRuntime::TraceBlackJS(JSTracer* trc, void* data)
     319                 : {
     320           14728 :     XPCJSRuntime* self = (XPCJSRuntime*)data;
     321                 : 
     322                 :     // Skip this part if XPConnect is shutting down. We get into
     323                 :     // bad locking problems with the thread iteration otherwise.
     324           14728 :     if (!self->GetXPConnect()->IsShuttingDown()) {
     325           11922 :         Mutex* threadLock = XPCPerThreadData::GetLock();
     326           11922 :         if (threadLock)
     327                 :         { // scoped lock
     328           23844 :             MutexAutoLock lock(*threadLock);
     329                 : 
     330           11922 :             XPCPerThreadData* iterp = nsnull;
     331                 :             XPCPerThreadData* thread;
     332                 : 
     333           35766 :             while (nsnull != (thread =
     334                 :                               XPCPerThreadData::IterateThreads(&iterp))) {
     335                 :                 // Trace those AutoMarkingPtr lists!
     336           11922 :                 thread->TraceJS(trc);
     337                 :             }
     338                 :         }
     339                 :     }
     340                 : 
     341                 :     {
     342           29456 :         XPCAutoLock lock(self->mMapLock);
     343                 : 
     344                 :         // XPCJSObjectHolders don't participate in cycle collection, so always
     345                 :         // trace them here.
     346                 :         XPCRootSetElem *e;
     347           14728 :         for (e = self->mObjectHolderRoots; e; e = e->GetNextRoot())
     348               0 :             static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
     349                 :     }
     350           14728 : }
     351                 : 
     352                 : // static
     353           14728 : void XPCJSRuntime::TraceGrayJS(JSTracer* trc, void* data)
     354                 : {
     355           14728 :     XPCJSRuntime* self = (XPCJSRuntime*)data;
     356                 : 
     357                 :     // Mark these roots as gray so the CC can walk them later.
     358           14728 :     self->TraceXPConnectRoots(trc);
     359           14728 : }
     360                 : 
     361                 : static void
     362            5847 : TraceJSObject(PRUint32 aLangID, void *aScriptThing, const char *name,
     363                 :               void *aClosure)
     364                 : {
     365            5847 :     if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
     366            5847 :         JS_CALL_TRACER(static_cast<JSTracer*>(aClosure), aScriptThing,
     367                 :                        js_GetGCThingTraceKind(aScriptThing), name);
     368                 :     }
     369            5847 : }
     370                 : 
     371                 : static JSDHashOperator
     372            5220 : TraceJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
     373                 :               void *arg)
     374                 : {
     375            5220 :     ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
     376                 : 
     377            5220 :     entry->tracer->Trace(entry->holder, TraceJSObject, arg);
     378                 : 
     379            5220 :     return JS_DHASH_NEXT;
     380                 : }
     381                 : 
     382                 : struct ClearedGlobalObject : public JSDHashEntryHdr
     383                 : {
     384                 :     JSContext* mContext;
     385                 :     JSObject* mGlobalObject;
     386                 : };
     387                 : 
     388                 : static PLDHashOperator
     389               0 : TraceExpandos(XPCWrappedNative *wn, JSObject *&expando, void *aClosure)
     390                 : {
     391               0 :     if (wn->IsWrapperExpired())
     392               0 :         return PL_DHASH_REMOVE;
     393               0 :     JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando, "expando object");
     394               0 :     return PL_DHASH_NEXT;
     395                 : }
     396                 : 
     397                 : static PLDHashOperator
     398               0 : TraceDOMExpandos(nsPtrHashKey<JSObject> *expando, void *aClosure)
     399                 : {
     400               0 :     JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando->GetKey(),
     401                 :                           "DOM expando object");
     402               0 :     return PL_DHASH_NEXT;
     403                 : }
     404                 : 
     405                 : static PLDHashOperator
     406           27300 : TraceCompartment(xpc::PtrAndPrincipalHashKey *aKey, JSCompartment *compartment, void *aClosure)
     407                 : {
     408                 :     xpc::CompartmentPrivate *priv =
     409           27300 :         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
     410           27300 :     if (priv->expandoMap)
     411               0 :         priv->expandoMap->Enumerate(TraceExpandos, aClosure);
     412           27300 :     if (priv->domExpandoMap)
     413               0 :         priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, aClosure);
     414           27300 :     return PL_DHASH_NEXT;
     415                 : }
     416                 : 
     417           14728 : void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
     418                 : {
     419           14728 :     JSContext *iter = nsnull;
     420           81212 :     while (JSContext *acx = JS_ContextIterator(GetJSRuntime(), &iter)) {
     421           33242 :         JS_ASSERT(js::HasUnrootedGlobal(acx));
     422           33242 :         if (JSObject *global = JS_GetGlobalObject(acx))
     423           26313 :             JS_CALL_OBJECT_TRACER(trc, global, "XPC global object");
     424                 :     }
     425                 : 
     426           29456 :     XPCAutoLock lock(mMapLock);
     427                 : 
     428           14728 :     XPCWrappedNativeScope::TraceJS(trc, this);
     429                 : 
     430           15279 :     for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot())
     431             551 :         static_cast<XPCTraceableVariant*>(e)->TraceJS(trc);
     432                 : 
     433          166841 :     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot())
     434          152113 :         static_cast<nsXPCWrappedJS*>(e)->TraceJS(trc);
     435                 : 
     436           14728 :     if (mJSHolders.ops)
     437           14728 :         JS_DHashTableEnumerate(&mJSHolders, TraceJSHolder, trc);
     438                 : 
     439                 :     // Trace compartments.
     440           14728 :     GetCompartmentMap().EnumerateRead(TraceCompartment, trc);
     441           14728 : }
     442                 : 
     443                 : struct Closure
     444                 : {
     445                 :     bool cycleCollectionEnabled;
     446                 :     nsCycleCollectionTraversalCallback *cb;
     447                 : };
     448                 : 
     449                 : static void
     450             648 : CheckParticipatesInCycleCollection(PRUint32 aLangID, void *aThing,
     451                 :                                    const char *name, void *aClosure)
     452                 : {
     453             648 :     Closure *closure = static_cast<Closure*>(aClosure);
     454                 : 
     455                 :     closure->cycleCollectionEnabled =
     456                 :         aLangID == nsIProgrammingLanguage::JAVASCRIPT &&
     457             648 :         AddToCCKind(js_GetGCThingTraceKind(aThing));
     458             648 : }
     459                 : 
     460                 : static JSDHashOperator
     461             623 : NoteJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
     462                 :              void *arg)
     463                 : {
     464             623 :     ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
     465             623 :     Closure *closure = static_cast<Closure*>(arg);
     466                 : 
     467                 :     entry->tracer->Trace(entry->holder, CheckParticipatesInCycleCollection,
     468             623 :                          closure);
     469             623 :     if (!closure->cycleCollectionEnabled)
     470               1 :         return JS_DHASH_NEXT;
     471                 : 
     472                 :     closure->cb->NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, entry->holder,
     473             622 :                           entry->tracer);
     474                 : 
     475             622 :     return JS_DHASH_NEXT;
     476                 : }
     477                 : 
     478                 : // static
     479                 : void
     480             190 : XPCJSRuntime::SuspectWrappedNative(XPCWrappedNative *wrapper,
     481                 :                                    nsCycleCollectionTraversalCallback &cb)
     482                 : {
     483             190 :     if (!wrapper->IsValid() || wrapper->IsWrapperExpired())
     484               0 :         return;
     485                 : 
     486             190 :     NS_ASSERTION(NS_IsMainThread() || NS_IsCycleCollectorThread(),
     487                 :                  "Suspecting wrapped natives from non-CC thread");
     488                 : 
     489                 :     // Only record objects that might be part of a cycle as roots, unless
     490                 :     // the callback wants all traces (a debug feature).
     491             190 :     JSObject* obj = wrapper->GetFlatJSObjectPreserveColor();
     492             190 :     if (xpc_IsGrayGCThing(obj) || cb.WantAllTraces())
     493                 :         cb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, obj,
     494              56 :                     nsXPConnect::GetXPConnect());
     495                 : }
     496                 : 
     497                 : static PLDHashOperator
     498               0 : SuspectExpandos(XPCWrappedNative *wrapper, JSObject *expando, void *arg)
     499                 : {
     500               0 :     Closure* closure = static_cast<Closure*>(arg);
     501               0 :     XPCJSRuntime::SuspectWrappedNative(wrapper, *closure->cb);
     502                 : 
     503               0 :     return PL_DHASH_NEXT;
     504                 : }
     505                 : 
     506                 : static PLDHashOperator
     507               0 : SuspectDOMExpandos(nsPtrHashKey<JSObject> *expando, void *arg)
     508                 : {
     509               0 :     Closure *closure = static_cast<Closure*>(arg);
     510               0 :     closure->cb->NoteXPCOMRoot(static_cast<nsISupports*>(js::GetObjectPrivate(expando->GetKey())));
     511               0 :     return PL_DHASH_NEXT;
     512                 : }
     513                 : 
     514                 : static PLDHashOperator
     515            3828 : SuspectCompartment(xpc::PtrAndPrincipalHashKey *key, JSCompartment *compartment, void *arg)
     516                 : {
     517                 :     xpc::CompartmentPrivate *priv =
     518            3828 :         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
     519            3828 :     if (priv->expandoMap)
     520               0 :         priv->expandoMap->EnumerateRead(SuspectExpandos, arg);
     521            3828 :     if (priv->domExpandoMap)
     522               0 :         priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, arg);
     523            3828 :     return PL_DHASH_NEXT;
     524                 : }
     525                 : 
     526                 : void
     527            1910 : XPCJSRuntime::AddXPConnectRoots(nsCycleCollectionTraversalCallback &cb)
     528                 : {
     529                 :     // For all JS objects that are held by native objects but aren't held
     530                 :     // through rooting or locking, we need to add all the native objects that
     531                 :     // hold them so that the JS objects are colored correctly in the cycle
     532                 :     // collector. This includes JSContexts that don't have outstanding requests,
     533                 :     // because their global object wasn't marked by the JS GC. All other JS
     534                 :     // roots were marked by the JS GC and will be colored correctly in the cycle
     535                 :     // collector.
     536                 : 
     537            1910 :     JSContext *iter = nsnull, *acx;
     538            9118 :     while ((acx = JS_ContextIterator(GetJSRuntime(), &iter))) {
     539                 :         cb.NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, acx,
     540            5298 :                     nsXPConnect::JSContextParticipant());
     541                 :     }
     542                 : 
     543            3820 :     XPCAutoLock lock(mMapLock);
     544                 : 
     545            1910 :     XPCWrappedNativeScope::SuspectAllWrappers(this, cb);
     546                 : 
     547            1910 :     for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot()) {
     548               0 :         XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(e);
     549               0 :         if (nsCCUncollectableMarker::InGeneration(cb,
     550               0 :                                                   v->CCGeneration())) {
     551               0 :            jsval val = v->GetJSValPreserveColor();
     552               0 :            if (val.isObject() && !xpc_IsGrayGCThing(&val.toObject()))
     553               0 :                continue;
     554                 :         }
     555               0 :         cb.NoteXPCOMRoot(v);
     556                 :     }
     557                 : 
     558           10294 :     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) {
     559            8384 :         nsXPCWrappedJS *wrappedJS = static_cast<nsXPCWrappedJS*>(e);
     560            8384 :         JSObject *obj = wrappedJS->GetJSObjectPreserveColor();
     561                 :         // If traversing wrappedJS wouldn't release it, nor
     562                 :         // cause any other objects to be added to the graph, no
     563                 :         // need to add it to the graph at all.
     564           15612 :         if (nsCCUncollectableMarker::sGeneration &&
     565            3782 :             !cb.WantAllTraces() && (!obj || !xpc_IsGrayGCThing(obj)) &&
     566            1192 :             !wrappedJS->IsSubjectToFinalization() &&
     567            1192 :             wrappedJS->GetRootWrapper() == wrappedJS &&
     568            1062 :             !wrappedJS->IsAggregatedToNative()) {
     569            1062 :             continue;
     570                 :         }
     571                 : 
     572            7322 :         cb.NoteXPCOMRoot(static_cast<nsIXPConnectWrappedJS *>(wrappedJS));
     573                 :     }
     574                 : 
     575            1910 :     Closure closure = { true, &cb };
     576            1910 :     if (mJSHolders.ops) {
     577            1910 :         JS_DHashTableEnumerate(&mJSHolders, NoteJSHolder, &closure);
     578                 :     }
     579                 : 
     580                 :     // Suspect wrapped natives with expando objects.
     581            1910 :     GetCompartmentMap().EnumerateRead(SuspectCompartment, &closure);
     582            1910 : }
     583                 : 
     584                 : static JSDHashOperator
     585               0 : UnmarkJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
     586                 :                void *arg)
     587                 : {
     588               0 :     ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
     589               0 :     entry->tracer->CanSkip(entry->holder, true);
     590               0 :     return JS_DHASH_NEXT;
     591                 : }
     592                 : 
     593                 : void
     594               0 : XPCJSRuntime::UnmarkSkippableJSHolders()
     595                 : {
     596               0 :     XPCAutoLock lock(mMapLock);
     597               0 :     if (mJSHolders.ops) {             
     598               0 :         JS_DHashTableEnumerate(&mJSHolders, UnmarkJSHolder, nsnull);
     599                 :     }
     600               0 : }
     601                 : 
     602                 : void
     603               0 : xpc_UnmarkSkippableJSHolders()
     604                 : {
     605               0 :     if (nsXPConnect::GetXPConnect() &&
     606               0 :         nsXPConnect::GetXPConnect()->GetRuntime()) {
     607               0 :         nsXPConnect::GetXPConnect()->GetRuntime()->UnmarkSkippableJSHolders();
     608                 :     }
     609               0 : }
     610                 : 
     611                 : template<class T> static void
     612         2443424 : DoDeferredRelease(nsTArray<T> &array)
     613                 : {
     614         2413968 :     while (1) {
     615         2443424 :         PRUint32 count = array.Length();
     616         2443424 :         if (!count) {
     617           29456 :             array.Compact();
     618                 :             break;
     619                 :         }
     620         2413968 :         T wrapper = array[count-1];
     621         2413968 :         array.RemoveElementAt(count-1);
     622         2413968 :         NS_RELEASE(wrapper);
     623                 :     }
     624           29456 : }
     625                 : 
     626                 : static JSDHashOperator
     627               0 : SweepWaiverWrappers(JSDHashTable *table, JSDHashEntryHdr *hdr,
     628                 :                     uint32_t number, void *arg)
     629                 : {
     630               0 :     JSObject *key = ((JSObject2JSObjectMap::Entry *)hdr)->key;
     631               0 :     JSObject *value = ((JSObject2JSObjectMap::Entry *)hdr)->value;
     632                 : 
     633               0 :     if (JS_IsAboutToBeFinalized(key) || JS_IsAboutToBeFinalized(value))
     634               0 :         return JS_DHASH_REMOVE;
     635               0 :     return JS_DHASH_NEXT;
     636                 : }
     637                 : 
     638                 : static PLDHashOperator
     639               0 : SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg)
     640                 : {
     641               0 :     return JS_IsAboutToBeFinalized(wn->GetFlatJSObjectPreserveColor())
     642                 :            ? PL_DHASH_REMOVE
     643               0 :            : PL_DHASH_NEXT;
     644                 : }
     645                 : 
     646                 : static PLDHashOperator
     647           27300 : SweepCompartment(nsCStringHashKey& aKey, JSCompartment *compartment, void *aClosure)
     648                 : {
     649           27300 :     MOZ_ASSERT(!aClosure);
     650                 :     xpc::CompartmentPrivate *priv =
     651           27300 :         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
     652           27300 :     if (priv->waiverWrapperMap)
     653               0 :         priv->waiverWrapperMap->Enumerate(SweepWaiverWrappers, nsnull);
     654           27300 :     if (priv->expandoMap)
     655               0 :         priv->expandoMap->Enumerate(SweepExpandos, nsnull);
     656           27300 :     return PL_DHASH_NEXT;
     657                 : }
     658                 : 
     659                 : /* static */ void
     660           29456 : XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
     661                 : {
     662           29456 :     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     663           29456 :     if (!self)
     664               0 :         return;
     665                 : 
     666           29456 :     switch (status) {
     667                 :         case JSGC_BEGIN:
     668                 :         {
     669                 :             // We seem to sometime lose the unrooted global flag. Restore it
     670                 :             // here. FIXME: bug 584495.
     671           14728 :             JSContext *iter = nsnull;
     672           81212 :             while (JSContext *acx = JS_ContextIterator(rt, &iter)) {
     673           33242 :                 if (!js::HasUnrootedGlobal(acx))
     674               0 :                     JS_ToggleOptions(acx, JSOPTION_UNROOTED_GLOBAL);
     675                 :             }
     676           14728 :             break;
     677                 :         }
     678                 :         case JSGC_END:
     679                 :         {
     680                 :             // Do any deferred releases of native objects.
     681                 : #ifdef XPC_TRACK_DEFERRED_RELEASES
     682                 :             printf("XPC - Begin deferred Release of %d nsISupports pointers\n",
     683                 :                    self->mNativesToReleaseArray.Length());
     684                 : #endif
     685           14728 :             DoDeferredRelease(self->mNativesToReleaseArray);
     686                 : #ifdef XPC_TRACK_DEFERRED_RELEASES
     687                 :             printf("XPC - End deferred Releases\n");
     688                 : #endif
     689                 : 
     690           14728 :             self->GetXPConnect()->ClearGCBeforeCC();
     691           14728 :             break;
     692                 :         }
     693                 :     }
     694                 : 
     695           58912 :     nsTArray<JSGCCallback> callbacks(self->extraGCCallbacks);
     696           29456 :     for (PRUint32 i = 0; i < callbacks.Length(); ++i)
     697               0 :         callbacks[i](rt, status);
     698                 : }
     699                 : 
     700                 : /* static */ void
     701           29456 : XPCJSRuntime::FinalizeCallback(JSContext *cx, JSFinalizeStatus status)
     702                 : {
     703           29456 :     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     704           29456 :     if (!self)
     705               0 :         return;
     706                 : 
     707           29456 :     switch (status) {
     708                 :         case JSFINALIZE_START:
     709                 :         {
     710           14728 :             NS_ASSERTION(!self->mDoingFinalization, "bad state");
     711                 : 
     712                 :             // mThreadRunningGC indicates that GC is running
     713                 :             { // scoped lock
     714           29456 :                 XPCAutoLock lock(self->GetMapLock());
     715           14728 :                 NS_ASSERTION(!self->mThreadRunningGC, "bad state");
     716           14728 :                 self->mThreadRunningGC = PR_GetCurrentThread();
     717                 :             }
     718                 : 
     719                 :             nsTArray<nsXPCWrappedJS*>* dyingWrappedJSArray =
     720           14728 :                 &self->mWrappedJSToReleaseArray;
     721                 : 
     722                 :             // Add any wrappers whose JSObjects are to be finalized to
     723                 :             // this array. Note that we do not want to be changing the
     724                 :             // refcount of these wrappers.
     725                 :             // We add them to the array now and Release the array members
     726                 :             // later to avoid the posibility of doing any JS GCThing
     727                 :             // allocations during the gc cycle.
     728                 :             self->mWrappedJSMap->
     729           14728 :                 Enumerate(WrappedJSDyingJSObjectFinder, dyingWrappedJSArray);
     730                 : 
     731                 :             // Find dying scopes.
     732           14728 :             XPCWrappedNativeScope::FinishedMarkPhaseOfGC(cx, self);
     733                 : 
     734                 :             // Sweep compartments.
     735           14728 :             self->GetCompartmentMap().EnumerateRead((XPCCompartmentMap::EnumReadFunction)
     736           29456 :                                                     SweepCompartment, nsnull);
     737                 : 
     738           14728 :             self->mDoingFinalization = true;
     739           14728 :             break;
     740                 :         }
     741                 :         case JSFINALIZE_END:
     742                 :         {
     743           14728 :             NS_ASSERTION(self->mDoingFinalization, "bad state");
     744           14728 :             self->mDoingFinalization = false;
     745                 : 
     746                 :             // Release all the members whose JSObjects are now known
     747                 :             // to be dead.
     748           14728 :             DoDeferredRelease(self->mWrappedJSToReleaseArray);
     749                 : 
     750                 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
     751                 :             printf("--------------------------------------------------------------\n");
     752                 :             int setsBefore = (int) self->mNativeSetMap->Count();
     753                 :             int ifacesBefore = (int) self->mIID2NativeInterfaceMap->Count();
     754                 : #endif
     755                 : 
     756                 :             // We use this occasion to mark and sweep NativeInterfaces,
     757                 :             // NativeSets, and the WrappedNativeJSClasses...
     758                 : 
     759                 :             // Do the marking...
     760           14728 :             XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos();
     761                 : 
     762                 :             self->mDetachedWrappedNativeProtoMap->
     763           14728 :                 Enumerate(DetachedWrappedNativeProtoMarker, nsnull);
     764                 : 
     765           14728 :             DOM_MarkInterfaces();
     766                 : 
     767                 :             // Mark the sets used in the call contexts. There is a small
     768                 :             // chance that a wrapper's set will change *while* a call is
     769                 :             // happening which uses that wrapper's old interfface set. So,
     770                 :             // we need to do this marking to avoid collecting those sets
     771                 :             // that might no longer be otherwise reachable from the wrappers
     772                 :             // or the wrapperprotos.
     773                 : 
     774                 :             // Skip this part if XPConnect is shutting down. We get into
     775                 :             // bad locking problems with the thread iteration otherwise.
     776           14728 :             if (!self->GetXPConnect()->IsShuttingDown()) {
     777           11922 :                 Mutex* threadLock = XPCPerThreadData::GetLock();
     778           11922 :                 if (threadLock)
     779                 :                 { // scoped lock
     780           23844 :                     MutexAutoLock lock(*threadLock);
     781                 : 
     782           11922 :                     XPCPerThreadData* iterp = nsnull;
     783                 :                     XPCPerThreadData* thread;
     784                 : 
     785           35766 :                     while (nsnull != (thread =
     786                 :                                       XPCPerThreadData::IterateThreads(&iterp))) {
     787                 :                         // Mark those AutoMarkingPtr lists!
     788           11922 :                         thread->MarkAutoRootsAfterJSFinalize();
     789                 : 
     790           11922 :                         XPCCallContext* ccxp = thread->GetCallContext();
     791           33630 :                         while (ccxp) {
     792                 :                             // Deal with the strictness of callcontext that
     793                 :                             // complains if you ask for a set when
     794                 :                             // it is in a state where the set could not
     795                 :                             // possibly be valid.
     796            9786 :                             if (ccxp->CanGetSet()) {
     797            3887 :                                 XPCNativeSet* set = ccxp->GetSet();
     798            3887 :                                 if (set)
     799            3887 :                                     set->Mark();
     800                 :                             }
     801            9786 :                             if (ccxp->CanGetInterface()) {
     802            3887 :                                 XPCNativeInterface* iface = ccxp->GetInterface();
     803            3887 :                                 if (iface)
     804            3887 :                                     iface->Mark();
     805                 :                             }
     806            9786 :                             ccxp = ccxp->GetPrevCallContext();
     807                 :                         }
     808                 :                     }
     809                 :                 }
     810                 :             }
     811                 : 
     812                 :             // Do the sweeping...
     813                 : 
     814                 :             // We don't want to sweep the JSClasses at shutdown time.
     815                 :             // At this point there may be JSObjects using them that have
     816                 :             // been removed from the other maps.
     817           14728 :             if (!self->GetXPConnect()->IsShuttingDown()) {
     818                 :                 self->mNativeScriptableSharedMap->
     819           11922 :                     Enumerate(JSClassSweeper, nsnull);
     820                 :             }
     821                 : 
     822                 :             self->mClassInfo2NativeSetMap->
     823           14728 :                 Enumerate(NativeUnMarkedSetRemover, nsnull);
     824                 : 
     825                 :             self->mNativeSetMap->
     826           14728 :                 Enumerate(NativeSetSweeper, nsnull);
     827                 : 
     828                 :             self->mIID2NativeInterfaceMap->
     829           14728 :                 Enumerate(NativeInterfaceSweeper, nsnull);
     830                 : 
     831                 : #ifdef DEBUG
     832           14728 :             XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked();
     833                 : #endif
     834                 : 
     835                 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
     836                 :             int setsAfter = (int) self->mNativeSetMap->Count();
     837                 :             int ifacesAfter = (int) self->mIID2NativeInterfaceMap->Count();
     838                 : 
     839                 :             printf("\n");
     840                 :             printf("XPCNativeSets:        before: %d  collected: %d  remaining: %d\n",
     841                 :                    setsBefore, setsBefore - setsAfter, setsAfter);
     842                 :             printf("XPCNativeInterfaces:  before: %d  collected: %d  remaining: %d\n",
     843                 :                    ifacesBefore, ifacesBefore - ifacesAfter, ifacesAfter);
     844                 :             printf("--------------------------------------------------------------\n");
     845                 : #endif
     846                 : 
     847                 :             // Sweep scopes needing cleanup
     848           14728 :             XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC(cx);
     849                 : 
     850                 :             // Now we are going to recycle any unused WrappedNativeTearoffs.
     851                 :             // We do this by iterating all the live callcontexts (on all
     852                 :             // threads!) and marking the tearoffs in use. And then we
     853                 :             // iterate over all the WrappedNative wrappers and sweep their
     854                 :             // tearoffs.
     855                 :             //
     856                 :             // This allows us to perhaps minimize the growth of the
     857                 :             // tearoffs. And also makes us not hold references to interfaces
     858                 :             // on our wrapped natives that we are not actually using.
     859                 :             //
     860                 :             // XXX We may decide to not do this on *every* gc cycle.
     861                 : 
     862                 :             // Skip this part if XPConnect is shutting down. We get into
     863                 :             // bad locking problems with the thread iteration otherwise.
     864           14728 :             if (!self->GetXPConnect()->IsShuttingDown()) {
     865           11922 :                 Mutex* threadLock = XPCPerThreadData::GetLock();
     866           11922 :                 if (threadLock) {
     867                 :                     // Do the marking...
     868                 : 
     869                 :                     { // scoped lock
     870           23844 :                         MutexAutoLock lock(*threadLock);
     871                 : 
     872           11922 :                         XPCPerThreadData* iterp = nsnull;
     873                 :                         XPCPerThreadData* thread;
     874                 : 
     875           35766 :                         while (nsnull != (thread =
     876                 :                                           XPCPerThreadData::IterateThreads(&iterp))) {
     877           11922 :                             XPCCallContext* ccxp = thread->GetCallContext();
     878           33630 :                             while (ccxp) {
     879                 :                                 // Deal with the strictness of callcontext that
     880                 :                                 // complains if you ask for a tearoff when
     881                 :                                 // it is in a state where the tearoff could not
     882                 :                                 // possibly be valid.
     883            9786 :                                 if (ccxp->CanGetTearOff()) {
     884                 :                                     XPCWrappedNativeTearOff* to =
     885            3975 :                                         ccxp->GetTearOff();
     886            3975 :                                     if (to)
     887            3877 :                                         to->Mark();
     888                 :                                 }
     889            9786 :                                 ccxp = ccxp->GetPrevCallContext();
     890                 :                             }
     891                 :                         }
     892                 :                     }
     893                 : 
     894                 :                     // Do the sweeping...
     895           11922 :                     XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs();
     896                 :                 }
     897                 :             }
     898                 : 
     899                 :             // Now we need to kill the 'Dying' XPCWrappedNativeProtos.
     900                 :             // We transfered these native objects to this table when their
     901                 :             // JSObject's were finalized. We did not destroy them immediately
     902                 :             // at that point because the ordering of JS finalization is not
     903                 :             // deterministic and we did not yet know if any wrappers that
     904                 :             // might still be referencing the protos where still yet to be
     905                 :             // finalized and destroyed. We *do* know that the protos'
     906                 :             // JSObjects would not have been finalized if there were any
     907                 :             // wrappers that referenced the proto but where not themselves
     908                 :             // slated for finalization in this gc cycle. So... at this point
     909                 :             // we know that any and all wrappers that might have been
     910                 :             // referencing the protos in the dying list are themselves dead.
     911                 :             // So, we can safely delete all the protos in the list.
     912                 : 
     913                 :             self->mDyingWrappedNativeProtoMap->
     914           14728 :                 Enumerate(DyingProtoKiller, nsnull);
     915                 : 
     916                 : 
     917                 :             // mThreadRunningGC indicates that GC is running.
     918                 :             // Clear it and notify waiters.
     919                 :             { // scoped lock
     920           29456 :                 XPCAutoLock lock(self->GetMapLock());
     921           14728 :                 NS_ASSERTION(self->mThreadRunningGC == PR_GetCurrentThread(), "bad state");
     922           14728 :                 self->mThreadRunningGC = nsnull;
     923           14728 :                 xpc_NotifyAll(self->GetMapLock());
     924                 :             }
     925                 : 
     926           14728 :             break;
     927                 :         }
     928                 :     }
     929                 : }
     930                 : 
     931                 : class AutoLockWatchdog {
     932                 :     XPCJSRuntime* const mRuntime;
     933                 : 
     934                 :   public:
     935          778895 :     AutoLockWatchdog(XPCJSRuntime* aRuntime)
     936          778895 :       : mRuntime(aRuntime) {
     937          778895 :         PR_Lock(mRuntime->mWatchdogLock);
     938          778895 :     }
     939                 : 
     940          778894 :     ~AutoLockWatchdog() {
     941          778894 :         PR_Unlock(mRuntime->mWatchdogLock);
     942          778894 :     }
     943                 : };
     944                 : 
     945                 : //static
     946                 : void
     947            1404 : XPCJSRuntime::WatchdogMain(void *arg)
     948                 : {
     949            1404 :     XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
     950                 : 
     951                 :     // Lock lasts until we return
     952            2807 :     AutoLockWatchdog lock(self);
     953                 : 
     954                 :     PRIntervalTime sleepInterval;
     955            6147 :     while (self->mWatchdogThread) {
     956                 :         // Sleep only 1 second if recently (or currently) active; otherwise, hibernate
     957            3340 :         if (self->mLastActiveTime == -1 || PR_Now() - self->mLastActiveTime <= PRTime(2*PR_USEC_PER_SEC))
     958            3339 :             sleepInterval = PR_TicksPerSecond();
     959                 :         else {
     960               1 :             sleepInterval = PR_INTERVAL_NO_TIMEOUT;
     961               1 :             self->mWatchdogHibernating = true;
     962                 :         }
     963            3340 :         MOZ_ALWAYS_TRUE(PR_WaitCondVar(self->mWatchdogWakeup, sleepInterval) == PR_SUCCESS);
     964            3339 :         JS_TriggerOperationCallback(self->mJSRuntime);
     965                 :     }
     966                 : 
     967                 :     /* Wake up the main thread waiting for the watchdog to terminate. */
     968            1403 :     PR_NotifyCondVar(self->mWatchdogWakeup);
     969            1403 : }
     970                 : 
     971                 : //static
     972                 : void
     973          774684 : XPCJSRuntime::ActivityCallback(void *arg, JSBool active)
     974                 : {
     975          774684 :     XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
     976                 : 
     977         1549368 :     AutoLockWatchdog lock(self);
     978                 :     
     979          774684 :     if (active) {
     980          387342 :         self->mLastActiveTime = -1;
     981          387342 :         if (self->mWatchdogHibernating) {
     982               1 :             self->mWatchdogHibernating = false;
     983               1 :             PR_NotifyCondVar(self->mWatchdogWakeup);
     984                 :         }
     985                 :     } else {
     986          387342 :         self->mLastActiveTime = PR_Now();
     987                 :     }
     988          774684 : }
     989                 : 
     990                 : size_t
     991               3 : XPCJSRuntime::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
     992                 : {
     993               3 :     size_t n = 0;
     994               3 :     n += mallocSizeOf(this);
     995               3 :     n += mWrappedJSMap->SizeOfIncludingThis(mallocSizeOf);
     996               3 :     n += mIID2NativeInterfaceMap->SizeOfIncludingThis(mallocSizeOf);
     997               3 :     n += mClassInfo2NativeSetMap->ShallowSizeOfIncludingThis(mallocSizeOf);
     998               3 :     n += mNativeSetMap->SizeOfIncludingThis(mallocSizeOf);
     999                 : 
    1000                 :     // NULL for the second arg;  we're not measuring anything hanging off the
    1001                 :     // entries in mJSHolders.
    1002               3 :     n += JS_DHashTableSizeOfExcludingThis(&mJSHolders, NULL, mallocSizeOf);
    1003                 : 
    1004                 :     // There are other XPCJSRuntime members that could be measured; the above
    1005                 :     // ones have been seen by DMD to be worth measuring.  More stuff may be
    1006                 :     // added later.
    1007                 : 
    1008               3 :     return n;
    1009                 : }
    1010                 : 
    1011                 : /***************************************************************************/
    1012                 : 
    1013                 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
    1014                 : static JSDHashOperator
    1015                 : DEBUG_WrapperChecker(JSDHashTable *table, JSDHashEntryHdr *hdr,
    1016                 :                      uint32_t number, void *arg)
    1017                 : {
    1018                 :     XPCWrappedNative* wrapper = (XPCWrappedNative*)((JSDHashEntryStub*)hdr)->key;
    1019                 :     NS_ASSERTION(!wrapper->IsValid(), "found a 'valid' wrapper!");
    1020                 :     ++ *((int*)arg);
    1021                 :     return JS_DHASH_NEXT;
    1022                 : }
    1023                 : #endif
    1024                 : 
    1025                 : static JSDHashOperator
    1026             275 : WrappedJSShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
    1027                 :                         uint32_t number, void *arg)
    1028                 : {
    1029             275 :     JSRuntime* rt = (JSRuntime*) arg;
    1030             275 :     nsXPCWrappedJS* wrapper = ((JSObject2WrappedJSMap::Entry*)hdr)->value;
    1031             275 :     NS_ASSERTION(wrapper, "found a null JS wrapper!");
    1032             275 :     NS_ASSERTION(wrapper->IsValid(), "found an invalid JS wrapper!");
    1033             275 :     wrapper->SystemIsBeingShutDown(rt);
    1034             275 :     return JS_DHASH_NEXT;
    1035                 : }
    1036                 : 
    1037                 : static JSDHashOperator
    1038               0 : DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
    1039                 :                                          uint32_t number, void *arg)
    1040                 : {
    1041                 :     XPCWrappedNativeProto* proto =
    1042               0 :         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
    1043                 : 
    1044               0 :     proto->SystemIsBeingShutDown();
    1045               0 :     return JS_DHASH_NEXT;
    1046                 : }
    1047                 : 
    1048            1403 : void XPCJSRuntime::SystemIsBeingShutDown()
    1049                 : {
    1050            1403 :     DOM_ClearInterfaces();
    1051                 : 
    1052            1403 :     if (mDetachedWrappedNativeProtoMap)
    1053                 :         mDetachedWrappedNativeProtoMap->
    1054            1403 :             Enumerate(DetachedWrappedNativeProtoShutdownMarker, nsnull);
    1055            1403 : }
    1056                 : 
    1057                 : JSContext *
    1058            1910 : XPCJSRuntime::GetJSCycleCollectionContext()
    1059                 : {
    1060            1910 :     if (!mJSCycleCollectionContext) {
    1061            1404 :         mJSCycleCollectionContext = JS_NewContext(mJSRuntime, 0);
    1062            1404 :         if (!mJSCycleCollectionContext)
    1063               0 :             return nsnull;
    1064                 :     }
    1065            1910 :     return mJSCycleCollectionContext;
    1066                 : }
    1067                 : 
    1068            2806 : XPCJSRuntime::~XPCJSRuntime()
    1069                 : {
    1070            1403 :     if (mWatchdogWakeup) {
    1071                 :         // If the watchdog thread is running, tell it to terminate waking it
    1072                 :         // up if necessary and wait until it signals that it finished. As we
    1073                 :         // must release the lock before calling PR_DestroyCondVar, we use an
    1074                 :         // extra block here.
    1075                 :         {
    1076            2806 :             AutoLockWatchdog lock(this);
    1077            1403 :             if (mWatchdogThread) {
    1078            1403 :                 mWatchdogThread = nsnull;
    1079            1403 :                 PR_NotifyCondVar(mWatchdogWakeup);
    1080            1403 :                 PR_WaitCondVar(mWatchdogWakeup, PR_INTERVAL_NO_TIMEOUT);
    1081                 :             }
    1082                 :         }
    1083            1403 :         PR_DestroyCondVar(mWatchdogWakeup);
    1084            1403 :         PR_DestroyLock(mWatchdogLock);
    1085            1403 :         mWatchdogWakeup = nsnull;
    1086                 :     }
    1087                 : 
    1088            1403 :     if (mJSCycleCollectionContext)
    1089            1403 :         JS_DestroyContextNoGC(mJSCycleCollectionContext);
    1090                 : 
    1091                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1092                 :     {
    1093                 :     // count the total JSContexts in use
    1094                 :     JSContext* iter = nsnull;
    1095                 :     int count = 0;
    1096                 :     while (JS_ContextIterator(mJSRuntime, &iter))
    1097                 :         count ++;
    1098                 :     if (count)
    1099                 :         printf("deleting XPCJSRuntime with %d live JSContexts\n", count);
    1100                 :     }
    1101                 : #endif
    1102                 : 
    1103                 :     // clean up and destroy maps...
    1104            1403 :     if (mWrappedJSMap) {
    1105                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1106                 :         uint32_t count = mWrappedJSMap->Count();
    1107                 :         if (count)
    1108                 :             printf("deleting XPCJSRuntime with %d live wrapped JSObject\n", (int)count);
    1109                 : #endif
    1110            1403 :         mWrappedJSMap->Enumerate(WrappedJSShutdownMarker, mJSRuntime);
    1111            1403 :         delete mWrappedJSMap;
    1112                 :     }
    1113                 : 
    1114            1403 :     if (mWrappedJSClassMap) {
    1115                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1116                 :         uint32_t count = mWrappedJSClassMap->Count();
    1117                 :         if (count)
    1118                 :             printf("deleting XPCJSRuntime with %d live nsXPCWrappedJSClass\n", (int)count);
    1119                 : #endif
    1120            1403 :         delete mWrappedJSClassMap;
    1121                 :     }
    1122                 : 
    1123            1403 :     if (mIID2NativeInterfaceMap) {
    1124                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1125                 :         uint32_t count = mIID2NativeInterfaceMap->Count();
    1126                 :         if (count)
    1127                 :             printf("deleting XPCJSRuntime with %d live XPCNativeInterfaces\n", (int)count);
    1128                 : #endif
    1129            1403 :         delete mIID2NativeInterfaceMap;
    1130                 :     }
    1131                 : 
    1132            1403 :     if (mClassInfo2NativeSetMap) {
    1133                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1134                 :         uint32_t count = mClassInfo2NativeSetMap->Count();
    1135                 :         if (count)
    1136                 :             printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count);
    1137                 : #endif
    1138            1403 :         delete mClassInfo2NativeSetMap;
    1139                 :     }
    1140                 : 
    1141            1403 :     if (mNativeSetMap) {
    1142                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1143                 :         uint32_t count = mNativeSetMap->Count();
    1144                 :         if (count)
    1145                 :             printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count);
    1146                 : #endif
    1147            1403 :         delete mNativeSetMap;
    1148                 :     }
    1149                 : 
    1150            1403 :     if (mMapLock)
    1151            1403 :         XPCAutoLock::DestroyLock(mMapLock);
    1152                 : 
    1153            1403 :     if (mThisTranslatorMap) {
    1154                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1155                 :         uint32_t count = mThisTranslatorMap->Count();
    1156                 :         if (count)
    1157                 :             printf("deleting XPCJSRuntime with %d live ThisTranslator\n", (int)count);
    1158                 : #endif
    1159            1403 :         delete mThisTranslatorMap;
    1160                 :     }
    1161                 : 
    1162                 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
    1163                 :     if (DEBUG_WrappedNativeHashtable) {
    1164                 :         int LiveWrapperCount = 0;
    1165                 :         JS_DHashTableEnumerate(DEBUG_WrappedNativeHashtable,
    1166                 :                                DEBUG_WrapperChecker, &LiveWrapperCount);
    1167                 :         if (LiveWrapperCount)
    1168                 :             printf("deleting XPCJSRuntime with %d live XPCWrappedNative (found in wrapper check)\n", (int)LiveWrapperCount);
    1169                 :         JS_DHashTableDestroy(DEBUG_WrappedNativeHashtable);
    1170                 :     }
    1171                 : #endif
    1172                 : 
    1173            1403 :     if (mNativeScriptableSharedMap) {
    1174                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1175                 :         uint32_t count = mNativeScriptableSharedMap->Count();
    1176                 :         if (count)
    1177                 :             printf("deleting XPCJSRuntime with %d live XPCNativeScriptableShared\n", (int)count);
    1178                 : #endif
    1179            1403 :         delete mNativeScriptableSharedMap;
    1180                 :     }
    1181                 : 
    1182            1403 :     if (mDyingWrappedNativeProtoMap) {
    1183                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1184                 :         uint32_t count = mDyingWrappedNativeProtoMap->Count();
    1185                 :         if (count)
    1186                 :             printf("deleting XPCJSRuntime with %d live but dying XPCWrappedNativeProto\n", (int)count);
    1187                 : #endif
    1188            1403 :         delete mDyingWrappedNativeProtoMap;
    1189                 :     }
    1190                 : 
    1191            1403 :     if (mDetachedWrappedNativeProtoMap) {
    1192                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1193                 :         uint32_t count = mDetachedWrappedNativeProtoMap->Count();
    1194                 :         if (count)
    1195                 :             printf("deleting XPCJSRuntime with %d live detached XPCWrappedNativeProto\n", (int)count);
    1196                 : #endif
    1197            1403 :         delete mDetachedWrappedNativeProtoMap;
    1198                 :     }
    1199                 : 
    1200            1403 :     if (mExplicitNativeWrapperMap) {
    1201                 : #ifdef XPC_DUMP_AT_SHUTDOWN
    1202                 :         uint32_t count = mExplicitNativeWrapperMap->Count();
    1203                 :         if (count)
    1204                 :             printf("deleting XPCJSRuntime with %d live explicit XPCNativeWrapper\n", (int)count);
    1205                 : #endif
    1206            1403 :         delete mExplicitNativeWrapperMap;
    1207                 :     }
    1208                 : 
    1209            1403 :     if (mJSHolders.ops) {
    1210            1403 :         JS_DHashTableFinish(&mJSHolders);
    1211            1403 :         mJSHolders.ops = nsnull;
    1212                 :     }
    1213                 : 
    1214            1403 :     if (mJSRuntime) {
    1215            1403 :         JS_DestroyRuntime(mJSRuntime);
    1216            1403 :         JS_ShutDown();
    1217                 : #ifdef DEBUG_shaver_off
    1218                 :         fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
    1219                 : #endif
    1220                 :     }
    1221                 : 
    1222            1403 :     XPCPerThreadData::ShutDown();
    1223            1403 : }
    1224                 : 
    1225                 : static void
    1226              18 : GetCompartmentName(JSCompartment *c, bool getAddress, nsCString &name)
    1227                 : {
    1228              18 :     if (js::IsAtomsCompartment(c)) {
    1229               6 :         name.AssignLiteral("atoms");
    1230              12 :     } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
    1231              12 :         nsJSPrincipals::get(principals)->GetScriptLocation(name);
    1232                 : 
    1233                 :         // For system compartments we append the location, if there is one.
    1234                 :         // And we append the address if |getAddress| is true, so that
    1235                 :         // multiple system compartments (and there can be many) can be
    1236                 :         // distinguished.
    1237              12 :         if (js::IsSystemCompartment(c)) {
    1238                 :             xpc::CompartmentPrivate *compartmentPrivate =
    1239               6 :                 static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(c));
    1240               6 :             if (compartmentPrivate && !compartmentPrivate->location.IsEmpty()) {
    1241               0 :                 name.AppendLiteral(", ");
    1242               0 :                 name.Append(compartmentPrivate->location);
    1243                 :             }
    1244                 :             
    1245               6 :             if (getAddress) {
    1246                 :                 // ample; 64-bit address max is 18 chars
    1247               3 :                 const int maxLength = 31;
    1248               6 :                 nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
    1249               3 :                 name.Append(address);
    1250                 :             }
    1251                 :         }
    1252                 :         
    1253                 :         // A hack: replace forward slashes with '\\' so they aren't
    1254                 :         // treated as path separators.  Users of the reporters
    1255                 :         // (such as about:memory) have to undo this change.
    1256              12 :         name.ReplaceChar('/', '\\');
    1257                 :     } else {
    1258               0 :         name.AssignLiteral("null-principal");
    1259                 :     }
    1260              18 : }
    1261                 : 
    1262                 : // We have per-compartment GC heap totals, so we can't put the total GC heap
    1263                 : // size in the explicit allocations tree.  But it's a useful figure, so put it
    1264                 : // in the "others" list.
    1265                 : 
    1266                 : static PRInt64
    1267               3 : GetGCChunkTotalBytes()
    1268                 : {
    1269               3 :     JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
    1270               3 :     return PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * js::gc::ChunkSize;
    1271                 : }
    1272                 : 
    1273            1422 : NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
    1274                 :                              "js-gc-heap",
    1275                 :                              KIND_OTHER,
    1276                 :                              nsIMemoryReporter::UNITS_BYTES,
    1277                 :                              GetGCChunkTotalBytes,
    1278            4278 :                              "Memory used by the garbage-collected JavaScript heap.")
    1279                 : 
    1280                 : static PRInt64
    1281               3 : GetJSSystemCompartmentCount()
    1282                 : {
    1283               3 :     return JS::SystemCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
    1284                 : }
    1285                 : 
    1286                 : static PRInt64
    1287               3 : GetJSUserCompartmentCount()
    1288                 : {
    1289               3 :     return JS::UserCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
    1290                 : }
    1291                 : 
    1292                 : // Nb: js-system-compartment-count + js-user-compartment-count could be
    1293                 : // different to the number of compartments reported by
    1294                 : // JSMemoryMultiReporter if a garbage collection occurred
    1295                 : // between them being consulted.  We could move these reporters into
    1296                 : // XPConnectJSCompartmentCount to avoid that problem, but then we couldn't
    1297                 : // easily report them via telemetry, so we live with the small risk of
    1298                 : // inconsistencies.
    1299            1425 : NS_MEMORY_REPORTER_IMPLEMENT(
    1300                 :     XPConnectJSSystemCompartmentCount,
    1301                 :     "js-compartments-system",
    1302                 :     KIND_OTHER,
    1303                 :     nsIMemoryReporter::UNITS_COUNT,
    1304                 :     GetJSSystemCompartmentCount,
    1305                 :     "The number of JavaScript compartments for system code.  The sum of this "
    1306                 :     "and 'js-compartments-user' might not match the number of compartments "
    1307                 :     "listed under 'js' if a garbage collection occurs at an inopportune time, "
    1308            4278 :     "but such cases should be rare.")
    1309                 : 
    1310            1425 : NS_MEMORY_REPORTER_IMPLEMENT(
    1311                 :     XPConnectJSUserCompartmentCount,
    1312                 :     "js-compartments-user",
    1313                 :     KIND_OTHER,
    1314                 :     nsIMemoryReporter::UNITS_COUNT,
    1315                 :     GetJSUserCompartmentCount,
    1316                 :     "The number of JavaScript compartments for user code.  The sum of this "
    1317                 :     "and 'js-compartments-system' might not match the number of compartments "
    1318                 :     "listed under 'js' if a garbage collection occurs at an inopportune time, "
    1319            4278 :     "but such cases should be rare.")
    1320                 : 
    1321                 : // The REPORT* macros do an unconditional report.  The REPORT*0 macros only
    1322                 : // report if the value is non-zero.
    1323                 : 
    1324                 : #define REPORT(_path, _kind, _units, _amount, _desc)                          \
    1325                 :     do {                                                                      \
    1326                 :         nsresult rv;                                                          \
    1327                 :         rv = cb->Callback(EmptyCString(), _path, _kind, _units, _amount,      \
    1328                 :                           NS_LITERAL_CSTRING(_desc), closure);                \
    1329                 :         NS_ENSURE_SUCCESS(rv, rv);                                            \
    1330                 :     } while (0)
    1331                 : 
    1332                 : #define REPORT0(_path, _kind, _units, _amount, _desc)                         \
    1333                 :     do {                                                                      \
    1334                 :         size_t amount = _amount;  /* evaluate _amount only once */            \
    1335                 :         if (amount > 0) {                                                     \
    1336                 :             nsresult rv;                                                      \
    1337                 :             rv = cb->Callback(EmptyCString(), _path, _kind, _units, amount,   \
    1338                 :                               NS_LITERAL_CSTRING(_desc), closure);            \
    1339                 :             NS_ENSURE_SUCCESS(rv, rv);                                        \
    1340                 :         }                                                                     \
    1341                 :     } while (0)
    1342                 : 
    1343                 : #define REPORT_BYTES(_path, _kind, _amount, _desc)                            \
    1344                 :     REPORT(_path, _kind, nsIMemoryReporter::UNITS_BYTES, _amount, _desc);
    1345                 : 
    1346                 : #define REPORT_BYTES0(_path, _kind, _amount, _desc)                           \
    1347                 :     REPORT0(_path, _kind, nsIMemoryReporter::UNITS_BYTES, _amount, _desc);
    1348                 : 
    1349                 : #define REPORT_GC_BYTES(_path, _amount, _desc)                                \
    1350                 :     do {                                                                      \
    1351                 :         size_t amount = _amount;  /* evaluate _amount only once */            \
    1352                 :         nsresult rv;                                                          \
    1353                 :         rv = cb->Callback(EmptyCString(), _path,                              \
    1354                 :                           nsIMemoryReporter::KIND_NONHEAP,                    \
    1355                 :                           nsIMemoryReporter::UNITS_BYTES, amount,             \
    1356                 :                           NS_LITERAL_CSTRING(_desc), closure);                \
    1357                 :         NS_ENSURE_SUCCESS(rv, rv);                                            \
    1358                 :         gcTotal += amount;                                                    \
    1359                 :     } while (0)
    1360                 : 
    1361                 : #define REPORT_GC_BYTES0(_path, _amount, _desc)                               \
    1362                 :     do {                                                                      \
    1363                 :         size_t amount = _amount;  /* evaluate _amount only once */            \
    1364                 :         if (amount > 0) {                                                     \
    1365                 :             nsresult rv;                                                      \
    1366                 :             rv = cb->Callback(EmptyCString(), _path,                          \
    1367                 :                               nsIMemoryReporter::KIND_NONHEAP,                \
    1368                 :                               nsIMemoryReporter::UNITS_BYTES, amount,         \
    1369                 :                               NS_LITERAL_CSTRING(_desc), closure);            \
    1370                 :             NS_ENSURE_SUCCESS(rv, rv);                                        \
    1371                 :             gcTotal += amount;                                                \
    1372                 :         }                                                                     \
    1373                 :     } while (0)
    1374                 : 
    1375                 : template <int N>
    1376                 : inline const nsCString
    1377             135 : MakePath(const nsACString &pathPrefix, const JS::CompartmentStats &cStats,
    1378                 :          const char (&reporterName)[N])
    1379                 : {
    1380             135 :     const char *name = static_cast<char *>(cStats.extra);
    1381             135 :     if (!name)
    1382               0 :         name = "error while initializing compartment name";
    1383                 :     return pathPrefix + NS_LITERAL_CSTRING("compartment(") +
    1384                 :            nsDependentCString(name) + NS_LITERAL_CSTRING(")/") +
    1385             135 :            nsDependentCString(reporterName);
    1386                 : }
    1387                 : 
    1388                 : namespace mozilla {
    1389                 : namespace xpconnect {
    1390                 : namespace memory {
    1391                 : 
    1392                 : static nsresult
    1393               9 : ReportCompartmentStats(const JS::CompartmentStats &cStats,
    1394                 :                        const nsACString &pathPrefix,
    1395                 :                        nsIMemoryMultiReporterCallback *cb,
    1396                 :                        nsISupports *closure, size_t *gcTotalOut)
    1397                 : {
    1398               9 :     size_t gcTotal = 0;
    1399                 : 
    1400               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/arena/headers"),
    1401                 :                      cStats.gcHeapArenaHeaders,
    1402                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1403                 :                      "heap, within arenas, that is used to hold internal "
    1404                 :                      "book-keeping information.");
    1405                 : 
    1406               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/arena/padding"),
    1407                 :                      cStats.gcHeapArenaPadding,
    1408                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1409                 :                      "heap, within arenas, that is unused and present only so "
    1410                 :                      "that other data is aligned. This constitutes internal "
    1411                 :                      "fragmentation.");
    1412                 : 
    1413               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/arena/unused"),
    1414                 :                      cStats.gcHeapArenaUnused,
    1415                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1416                 :                      "heap, within arenas, that could be holding useful data "
    1417                 :                      "but currently isn't.");
    1418                 : 
    1419               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/objects/non-function"),
    1420                 :                      cStats.gcHeapObjectsNonFunction,
    1421                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1422                 :                      "heap that holds non-function objects.");
    1423                 : 
    1424               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/objects/function"),
    1425                 :                      cStats.gcHeapObjectsFunction,
    1426                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1427                 :                      "heap that holds function objects.");
    1428                 : 
    1429               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/strings"),
    1430                 :                      cStats.gcHeapStrings,
    1431                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1432                 :                      "heap that holds string headers.  String headers contain "
    1433                 :                      "various pieces of information about a string, but do not "
    1434                 :                      "contain (except in the case of very short strings) the "
    1435                 :                      "string characters;  characters in longer strings are "
    1436                 :                      "counted " "under 'gc-heap/string-chars' instead.");
    1437                 : 
    1438               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/scripts"),
    1439                 :                      cStats.gcHeapScripts,
    1440                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1441                 :                      "heap that holds JSScript instances. A JSScript is "
    1442                 :                      "created for each user-defined function in a script. One "
    1443                 :                      "is also created for the top-level code in a script.");
    1444                 : 
    1445               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/shapes/tree"),
    1446                 :                      cStats.gcHeapShapesTree,
    1447                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1448                 :                      "heap that holds shapes that are in a property tree.");
    1449                 : 
    1450               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/shapes/dict"),
    1451                 :                      cStats.gcHeapShapesDict,
    1452                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1453                 :                      "heap that holds shapes that are in dictionary mode.");
    1454                 : 
    1455               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/shapes/base"),
    1456                 :                      cStats.gcHeapShapesBase,
    1457                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1458                 :                      "heap that collates data common to many shapes.");
    1459                 : 
    1460               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/type-objects"),
    1461                 :                      cStats.gcHeapTypeObjects,
    1462                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1463                 :                      "heap that holds type inference information.");
    1464                 : 
    1465               9 :     REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/xml"),
    1466                 :                      cStats.gcHeapXML,
    1467                 :                      "Memory on the compartment's garbage-collected JavaScript "
    1468                 :                      "heap that holds E4X XML objects.");
    1469                 : 
    1470               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "objects/slots"),
    1471                 :                   nsIMemoryReporter::KIND_HEAP, cStats.objectSlots,
    1472                 :                   "Memory allocated for the compartment's non-fixed object "
    1473                 :                   "slot arrays, which are used to represent object properties. "
    1474                 :                   "Some objects also contain a fixed number of slots which are "
    1475                 :                   "stored on the compartment's JavaScript heap; those slots "
    1476                 :                   "are not counted here, but in 'gc-heap/objects' instead.");
    1477                 : 
    1478               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "objects/elements"),
    1479                 :                   nsIMemoryReporter::KIND_HEAP, cStats.objectElements,
    1480                 :                   "Memory allocated for the compartment's object element "
    1481                 :                   "arrays, which are used to represent indexed object "
    1482                 :                   "properties.");
    1483                 : 
    1484               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "objects/misc"),
    1485                 :                   nsIMemoryReporter::KIND_HEAP, cStats.objectMisc,
    1486                 :                   "Memory allocated for various small, miscellaneous "
    1487                 :                   "structures that hang off certain kinds of objects.");
    1488                 : 
    1489               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "string-chars"),
    1490                 :                   nsIMemoryReporter::KIND_HEAP, cStats.stringChars,
    1491                 :                   "Memory allocated to hold the compartment's string "
    1492                 :                   "characters.  Sometimes more memory is allocated than "
    1493                 :                   "necessary, to simplify string concatenation.  Each string "
    1494                 :                   "also includes a header which is stored on the "
    1495                 :                   "compartment's JavaScript heap;  that header is not counted "
    1496                 :                   "here, but in 'gc-heap/strings' instead.");
    1497                 : 
    1498               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/tree-tables"),
    1499                 :                   nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeTables,
    1500                 :                   "Memory allocated for the compartment's property tables "
    1501                 :                   "that belong to shapes that are in a property tree.");
    1502                 : 
    1503               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/dict-tables"),
    1504                 :                   nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraDictTables,
    1505                 :                   "Memory allocated for the compartment's property tables "
    1506                 :                   "that belong to shapes that are in dictionary mode.");
    1507                 : 
    1508               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/tree-shape-kids"),
    1509                 :                   nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeShapeKids,
    1510                 :                   "Memory allocated for the compartment's kid hashes that "
    1511                 :                   "belong to shapes that are in a property tree.");
    1512                 : 
    1513               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/compartment-tables"),
    1514                 :                   nsIMemoryReporter::KIND_HEAP, cStats.shapesCompartmentTables,
    1515                 :                   "Memory used by compartment wide tables storing shape "
    1516                 :                   "information for use during object construction.");
    1517                 : 
    1518               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "script-data"),
    1519                 :                   nsIMemoryReporter::KIND_HEAP, cStats.scriptData,
    1520                 :                   "Memory allocated for JSScript bytecode and various "
    1521                 :                   "variable-length tables.");
    1522                 : 
    1523                 : #ifdef JS_METHODJIT
    1524               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "mjit/code"),
    1525                 :                   nsIMemoryReporter::KIND_NONHEAP, cStats.mjitCode,
    1526                 :                   "Memory used by the method JIT to hold the compartment's "
    1527                 :                   "generated code.");
    1528                 : 
    1529               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "mjit/data"),
    1530                 :                   nsIMemoryReporter::KIND_HEAP, cStats.mjitData,
    1531                 :                   "Memory used by the method JIT for the compartment's "
    1532                 :                   "compilation data: JITScripts, native maps, and inline "
    1533                 :                   "cache structs.");
    1534                 : #endif
    1535                 : 
    1536               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "type-inference/script-main"),
    1537                 :                   nsIMemoryReporter::KIND_HEAP,
    1538                 :                   cStats.typeInferenceSizes.scripts,
    1539                 :                   "Memory used during type inference to store type sets of "
    1540                 :                   "variables and dynamically observed types.");
    1541                 : 
    1542               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "type-inference/object-main"),
    1543                 :                   nsIMemoryReporter::KIND_HEAP,
    1544                 :                   cStats.typeInferenceSizes.objects,
    1545                 :                   "Memory used during type inference to store types and "
    1546                 :                   "possible property types of JS objects.");
    1547                 : 
    1548               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "type-inference/tables"),
    1549                 :                   nsIMemoryReporter::KIND_HEAP,
    1550                 :                   cStats.typeInferenceSizes.tables,
    1551                 :                   "Memory used during type inference for compartment-wide "
    1552                 :                   "tables.");
    1553                 : 
    1554               9 :     REPORT_BYTES0(MakePath(pathPrefix, cStats, "analysis-temporary"),
    1555                 :                   nsIMemoryReporter::KIND_HEAP,
    1556                 :                   cStats.typeInferenceSizes.temporary,
    1557                 :                   "Memory used during type inference and compilation to hold "
    1558                 :                   "transient analysis information.  Cleared on GC.");
    1559                 : 
    1560               9 :     *gcTotalOut += gcTotal;
    1561                 : 
    1562               9 :     return NS_OK;
    1563                 : }
    1564                 : 
    1565                 : nsresult
    1566               3 : ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
    1567                 :                                  const nsACString &pathPrefix,
    1568                 :                                  nsIMemoryMultiReporterCallback *cb,
    1569                 :                                  nsISupports *closure)
    1570                 : {
    1571                 :     nsresult rv;
    1572               3 :     size_t gcTotal = 0;
    1573              24 :     for (size_t index = 0;
    1574              12 :          index < rtStats.compartmentStatsVector.length();
    1575                 :          index++) {
    1576               9 :         rv = ReportCompartmentStats(rtStats.compartmentStatsVector[index],
    1577               9 :                                     pathPrefix, cb, closure, &gcTotal);
    1578               9 :         NS_ENSURE_SUCCESS(rv, rv);
    1579                 :     }
    1580                 : 
    1581               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
    1582                 :                  nsIMemoryReporter::KIND_HEAP, rtStats.runtimeObject,
    1583                 :                  "Memory used by the JSRuntime object.");
    1584                 : 
    1585               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"),
    1586                 :                  nsIMemoryReporter::KIND_HEAP, rtStats.runtimeAtomsTable,
    1587                 :                  "Memory used by the atoms table.");
    1588                 : 
    1589               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/contexts"),
    1590                 :                  nsIMemoryReporter::KIND_HEAP, rtStats.runtimeContexts,
    1591                 :                  "Memory used by JSContext objects and certain structures "
    1592                 :                  "hanging off them.");
    1593                 : 
    1594               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/normal"),
    1595                 :                  nsIMemoryReporter::KIND_HEAP, rtStats.runtimeNormal,
    1596                 :                  "Memory used by a JSRuntime, excluding memory that is "
    1597                 :                  "reported by other reporters under 'explicit/js/runtime/'.");
    1598                 : 
    1599               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/temporary"),
    1600                 :                  nsIMemoryReporter::KIND_HEAP, rtStats.runtimeTemporary,
    1601                 :                  "Memory held transiently in JSRuntime and used during "
    1602                 :                  "compilation.  It mostly holds parse nodes.");
    1603                 : 
    1604               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/regexp-code"),
    1605                 :                  nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeRegexpCode,
    1606                 :                  "Memory used by the regexp JIT to hold generated code.");
    1607                 : 
    1608               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"),
    1609                 :                  nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeStackCommitted,
    1610                 :                  "Memory used for the JS call stack.  This is the committed "
    1611                 :                  "portion of the stack; the uncommitted portion is not "
    1612                 :                  "measured because it hardly costs anything.");
    1613                 : 
    1614               3 :     REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/gc-marker"),
    1615                 :                  nsIMemoryReporter::KIND_HEAP, rtStats.runtimeGCMarker,
    1616                 :                  "Memory used for the GC mark stack and gray roots.");
    1617                 : 
    1618               3 :     REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
    1619                 :                     rtStats.gcHeapChunkDirtyUnused,
    1620                 :                     "Memory on the garbage-collected JavaScript heap, within "
    1621                 :                     "chunks with at least one allocated GC thing, that could "
    1622                 :                     "be holding useful data but currently isn't.  Memory here "
    1623                 :                     "is mutually exclusive with memory reported under "
    1624                 :                     "'explicit/js/gc-heap-decommitted'.");
    1625                 : 
    1626               3 :     REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-clean-unused"),
    1627                 :                     rtStats.gcHeapChunkCleanUnused,
    1628                 :                     "Memory on the garbage-collected JavaScript heap taken by "
    1629                 :                     "completely empty chunks, that soon will be released "
    1630                 :                     "unless claimed for new allocations.  Memory here is "
    1631                 :                     "mutually exclusive with memory reported under "
    1632                 :                     "'explicit/js/gc-heap-decommitted'.");
    1633                 : 
    1634               3 :     REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-decommitted"),
    1635                 :                     rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
    1636                 :                     "Memory in the address space of the garbage-collected "
    1637                 :                     "JavaScript heap that is currently returned to the OS.");
    1638                 : 
    1639               3 :     REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
    1640                 :                     rtStats.gcHeapChunkAdmin,
    1641                 :                     "Memory on the garbage-collected JavaScript heap, within "
    1642                 :                     "chunks, that is used to hold internal book-keeping "
    1643                 :                     "information.");
    1644                 : 
    1645                 :     // gcTotal is the sum of everything we've reported for the GC heap.  It
    1646                 :     // should equal rtStats.gcHeapChunkTotal.
    1647               3 :     JS_ASSERT(gcTotal == rtStats.gcHeapChunkTotal);
    1648                 : 
    1649               3 :     return NS_OK;
    1650                 : }
    1651                 : 
    1652                 : } // namespace memory
    1653                 : } // namespace xpconnect
    1654                 : } // namespace mozilla
    1655                 : 
    1656           42948 : NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
    1657                 : 
    1658                 : class JSCompartmentsMultiReporter : public nsIMemoryMultiReporter
    1659            1404 : {
    1660                 :   public:
    1661                 :     NS_DECL_ISUPPORTS
    1662                 : 
    1663               0 :     NS_IMETHOD GetName(nsACString &name)
    1664                 :     {
    1665               0 :         name.AssignLiteral("compartments");
    1666               0 :         return NS_OK;
    1667                 :     }
    1668                 : 
    1669                 :     typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths; 
    1670                 : 
    1671               9 :     static void CompartmentCallback(JSRuntime *rt, void* data, JSCompartment *c)
    1672                 :     {
    1673                 :         // silently ignore OOM errors
    1674               9 :         Paths *paths = static_cast<Paths *>(data);
    1675              18 :         nsCString path;
    1676               9 :         GetCompartmentName(c, /* getAddress = */ false, path);
    1677               9 :         path.Insert(js::IsSystemCompartment(c)
    1678               6 :                     ? NS_LITERAL_CSTRING("compartments/system/")
    1679               3 :                     : NS_LITERAL_CSTRING("compartments/user/"),
    1680              18 :                     0);
    1681               9 :         paths->append(path);
    1682               9 :     }
    1683                 : 
    1684               3 :     NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *cb,
    1685                 :                               nsISupports *closure)
    1686                 :     {
    1687                 :         // First we collect the compartment paths.  Then we report them.  Doing
    1688                 :         // the two steps interleaved is a bad idea, because calling |cb|
    1689                 :         // from within CompartmentCallback() leads to all manner of assertions.
    1690                 : 
    1691                 :         // Collect.
    1692                 :  
    1693               6 :         Paths paths; 
    1694                 :         JS_IterateCompartments(nsXPConnect::GetRuntimeInstance()->GetJSRuntime(),
    1695               3 :                                &paths, CompartmentCallback);
    1696                 :  
    1697                 :         // Report.
    1698              12 :         for (size_t i = 0; i < paths.length(); i++)
    1699                 :             // These ones don't need a description, hence the "".
    1700               9 :             REPORT(nsCString(paths[i]),
    1701                 :                    nsIMemoryReporter::KIND_OTHER,
    1702                 :                    nsIMemoryReporter::UNITS_COUNT,
    1703                 :                    1, "");
    1704                 : 
    1705               3 :         return NS_OK;
    1706                 :     }
    1707                 : 
    1708                 :     NS_IMETHOD
    1709               3 :     GetExplicitNonHeap(PRInt64 *n)
    1710                 :     {
    1711                 :         // This reporter does neither "explicit" nor NONHEAP measurements.
    1712               3 :         *n = 0;
    1713               3 :         return NS_OK;
    1714                 :     }
    1715                 : };
    1716                 : 
    1717            4242 : NS_IMPL_THREADSAFE_ISUPPORTS1(JSCompartmentsMultiReporter
    1718                 :                               , nsIMemoryMultiReporter
    1719                 :                               )
    1720                 : 
    1721                 : struct XPCJSRuntimeStats : public JS::RuntimeStats {
    1722               3 :     XPCJSRuntimeStats()
    1723               3 :       : JS::RuntimeStats(JsMallocSizeOf) { }
    1724                 :     
    1725               6 :     ~XPCJSRuntimeStats() {
    1726              12 :         for (size_t i = 0; i != compartmentStatsVector.length(); ++i)
    1727               9 :             free(compartmentStatsVector[i].extra);
    1728               3 :     }
    1729                 : 
    1730               9 :     virtual void initExtraCompartmentStats(JSCompartment *c,
    1731                 :                                            JS::CompartmentStats *cstats) MOZ_OVERRIDE {
    1732              18 :         nsCAutoString name;
    1733               9 :         GetCompartmentName(c, /* getAddress = */ true, name);
    1734               9 :         cstats->extra = strdup(name.get());
    1735               9 :     }
    1736                 : };
    1737                 :     
    1738                 : class JSMemoryMultiReporter : public nsIMemoryMultiReporter
    1739            1404 : {
    1740                 : public:
    1741                 :     NS_DECL_ISUPPORTS
    1742                 : 
    1743               0 :     NS_IMETHOD GetName(nsACString &name)
    1744                 :     {
    1745               0 :         name.AssignLiteral("js");
    1746               0 :         return NS_OK;
    1747                 :     }
    1748                 : 
    1749               3 :     NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *cb,
    1750                 :                               nsISupports *closure)
    1751                 :     {
    1752               3 :         XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
    1753                 : 
    1754                 :         // In the first step we get all the stats and stash them in a local
    1755                 :         // data structure.  In the second step we pass all the stashed stats to
    1756                 :         // the callback.  Separating these steps is important because the
    1757                 :         // callback may be a JS function, and executing JS while getting these
    1758                 :         // stats seems like a bad idea.
    1759               6 :         XPCJSRuntimeStats rtStats;
    1760               3 :         if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
    1761               0 :             return NS_ERROR_FAILURE;
    1762                 : 
    1763                 :         size_t xpconnect =
    1764               3 :             xpcrt->SizeOfIncludingThis(JsMallocSizeOf) +
    1765               3 :             XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
    1766                 : 
    1767               6 :         NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
    1768                 : 
    1769                 :         // This is the second step (see above).  First we report stuff in the
    1770                 :         // "explicit" tree, then we report other stuff.
    1771                 : 
    1772                 :         nsresult rv =
    1773               3 :             ReportJSRuntimeExplicitTreeStats(rtStats, pathPrefix, cb, closure);
    1774               3 :         NS_ENSURE_SUCCESS(rv, rv);
    1775                 : 
    1776               3 :         REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
    1777                 :                      nsIMemoryReporter::KIND_HEAP, xpconnect,
    1778                 :                      "Memory used by XPConnect.");
    1779                 : 
    1780               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-chunk-dirty-unused"),
    1781                 :                      nsIMemoryReporter::KIND_OTHER,
    1782                 :                      rtStats.gcHeapChunkDirtyUnused,
    1783                 :                      "The same as 'explicit/js/gc-heap-chunk-dirty-unused'. "
    1784                 :                      "Shown here for easy comparison with other 'js-gc' "
    1785                 :                      "reporters.");
    1786                 : 
    1787               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-chunk-clean-unused"),
    1788                 :                      nsIMemoryReporter::KIND_OTHER,
    1789                 :                      rtStats.gcHeapChunkCleanUnused,
    1790                 :                      "The same as 'explicit/js/gc-heap-chunk-clean-unused'.  "
    1791                 :                      "Shown here for easy comparison with other 'js-gc' "
    1792                 :                      "reporters.");
    1793                 : 
    1794               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-decommitted"),
    1795                 :                      nsIMemoryReporter::KIND_OTHER,
    1796                 :                      rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
    1797                 :                      "The same as 'explicit/js/gc-heap-decommitted'.  Shown "
    1798                 :                      "here for easy comparison with other 'js-gc' reporters.");
    1799                 : 
    1800               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-arena-unused"),
    1801                 :                      nsIMemoryReporter::KIND_OTHER,
    1802                 :                      rtStats.gcHeapArenaUnused,
    1803                 :                      "Memory on the main JSRuntime's garbage-collected "
    1804                 :                      "JavaScript heap, within arenas, that could be holding "
    1805                 :                      "useful data but currently isn't. This is the sum of all "
    1806                 :                      "compartments' 'gc-heap/arena-unused' numbers.");
    1807                 : 
    1808               3 :         REPORT(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-unused-fraction"),
    1809                 :                nsIMemoryReporter::KIND_OTHER,
    1810                 :                nsIMemoryReporter::UNITS_PERCENTAGE,
    1811                 :                rtStats.gcHeapUnusedPercentage,
    1812                 :                "Fraction of the main JSRuntime's garbage-collected JavaScript "
    1813                 :                "heap that is unused. Computed as "
    1814                 :                "('js-gc-heap-chunk-clean-unused' + "
    1815                 :                "'js-gc-heap-chunk-dirty-unused' + 'js-gc-heap-decommitted' + "
    1816                 :                "'js-gc-heap-arena-unused') / 'js-gc-heap'.");
    1817                 : 
    1818               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-objects"),
    1819                 :                      nsIMemoryReporter::KIND_OTHER, rtStats.totalObjects,
    1820                 :                      "Memory used for all object-related data in the main "
    1821                 :                      "JSRuntime. This is the sum of all compartments' "
    1822                 :                      "'gc-heap/objects-non-function', "
    1823                 :                      "'gc-heap/objects-function' and 'object-slots' numbers.");
    1824                 : 
    1825               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-shapes"),
    1826                 :                      nsIMemoryReporter::KIND_OTHER, rtStats.totalShapes,
    1827                 :                      "Memory used for all shape-related data in the main "
    1828                 :                      "JSRuntime. This is the sum of all compartments' "
    1829                 :                      "'gc-heap/shapes/tree', 'gc-heap/shapes/dict', "
    1830                 :                      "'gc-heap/shapes/base', 'shapes-extra/tree-tables', "
    1831                 :                      "'shapes-extra/dict-tables', "
    1832                 :                      "'shapes-extra/tree-shape-kids' and "
    1833                 :                      "'shapes-extra/empty-shape-arrays'.");
    1834                 : 
    1835               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-scripts"),
    1836                 :                      nsIMemoryReporter::KIND_OTHER, rtStats.totalScripts,
    1837                 :                      "Memory used for all script-related data in the main "
    1838                 :                      "JSRuntime. This is the sum of all compartments' "
    1839                 :                      "'gc-heap/scripts' and 'script-data' numbers.");
    1840                 : 
    1841               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-strings"),
    1842                 :                      nsIMemoryReporter::KIND_OTHER, rtStats.totalStrings,
    1843                 :                      "Memory used for all string-related data in the main "
    1844                 :                      "JSRuntime. This is the sum of all compartments' "
    1845                 :                      "'gc-heap/strings' and 'string-chars' numbers.");
    1846                 : 
    1847                 : #ifdef JS_METHODJIT
    1848               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-mjit"),
    1849                 :                      nsIMemoryReporter::KIND_OTHER, rtStats.totalMjit,
    1850                 :                      "Memory used by the method JIT in the main JSRuntime.  "
    1851                 :                      "This is the sum of all compartments' 'mjit/code', and "
    1852                 :                      "'mjit/data' numbers.");
    1853                 : #endif
    1854               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-type-inference"),
    1855                 :                      nsIMemoryReporter::KIND_OTHER, rtStats.totalTypeInference,
    1856                 :                      "Non-transient memory used by type inference in the main "
    1857                 :                      "JSRuntime. This is the sum of all compartments' "
    1858                 :                      "'gc-heap/type-objects', 'type-inference/script-main', "
    1859                 :                      "'type-inference/object-main' and "
    1860                 :                      "'type-inference/tables' numbers.");
    1861                 : 
    1862               3 :         REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-analysis-temporary"),
    1863                 :                      nsIMemoryReporter::KIND_OTHER, rtStats.totalAnalysisTemp,
    1864                 :                      "Memory used transiently during type inference and "
    1865                 :                      "compilation in the main JSRuntime. This is the sum of "
    1866                 :                      "all compartments' 'analysis-temporary' numbers.");
    1867                 : 
    1868               3 :         return NS_OK;
    1869                 :     }
    1870                 : 
    1871                 :     NS_IMETHOD
    1872               3 :     GetExplicitNonHeap(PRInt64 *n)
    1873                 :     {
    1874               3 :         JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
    1875               3 :         *reinterpret_cast<int64_t*>(n) = JS::GetExplicitNonHeapForRuntime(rt, JsMallocSizeOf);
    1876               3 :         return NS_OK;
    1877                 :     }
    1878                 : };
    1879                 : 
    1880            4242 : NS_IMPL_THREADSAFE_ISUPPORTS1(JSMemoryMultiReporter
    1881                 :                               , nsIMemoryMultiReporter
    1882                 :                               )
    1883                 : 
    1884                 : #ifdef MOZ_CRASHREPORTER
    1885                 : static JSBool
    1886            4212 : DiagnosticMemoryCallback(void *ptr, size_t size)
    1887                 : {
    1888            4212 :     return CrashReporter::RegisterAppMemory(ptr, size) == NS_OK;
    1889                 : }
    1890                 : #endif
    1891                 : 
    1892                 : static void
    1893          147280 : AccumulateTelemetryCallback(int id, uint32_t sample)
    1894                 : {
    1895          147280 :     switch (id) {
    1896                 :       case JS_TELEMETRY_GC_REASON:
    1897           14728 :         Telemetry::Accumulate(Telemetry::GC_REASON, sample);
    1898           14728 :         break;
    1899                 :       case JS_TELEMETRY_GC_IS_COMPARTMENTAL:
    1900           14728 :         Telemetry::Accumulate(Telemetry::GC_IS_COMPARTMENTAL, sample);
    1901           14728 :         break;
    1902                 :       case JS_TELEMETRY_GC_MS:
    1903           14728 :         Telemetry::Accumulate(Telemetry::GC_MS, sample);
    1904           14728 :         break;
    1905                 :       case JS_TELEMETRY_GC_MARK_MS:
    1906           14728 :         Telemetry::Accumulate(Telemetry::GC_MARK_MS, sample);
    1907           14728 :         break;
    1908                 :       case JS_TELEMETRY_GC_SWEEP_MS:
    1909           14728 :         Telemetry::Accumulate(Telemetry::GC_SWEEP_MS, sample);
    1910           14728 :         break;
    1911                 :       case JS_TELEMETRY_GC_SLICE_MS:
    1912           14728 :         Telemetry::Accumulate(Telemetry::GC_SLICE_MS, sample);
    1913           14728 :         break;
    1914                 :       case JS_TELEMETRY_GC_MMU_50:
    1915           14728 :         Telemetry::Accumulate(Telemetry::GC_MMU_50, sample);
    1916           14728 :         break;
    1917                 :       case JS_TELEMETRY_GC_RESET:
    1918           14728 :         Telemetry::Accumulate(Telemetry::GC_RESET, sample);
    1919           14728 :         break;
    1920                 :       case JS_TELEMETRY_GC_INCREMENTAL_DISABLED:
    1921           14728 :         Telemetry::Accumulate(Telemetry::GC_INCREMENTAL_DISABLED, sample);
    1922           14728 :         break;
    1923                 :       case JS_TELEMETRY_GC_NON_INCREMENTAL:
    1924           14728 :         Telemetry::Accumulate(Telemetry::GC_NON_INCREMENTAL, sample);
    1925           14728 :         break;
    1926                 :     }
    1927          147280 : }
    1928                 : 
    1929                 : bool XPCJSRuntime::gNewDOMBindingsEnabled;
    1930                 : 
    1931               0 : bool PreserveWrapper(JSContext *cx, JSObject *obj)
    1932                 : {
    1933               0 :     JS_ASSERT(IS_WRAPPER_CLASS(js::GetObjectClass(obj)));
    1934               0 :     nsISupports *native = nsXPConnect::GetXPConnect()->GetNativeOfWrapper(cx, obj);
    1935               0 :     if (!native)
    1936               0 :         return false;
    1937                 :     nsresult rv;
    1938               0 :     nsCOMPtr<nsINode> node = do_QueryInterface(native, &rv);
    1939               0 :     if (NS_FAILED(rv))
    1940               0 :         return false;
    1941               0 :     nsContentUtils::PreserveWrapper(native, node);
    1942               0 :     return true;
    1943                 : }
    1944                 : 
    1945            1404 : XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
    1946                 :  : mXPConnect(aXPConnect),
    1947                 :    mJSRuntime(nsnull),
    1948                 :    mJSCycleCollectionContext(nsnull),
    1949            1404 :    mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)),
    1950            1404 :    mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)),
    1951            1404 :    mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_SIZE)),
    1952            1404 :    mClassInfo2NativeSetMap(ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
    1953            1404 :    mNativeSetMap(NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
    1954            1404 :    mThisTranslatorMap(IID2ThisTranslatorMap::newMap(XPC_THIS_TRANSLATOR_MAP_SIZE)),
    1955            1404 :    mNativeScriptableSharedMap(XPCNativeScriptableSharedMap::newMap(XPC_NATIVE_JSCLASS_MAP_SIZE)),
    1956            1404 :    mDyingWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_SIZE)),
    1957            1404 :    mDetachedWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DETACHED_NATIVE_PROTO_MAP_SIZE)),
    1958            1404 :    mExplicitNativeWrapperMap(XPCNativeWrapperMap::newMap(XPC_NATIVE_WRAPPER_MAP_SIZE)),
    1959            1404 :    mMapLock(XPCAutoLock::NewLock("XPCJSRuntime::mMapLock")),
    1960                 :    mThreadRunningGC(nsnull),
    1961                 :    mWrappedJSToReleaseArray(),
    1962                 :    mNativesToReleaseArray(),
    1963                 :    mDoingFinalization(false),
    1964                 :    mVariantRoots(nsnull),
    1965                 :    mWrappedJSRoots(nsnull),
    1966                 :    mObjectHolderRoots(nsnull),
    1967                 :    mWatchdogLock(nsnull),
    1968                 :    mWatchdogWakeup(nsnull),
    1969                 :    mWatchdogThread(nsnull),
    1970                 :    mWatchdogHibernating(false),
    1971           16848 :    mLastActiveTime(-1)
    1972                 : {
    1973                 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
    1974                 :     DEBUG_WrappedNativeHashtable =
    1975                 :         JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
    1976                 :                          sizeof(JSDHashEntryStub), 128);
    1977                 : #endif
    1978                 :     NS_TIME_FUNCTION;
    1979                 : 
    1980            1404 :     DOM_InitInterfaces();
    1981                 :     Preferences::AddBoolVarCache(&gNewDOMBindingsEnabled, "dom.new_bindings",
    1982            1404 :                                  false);
    1983                 : 
    1984                 : 
    1985                 :     // these jsids filled in later when we have a JSContext to work with.
    1986            1404 :     mStrIDs[0] = JSID_VOID;
    1987                 : 
    1988            1404 :     mJSRuntime = JS_NewRuntime(32L * 1024L * 1024L); // pref ?
    1989            1404 :     if (!mJSRuntime)
    1990               0 :         NS_RUNTIMEABORT("JS_NewRuntime failed.");
    1991                 : 
    1992                 :     // Unconstrain the runtime's threshold on nominal heap size, to avoid
    1993                 :     // triggering GC too often if operating continuously near an arbitrary
    1994                 :     // finite threshold (0xffffffff is infinity for uint32_t parameters).
    1995                 :     // This leaves the maximum-JS_malloc-bytes threshold still in effect
    1996                 :     // to cause period, and we hope hygienic, last-ditch GCs from within
    1997                 :     // the GC's allocator.
    1998            1404 :     JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff);
    1999                 : #ifdef MOZ_ASAN
    2000                 :     // ASan requires more stack space due to redzones
    2001                 :     JS_SetNativeStackQuota(mJSRuntime, 2 * 128 * sizeof(size_t) * 1024);
    2002                 : #else  
    2003            1404 :     JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024);
    2004                 : #endif
    2005            1404 :     JS_SetContextCallback(mJSRuntime, ContextCallback);
    2006            1404 :     JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback);
    2007            1404 :     JS_SetGCCallback(mJSRuntime, GCCallback);
    2008            1404 :     JS_SetFinalizeCallback(mJSRuntime, FinalizeCallback);
    2009            1404 :     JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
    2010            1404 :     JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
    2011                 :     JS_SetWrapObjectCallbacks(mJSRuntime,
    2012                 :                               xpc::WrapperFactory::Rewrap,
    2013            1404 :                               xpc::WrapperFactory::PrepareForWrapping);
    2014            1404 :     js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);
    2015                 : #ifdef MOZ_CRASHREPORTER
    2016            1404 :     JS_EnumerateDiagnosticMemoryRegions(DiagnosticMemoryCallback);
    2017                 : #endif
    2018            1404 :     JS_SetAccumulateTelemetryCallback(mJSRuntime, AccumulateTelemetryCallback);
    2019            1404 :     js::SetActivityCallback(mJSRuntime, ActivityCallback, this);
    2020                 :         
    2021            1404 :     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
    2022            1404 :     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
    2023            1404 :     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
    2024            1404 :     NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter);
    2025            1404 :     NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
    2026                 : 
    2027            1404 :     if (!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
    2028            1404 :                            sizeof(ObjectHolder), 512))
    2029               0 :         mJSHolders.ops = nsnull;
    2030                 : 
    2031            1404 :     mCompartmentMap.Init();
    2032                 : 
    2033                 :     // Install a JavaScript 'debugger' keyword handler in debug builds only
    2034                 : #ifdef DEBUG
    2035            1404 :     if (!JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
    2036            1404 :         xpc_InstallJSDebuggerKeywordHandler(mJSRuntime);
    2037                 : #endif
    2038                 : 
    2039            1404 :     mWatchdogLock = PR_NewLock();
    2040            1404 :     if (!mWatchdogLock)
    2041               0 :         NS_RUNTIMEABORT("PR_NewLock failed.");
    2042            1404 :     mWatchdogWakeup = PR_NewCondVar(mWatchdogLock);
    2043            1404 :     if (!mWatchdogWakeup)
    2044               0 :         NS_RUNTIMEABORT("PR_NewCondVar failed.");
    2045                 : 
    2046                 :     {
    2047            2808 :         AutoLockWatchdog lock(this);
    2048                 : 
    2049                 :         mWatchdogThread = PR_CreateThread(PR_USER_THREAD, WatchdogMain, this,
    2050                 :                                           PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
    2051            1404 :                                           PR_UNJOINABLE_THREAD, 0);
    2052            1404 :         if (!mWatchdogThread)
    2053               0 :             NS_RUNTIMEABORT("PR_CreateThread failed!");
    2054                 :     }
    2055            1404 : }
    2056                 : 
    2057                 : // static
    2058                 : XPCJSRuntime*
    2059            1404 : XPCJSRuntime::newXPCJSRuntime(nsXPConnect* aXPConnect)
    2060                 : {
    2061            1404 :     NS_PRECONDITION(aXPConnect,"bad param");
    2062                 : 
    2063            1404 :     XPCJSRuntime* self = new XPCJSRuntime(aXPConnect);
    2064                 : 
    2065           16848 :     if (self                                  &&
    2066            1404 :         self->GetJSRuntime()                  &&
    2067            1404 :         self->GetWrappedJSMap()               &&
    2068            1404 :         self->GetWrappedJSClassMap()          &&
    2069            1404 :         self->GetIID2NativeInterfaceMap()     &&
    2070            1404 :         self->GetClassInfo2NativeSetMap()     &&
    2071            1404 :         self->GetNativeSetMap()               &&
    2072            1404 :         self->GetThisTranslatorMap()          &&
    2073            1404 :         self->GetNativeScriptableSharedMap()  &&
    2074            1404 :         self->GetDyingWrappedNativeProtoMap() &&
    2075            1404 :         self->GetExplicitNativeWrapperMap()   &&
    2076            1404 :         self->GetMapLock()                    &&
    2077                 :         self->mWatchdogThread) {
    2078            1404 :         return self;
    2079                 :     }
    2080                 : 
    2081               0 :     NS_RUNTIMEABORT("new XPCJSRuntime failed to initialize.");
    2082                 : 
    2083               0 :     delete self;
    2084               0 :     return nsnull;
    2085                 : }
    2086                 : 
    2087                 : // InternStaticDictionaryJSVals is automatically generated.
    2088                 : bool InternStaticDictionaryJSVals(JSContext* aCx);
    2089                 : 
    2090                 : JSBool
    2091            7715 : XPCJSRuntime::OnJSContextNew(JSContext *cx)
    2092                 : {
    2093                 :     NS_TIME_FUNCTION;
    2094                 : 
    2095                 :     // if it is our first context then we need to generate our string ids
    2096            7715 :     JSBool ok = true;
    2097            7715 :     if (JSID_IS_VOID(mStrIDs[0])) {
    2098            1404 :         JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 16 * 1024 * 1024);
    2099                 :         {
    2100                 :             // Scope the JSAutoRequest so it goes out of scope before calling
    2101                 :             // mozilla::dom::binding::DefineStaticJSVals.
    2102            2808 :             JSAutoRequest ar(cx);
    2103           30888 :             for (unsigned i = 0; i < IDX_TOTAL_COUNT; i++) {
    2104           29484 :                 JSString* str = JS_InternString(cx, mStrings[i]);
    2105           29484 :                 if (!str || !JS_ValueToId(cx, STRING_TO_JSVAL(str), &mStrIDs[i])) {
    2106               0 :                     mStrIDs[0] = JSID_VOID;
    2107               0 :                     ok = false;
    2108               0 :                     break;
    2109                 :                 }
    2110           29484 :                 mStrJSVals[i] = STRING_TO_JSVAL(str);
    2111                 :             }
    2112                 :         }
    2113                 : 
    2114            1404 :         ok = mozilla::dom::binding::DefineStaticJSVals(cx);
    2115            1404 :         if (!ok)
    2116               0 :             return false;
    2117                 : 
    2118            1404 :         ok = InternStaticDictionaryJSVals(cx);
    2119                 :     }
    2120            7715 :     if (!ok)
    2121               0 :         return false;
    2122                 : 
    2123            7715 :     XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
    2124            7715 :     if (!tls)
    2125               0 :         return false;
    2126                 : 
    2127            7715 :     XPCContext* xpc = new XPCContext(this, cx);
    2128            7715 :     if (!xpc)
    2129               0 :         return false;
    2130                 : 
    2131                 :     // we want to mark the global object ourselves since we use a different color
    2132            7715 :     JS_ToggleOptions(cx, JSOPTION_UNROOTED_GLOBAL);
    2133                 : 
    2134            7715 :     return true;
    2135                 : }
    2136                 : 
    2137                 : JSBool
    2138         2408465 : XPCJSRuntime::DeferredRelease(nsISupports* obj)
    2139                 : {
    2140         2408465 :     NS_ASSERTION(obj, "bad param");
    2141                 : 
    2142         2408465 :     if (mNativesToReleaseArray.IsEmpty()) {
    2143                 :         // This array sometimes has 1000's
    2144                 :         // of entries, and usually has 50-200 entries. Avoid lots
    2145                 :         // of incremental grows.  We compact it down when we're done.
    2146            8772 :         mNativesToReleaseArray.SetCapacity(256);
    2147                 :     }
    2148         2408465 :     return mNativesToReleaseArray.AppendElement(obj) != nsnull;
    2149                 : }
    2150                 : 
    2151                 : /***************************************************************************/
    2152                 : 
    2153                 : #ifdef DEBUG
    2154                 : static JSDHashOperator
    2155               0 : WrappedJSClassMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
    2156                 :                                 uint32_t number, void *arg)
    2157                 : {
    2158               0 :     ((IID2WrappedJSClassMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
    2159               0 :     return JS_DHASH_NEXT;
    2160                 : }
    2161                 : static JSDHashOperator
    2162               0 : WrappedJSMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
    2163                 :                            uint32_t number, void *arg)
    2164                 : {
    2165               0 :     ((JSObject2WrappedJSMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
    2166               0 :     return JS_DHASH_NEXT;
    2167                 : }
    2168                 : static JSDHashOperator
    2169               0 : NativeSetDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
    2170                 :                         uint32_t number, void *arg)
    2171                 : {
    2172               0 :     ((NativeSetMap::Entry*)hdr)->key_value->DebugDump(*(PRInt16*)arg);
    2173               0 :     return JS_DHASH_NEXT;
    2174                 : }
    2175                 : #endif
    2176                 : 
    2177                 : void
    2178               0 : XPCJSRuntime::DebugDump(PRInt16 depth)
    2179                 : {
    2180                 : #ifdef DEBUG
    2181               0 :     depth--;
    2182               0 :     XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
    2183               0 :         XPC_LOG_INDENT();
    2184               0 :         XPC_LOG_ALWAYS(("mXPConnect @ %x", mXPConnect));
    2185               0 :         XPC_LOG_ALWAYS(("mJSRuntime @ %x", mJSRuntime));
    2186               0 :         XPC_LOG_ALWAYS(("mMapLock @ %x", mMapLock));
    2187                 : 
    2188               0 :         XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)", \
    2189                 :                         &mWrappedJSToReleaseArray,
    2190                 :                         mWrappedJSToReleaseArray.Length()));
    2191                 : 
    2192               0 :         int cxCount = 0;
    2193               0 :         JSContext* iter = nsnull;
    2194               0 :         while (JS_ContextIterator(mJSRuntime, &iter))
    2195               0 :             ++cxCount;
    2196               0 :         XPC_LOG_ALWAYS(("%d JS context(s)", cxCount));
    2197                 : 
    2198               0 :         iter = nsnull;
    2199               0 :         while (JS_ContextIterator(mJSRuntime, &iter)) {
    2200               0 :             XPCContext *xpc = XPCContext::GetXPCContext(iter);
    2201               0 :             XPC_LOG_INDENT();
    2202               0 :             xpc->DebugDump(depth);
    2203               0 :             XPC_LOG_OUTDENT();
    2204                 :         }
    2205                 : 
    2206               0 :         XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)",  \
    2207                 :                         mWrappedJSClassMap, mWrappedJSClassMap ?              \
    2208                 :                         mWrappedJSClassMap->Count() : 0));
    2209                 :         // iterate wrappersclasses...
    2210               0 :         if (depth && mWrappedJSClassMap && mWrappedJSClassMap->Count()) {
    2211               0 :             XPC_LOG_INDENT();
    2212               0 :             mWrappedJSClassMap->Enumerate(WrappedJSClassMapDumpEnumerator, &depth);
    2213               0 :             XPC_LOG_OUTDENT();
    2214                 :         }
    2215               0 :         XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)",             \
    2216                 :                         mWrappedJSMap, mWrappedJSMap ?                        \
    2217                 :                         mWrappedJSMap->Count() : 0));
    2218                 :         // iterate wrappers...
    2219               0 :         if (depth && mWrappedJSMap && mWrappedJSMap->Count()) {
    2220               0 :             XPC_LOG_INDENT();
    2221               0 :             mWrappedJSMap->Enumerate(WrappedJSMapDumpEnumerator, &depth);
    2222               0 :             XPC_LOG_OUTDENT();
    2223                 :         }
    2224                 : 
    2225               0 :         XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %x with %d interface(s)",  \
    2226                 :                         mIID2NativeInterfaceMap, mIID2NativeInterfaceMap ?    \
    2227                 :                         mIID2NativeInterfaceMap->Count() : 0));
    2228                 : 
    2229               0 :         XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %x with %d sets(s)",       \
    2230                 :                         mClassInfo2NativeSetMap, mClassInfo2NativeSetMap ?    \
    2231                 :                         mClassInfo2NativeSetMap->Count() : 0));
    2232                 : 
    2233               0 :         XPC_LOG_ALWAYS(("mThisTranslatorMap @ %x with %d translator(s)",      \
    2234                 :                         mThisTranslatorMap, mThisTranslatorMap ?              \
    2235                 :                         mThisTranslatorMap->Count() : 0));
    2236                 : 
    2237               0 :         XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)",                 \
    2238                 :                         mNativeSetMap, mNativeSetMap ?                        \
    2239                 :                         mNativeSetMap->Count() : 0));
    2240                 : 
    2241                 :         // iterate sets...
    2242               0 :         if (depth && mNativeSetMap && mNativeSetMap->Count()) {
    2243               0 :             XPC_LOG_INDENT();
    2244               0 :             mNativeSetMap->Enumerate(NativeSetDumpEnumerator, &depth);
    2245               0 :             XPC_LOG_OUTDENT();
    2246                 :         }
    2247                 : 
    2248               0 :         XPC_LOG_OUTDENT();
    2249                 : #endif
    2250               0 : }
    2251                 : 
    2252                 : /***************************************************************************/
    2253                 : 
    2254                 : void
    2255          117513 : XPCRootSetElem::AddToRootSet(XPCLock *lock, XPCRootSetElem **listHead)
    2256                 : {
    2257          117513 :     NS_ASSERTION(!mSelfp, "Must be not linked");
    2258                 : 
    2259          235026 :     XPCAutoLock autoLock(lock);
    2260                 : 
    2261          117513 :     mSelfp = listHead;
    2262          117513 :     mNext = *listHead;
    2263          117513 :     if (mNext) {
    2264          114086 :         NS_ASSERTION(mNext->mSelfp == listHead, "Must be list start");
    2265          114086 :         mNext->mSelfp = &mNext;
    2266                 :     }
    2267          117513 :     *listHead = this;
    2268          117513 : }
    2269                 : 
    2270                 : void
    2271          117232 : XPCRootSetElem::RemoveFromRootSet(XPCLock *lock)
    2272                 : {
    2273          117232 :     NS_ASSERTION(mSelfp, "Must be linked");
    2274                 : 
    2275          234464 :     XPCAutoLock autoLock(lock);
    2276                 : 
    2277          117232 :     NS_ASSERTION(*mSelfp == this, "Link invariant");
    2278          117232 :     *mSelfp = mNext;
    2279          117232 :     if (mNext)
    2280          110746 :         mNext->mSelfp = mSelfp;
    2281                 : #ifdef DEBUG
    2282          117232 :     mSelfp = nsnull;
    2283          117232 :     mNext = nsnull;
    2284                 : #endif
    2285          117232 : }
    2286                 : 
    2287                 : void
    2288               0 : XPCJSRuntime::AddGCCallback(JSGCCallback cb)
    2289                 : {
    2290               0 :     NS_ASSERTION(cb, "null callback");
    2291               0 :     extraGCCallbacks.AppendElement(cb);
    2292               0 : }
    2293                 : 
    2294                 : void
    2295               0 : XPCJSRuntime::RemoveGCCallback(JSGCCallback cb)
    2296                 : {
    2297               0 :     NS_ASSERTION(cb, "null callback");
    2298               0 :     bool found = extraGCCallbacks.RemoveElement(cb);
    2299               0 :     if (!found) {
    2300               0 :         NS_ERROR("Removing a callback which was never added.");
    2301                 :     }
    2302               0 : }

Generated by: LCOV version 1.7