LCOV - app.info - js/xpconnect/src/XPCJSRuntime.cpp

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-07-07 | 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          198068 : WrappedJSDyingJSObjectFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
         102                 :                              uint32_t number, void *arg)
         103                 : {
         104          198068 :     nsTArray<nsXPCWrappedJS*>* array = static_cast<nsTArray<nsXPCWrappedJS*>*>(arg);
         105          198068 :     nsXPCWrappedJS* wrapper = ((JSObject2WrappedJSMap::Entry*)hdr)->value;
         106          198068 :     NS_ASSERTION(wrapper, "found a null JS wrapper!");
         107                 :
         108                 :     // walk the wrapper chain and find any whose JSObject is to be finalized
         109          613234 :     while (wrapper) {
         110          217098 :         if (wrapper->IsSubjectToFinalization()) {
         111           65010 :             if (JS_IsAboutToBeFinalized(wrapper->GetJSObjectPreserveColor()))
         112            5509 :                 array->AppendElement(wrapper);
         113                 :         }
         114          217098 :         wrapper = wrapper->GetNextWrapper();
         115                 :     }
         116          198068 :     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          403238 : NativeInterfaceSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
         127                 :                        uint32_t number, void *arg)
         128                 : {
         129          403238 :     XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
         130          403238 :     if (iface->IsMarked()) {
         131          275855 :         iface->Unmark();
         132          275855 :         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          127383 :     XPCNativeInterface::DestroyInstance(iface);
         142          127383 :     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          716828 : NativeUnMarkedSetRemover(JSDHashTable *table, JSDHashEntryHdr *hdr,
         152                 :                          uint32_t number, void *arg)
         153                 : {
         154          716828 :     XPCNativeSet* set = ((ClassInfo2NativeSetMap::Entry*)hdr)->value;
         155          716828 :     if (set->IsMarked())
         156          680473 :         return JS_DHASH_NEXT;
         157           36355 :     return JS_DHASH_REMOVE;
         158                 : }
         159                 :
         160                 : static JSDHashOperator
         161          337009 : NativeSetSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
         162                 :                  uint32_t number, void *arg)
         163                 : {
         164          337009 :     XPCNativeSet* set = ((NativeSetMap::Entry*)hdr)->key_value;
         165          337009 :     if (set->IsMarked()) {
         166          221817 :         set->Unmark();
         167          221817 :         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          115192 :     XPCNativeSet::DestroyInstance(set);
         182          115192 :     return JS_DHASH_REMOVE;
         183                 : }
         184                 :
         185                 : static JSDHashOperator
         186          122162 : JSClassSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
         187                 :                uint32_t number, void *arg)
         188                 : {
         189                 :     XPCNativeScriptableShared* shared =
         190          122162 :         ((XPCNativeScriptableSharedMap::Entry*) hdr)->key;
         191          122162 :     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          101051 :         shared->Unmark();
         198          101051 :         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           21111 :     delete shared;
         208           21111 :     return JS_DHASH_REMOVE;
         209                 : }
         210                 :
         211                 : static JSDHashOperator
         212          186759 : DyingProtoKiller(JSDHashTable *table, JSDHashEntryHdr *hdr,
         213                 :                  uint32_t number, void *arg)
         214                 : {
         215                 :     XPCWrappedNativeProto* proto =
         216          186759 :         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
         217          186759 :     delete proto;
         218          186759 :     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            7453 : XPCJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer)
         289                 : {
         290            7453 :     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            7453 :                                                              JS_DHASH_ADD));
         297            7453 :     if (!entry)
         298               0 :         return NS_ERROR_OUT_OF_MEMORY;
         299                 :
         300            7453 :     entry->holder = aHolder;
         301            7453 :     entry->tracer = aTracer;
         302                 :
         303            7453 :     return NS_OK;
         304                 : }
         305                 :
         306                 : nsresult
         307            7451 : XPCJSRuntime::RemoveJSHolder(void* aHolder)
         308                 : {
         309            7451 :     if (!mJSHolders.ops)
         310               0 :         return NS_ERROR_OUT_OF_MEMORY;
         311                 :
         312            7451 :     JS_DHashTableOperate(&mJSHolders, aHolder, JS_DHASH_REMOVE);
         313                 :
         314            7451 :     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            5833 : TraceJSObject(PRUint32 aLangID, void *aScriptThing, const char *name,
         363                 :               void *aClosure)
         364                 : {
         365            5833 :     if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
         366            5833 :         JS_CALL_TRACER(static_cast<JSTracer*>(aClosure), aScriptThing,
         367                 :                        js_GetGCThingTraceKind(aScriptThing), name);
         368                 :     }
         369            5833 : }
         370                 :
         371                 : static JSDHashOperator
         372            5210 : TraceJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
         373                 :               void *arg)
         374                 : {
         375            5210 :     ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
         376                 :
         377            5210 :     entry->tracer->Trace(entry->holder, TraceJSObject, arg);
         378                 :
         379            5210 :     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           27299 : TraceCompartment(xpc::PtrAndPrincipalHashKey *aKey, JSCompartment *compartment, void *aClosure)
         407                 : {
         408                 :     xpc::CompartmentPrivate *priv =
         409           27299 :         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
         410           27299 :     if (priv->expandoMap)
         411               0 :         priv->expandoMap->Enumerate(TraceExpandos, aClosure);
         412           27299 :     if (priv->domExpandoMap)
         413               0 :         priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, aClosure);
         414           27299 :     return PL_DHASH_NEXT;
         415                 : }
         416                 :
         417           14728 : void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
         418                 : {
         419           14728 :     JSContext *iter = nsnull;
         420           81172 :     while (JSContext *acx = JS_ContextIterator(GetJSRuntime(), &iter)) {
         421           33222 :         JS_ASSERT(js::HasUnrootedGlobal(acx));
         422           33222 :         if (JSObject *global = JS_GetGlobalObject(acx))
         423           26309 :             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          166816 :     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot())
         434          152088 :         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             647 : CheckParticipatesInCycleCollection(PRUint32 aLangID, void *aThing,
         451                 :                                    const char *name, void *aClosure)
         452                 : {
         453             647 :     Closure *closure = static_cast<Closure*>(aClosure);
         454                 :
         455                 :     closure->cycleCollectionEnabled =
         456                 :         aLangID == nsIProgrammingLanguage::JAVASCRIPT &&
         457             647 :         AddToCCKind(js_GetGCThingTraceKind(aThing));
         458             647 : }
         459                 :
         460                 : static JSDHashOperator
         461             622 : NoteJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
         462                 :              void *arg)
         463                 : {
         464             622 :     ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
         465             622 :     Closure *closure = static_cast<Closure*>(arg);
         466                 :
         467                 :     entry->tracer->Trace(entry->holder, CheckParticipatesInCycleCollection,
         468             622 :                          closure);
         469             622 :     if (!closure->cycleCollectionEnabled)
         470               1 :         return JS_DHASH_NEXT;
         471                 :
         472                 :     closure->cb->NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, entry->holder,
         473             621 :                           entry->tracer);
         474                 :
         475             621 :     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              71 :                     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            3826 : SuspectCompartment(xpc::PtrAndPrincipalHashKey *key, JSCompartment *compartment, void *arg)
         516                 : {
         517                 :     xpc::CompartmentPrivate *priv =
         518            3826 :         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
         519            3826 :     if (priv->expandoMap)
         520               0 :         priv->expandoMap->EnumerateRead(SuspectExpandos, arg);
         521            3826 :     if (priv->domExpandoMap)
         522               0 :         priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, arg);
         523            3826 :     return PL_DHASH_NEXT;
         524                 : }
         525                 :
         526                 : void
         527            1909 : 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            1909 :     JSContext *iter = nsnull, *acx;
         538            9112 :     while ((acx = JS_ContextIterator(GetJSRuntime(), &iter))) {
         539                 :         cb.NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, acx,
         540            5294 :                     nsXPConnect::JSContextParticipant());
         541                 :     }
         542                 :
         543            3818 :     XPCAutoLock lock(mMapLock);
         544                 :
         545            1909 :     XPCWrappedNativeScope::SuspectAllWrappers(this, cb);
         546                 :
         547            1909 :     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           10151 :     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) {
         559            8242 :         nsXPCWrappedJS *wrappedJS = static_cast<nsXPCWrappedJS*>(e);
         560            8242 :         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           15028 :         if (nsCCUncollectableMarker::sGeneration &&
         565            3460 :             !cb.WantAllTraces() && (!obj || !xpc_IsGrayGCThing(obj)) &&
         566            1150 :             !wrappedJS->IsSubjectToFinalization() &&
         567            1150 :             wrappedJS->GetRootWrapper() == wrappedJS &&
         568            1026 :             !wrappedJS->IsAggregatedToNative()) {
         569            1026 :             continue;
         570                 :         }
         571                 :
         572            7216 :         cb.NoteXPCOMRoot(static_cast<nsIXPConnectWrappedJS *>(wrappedJS));
         573                 :     }
         574                 :
         575            1909 :     Closure closure = { true, &cb };
         576            1909 :     if (mJSHolders.ops) {
         577            1909 :         JS_DHashTableEnumerate(&mJSHolders, NoteJSHolder, &closure);
         578                 :     }
         579                 :
         580                 :     // Suspect wrapped natives with expando objects.
         581            1909 :     GetCompartmentMap().EnumerateRead(SuspectCompartment, &closure);
         582            1909 : }
         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         2442869 : DoDeferredRelease(nsTArray<T> &array)
         613                 : {
         614         2413413 :     while (1) {
         615         2442869 :         PRUint32 count = array.Length();
         616         2442869 :         if (!count) {
         617           29456 :             array.Compact();
         618                 :             break;
         619                 :         }
         620         2413413 :         T wrapper = array[count-1];
         621         2413413 :         array.RemoveElementAt(count-1);
         622         2413413 :         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           27299 : SweepCompartment(nsCStringHashKey& aKey, JSCompartment *compartment, void *aClosure)
         648                 : {
         649           27299 :     MOZ_ASSERT(!aClosure);
         650                 :     xpc::CompartmentPrivate *priv =
         651           27299 :         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
         652           27299 :     if (priv->waiverWrapperMap)
         653               0 :         priv->waiverWrapperMap->Enumerate(SweepWaiverWrappers, nsnull);
         654           27299 :     if (priv->expandoMap)
         655               0 :         priv->expandoMap->Enumerate(SweepExpandos, nsnull);
         656           27299 :     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           81172 :             while (JSContext *acx = JS_ContextIterator(rt, &iter)) {
         673           33222 :                 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            3886 :                                 XPCNativeSet* set = ccxp->GetSet();
         798            3886 :                                 if (set)
         799            3886 :                                     set->Mark();
         800                 :                             }
         801            9786 :                             if (ccxp->CanGetInterface()) {
         802            3886 :                                 XPCNativeInterface* iface = ccxp->GetInterface();
         803            3886 :                                 if (iface)
         804            3886 :                                     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            3974 :                                         ccxp->GetTearOff();
         886            3974 :                                     if (to)
         887            3876 :                                         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          779955 :     AutoLockWatchdog(XPCJSRuntime* aRuntime)
         936          779955 :       : mRuntime(aRuntime) {
         937          779955 :         PR_Lock(mRuntime->mWatchdogLock);
         938          779955 :     }
         939                 :
         940          779954 :     ~AutoLockWatchdog() {
         941          779954 :         PR_Unlock(mRuntime->mWatchdogLock);
         942          779954 :     }
         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            6044 :     while (self->mWatchdogThread) {
         956                 :         // Sleep only 1 second if recently (or currently) active; otherwise, hibernate
         957            3237 :         if (self->mLastActiveTime == -1 || PR_Now() - self->mLastActiveTime <= PRTime(2*PR_USEC_PER_SEC))
         958            3236 :             sleepInterval = PR_TicksPerSecond();
         959                 :         else {
         960               1 :             sleepInterval = PR_INTERVAL_NO_TIMEOUT;
         961               1 :             self->mWatchdogHibernating = true;
         962                 :         }
         963            3237 :         MOZ_ALWAYS_TRUE(PR_WaitCondVar(self->mWatchdogWakeup, sleepInterval) == PR_SUCCESS);
         964            3236 :         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          775744 : XPCJSRuntime::ActivityCallback(void *arg, JSBool active)
         974                 : {
         975          775744 :     XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
         976                 :
         977         1551488 :     AutoLockWatchdog lock(self);
         978                 :
         979          775744 :     if (active) {
         980          387872 :         self->mLastActiveTime = -1;
         981          387872 :         if (self->mWatchdogHibernating) {
         982               1 :             self->mWatchdogHibernating = false;
         983               1 :             PR_NotifyCondVar(self->mWatchdogWakeup);
         984                 :         }
         985                 :     } else {
         986          387872 :         self->mLastActiveTime = PR_Now();
         987                 :     }
         988          775744 : }
         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            1909 : XPCJSRuntime::GetJSCycleCollectionContext()
        1059                 : {
        1060            1909 :     if (!mJSCycleCollectionContext) {
        1061            1404 :         mJSCycleCollectionContext = JS_NewContext(mJSRuntime, 0);
        1062            1404 :         if (!mJSCycleCollectionContext)
        1063               0 :             return nsnull;
        1064                 :     }
        1065            1909 :     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           42952 : 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         2407904 : XPCJSRuntime::DeferredRelease(nsISupports* obj)
        2139                 : {
        2140         2407904 :     NS_ASSERTION(obj, "bad param");
        2141                 :
        2142         2407904 :     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            8774 :         mNativesToReleaseArray.SetCapacity(256);
        2147                 :     }
        2148         2407904 :     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          117819 : XPCRootSetElem::AddToRootSet(XPCLock *lock, XPCRootSetElem **listHead)
        2256                 : {
        2257          117819 :     NS_ASSERTION(!mSelfp, "Must be not linked");
        2258                 :
        2259          235638 :     XPCAutoLock autoLock(lock);
        2260                 :
        2261          117819 :     mSelfp = listHead;
        2262          117819 :     mNext = *listHead;
        2263          117819 :     if (mNext) {
        2264          114392 :         NS_ASSERTION(mNext->mSelfp == listHead, "Must be list start");
        2265          114392 :         mNext->mSelfp = &mNext;
        2266                 :     }
        2267          117819 :     *listHead = this;
        2268          117819 : }
        2269                 :
        2270                 : void
        2271          117538 : XPCRootSetElem::RemoveFromRootSet(XPCLock *lock)
        2272                 : {
        2273          117538 :     NS_ASSERTION(mSelfp, "Must be linked");
        2274                 :
        2275          235076 :     XPCAutoLock autoLock(lock);
        2276                 :
        2277          117538 :     NS_ASSERTION(*mSelfp == this, "Link invariant");
        2278          117538 :     *mSelfp = mNext;
        2279          117538 :     if (mNext)
        2280          111010 :         mNext->mSelfp = mSelfp;
        2281                 : #ifdef DEBUG
        2282          117538 :     mSelfp = nsnull;
        2283          117538 :     mNext = nsnull;
        2284                 : #endif
        2285          117538 : }
        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