LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCJSRuntime.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 123 1184 10.4 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* Per JSRuntime object */
       8             : 
       9             : #include "mozilla/MemoryReporting.h"
      10             : #include "mozilla/UniquePtr.h"
      11             : 
      12             : #include "xpcprivate.h"
      13             : #include "xpcpublic.h"
      14             : #include "XPCWrapper.h"
      15             : #include "XPCJSMemoryReporter.h"
      16             : #include "XrayWrapper.h"
      17             : #include "WrapperFactory.h"
      18             : #include "mozJSComponentLoader.h"
      19             : #include "nsAutoPtr.h"
      20             : #include "nsNetUtil.h"
      21             : 
      22             : #include "nsExceptionHandler.h"
      23             : #include "nsIMemoryInfoDumper.h"
      24             : #include "nsIMemoryReporter.h"
      25             : #include "nsIObserverService.h"
      26             : #include "nsIDebug2.h"
      27             : #include "nsIDocShell.h"
      28             : #include "nsIRunnable.h"
      29             : #include "nsPIDOMWindow.h"
      30             : #include "nsPrintfCString.h"
      31             : #include "nsWindowSizes.h"
      32             : #include "mozilla/Preferences.h"
      33             : #include "mozilla/Telemetry.h"
      34             : #include "mozilla/Services.h"
      35             : #include "mozilla/dom/ScriptLoader.h"
      36             : #include "mozilla/dom/ScriptSettings.h"
      37             : 
      38             : #include "nsContentUtils.h"
      39             : #include "nsCCUncollectableMarker.h"
      40             : #include "nsCycleCollectionNoteRootCallback.h"
      41             : #include "nsCycleCollector.h"
      42             : #include "jsapi.h"
      43             : #include "js/MemoryMetrics.h"
      44             : #include "mozilla/dom/GeneratedAtomList.h"
      45             : #include "mozilla/dom/BindingUtils.h"
      46             : #include "mozilla/dom/Element.h"
      47             : #include "mozilla/dom/WindowBinding.h"
      48             : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
      49             : #include "mozilla/Atomics.h"
      50             : #include "mozilla/Attributes.h"
      51             : #include "mozilla/ProcessHangMonitor.h"
      52             : #include "mozilla/Sprintf.h"
      53             : #include "mozilla/UniquePtrExtensions.h"
      54             : #include "mozilla/Unused.h"
      55             : #include "AccessCheck.h"
      56             : #include "nsGlobalWindow.h"
      57             : #include "nsAboutProtocolUtils.h"
      58             : 
      59             : #include "GeckoProfiler.h"
      60             : #include "nsIInputStream.h"
      61             : #include "nsIXULRuntime.h"
      62             : #include "nsJSPrincipals.h"
      63             : 
      64             : #ifdef XP_WIN
      65             : #include <windows.h>
      66             : #endif
      67             : 
      68             : using namespace mozilla;
      69             : using namespace xpc;
      70             : using namespace JS;
      71             : using mozilla::dom::PerThreadAtomCache;
      72             : using mozilla::dom::AutoEntryScript;
      73             : 
      74             : /***************************************************************************/
      75             : 
      76             : const char* const XPCJSRuntime::mStrings[] = {
      77             :     "constructor",          // IDX_CONSTRUCTOR
      78             :     "toString",             // IDX_TO_STRING
      79             :     "toSource",             // IDX_TO_SOURCE
      80             :     "lastResult",           // IDX_LAST_RESULT
      81             :     "returnCode",           // IDX_RETURN_CODE
      82             :     "value",                // IDX_VALUE
      83             :     "QueryInterface",       // IDX_QUERY_INTERFACE
      84             :     "Components",           // IDX_COMPONENTS
      85             :     "Cc",                   // IDX_CC
      86             :     "Ci",                   // IDX_CI
      87             :     "Cr",                   // IDX_CR
      88             :     "Cu",                   // IDX_CU
      89             :     "wrappedJSObject",      // IDX_WRAPPED_JSOBJECT
      90             :     "Object",               // IDX_OBJECT
      91             :     "Function",             // IDX_FUNCTION
      92             :     "prototype",            // IDX_PROTOTYPE
      93             :     "createInstance",       // IDX_CREATE_INSTANCE
      94             :     "item",                 // IDX_ITEM
      95             :     "__proto__",            // IDX_PROTO
      96             :     "eval",                 // IDX_EVAL
      97             :     "controllers",          // IDX_CONTROLLERS
      98             :     "Controllers",          // IDX_CONTROLLERS_CLASS
      99             :     "realFrameElement",     // IDX_REALFRAMEELEMENT
     100             :     "length",               // IDX_LENGTH
     101             :     "name",                 // IDX_NAME
     102             :     "undefined",            // IDX_UNDEFINED
     103             :     "",                     // IDX_EMPTYSTRING
     104             :     "fileName",             // IDX_FILENAME
     105             :     "lineNumber",           // IDX_LINENUMBER
     106             :     "columnNumber",         // IDX_COLUMNNUMBER
     107             :     "stack",                // IDX_STACK
     108             :     "message",              // IDX_MESSAGE
     109             :     "lastIndex",            // IDX_LASTINDEX
     110             :     "then",                 // IDX_THEN
     111             :     "isInstance",           // IDX_ISINSTANCE
     112             : };
     113             : 
     114             : /***************************************************************************/
     115             : 
     116             : // *Some* NativeSets are referenced from mClassInfo2NativeSetMap.
     117             : // *All* NativeSets are referenced from mNativeSetMap.
     118             : // So, in mClassInfo2NativeSetMap we just clear references to the unmarked.
     119             : // In mNativeSetMap we clear the references to the unmarked *and* delete them.
     120             : 
     121           0 : class AsyncFreeSnowWhite : public Runnable
     122             : {
     123             : public:
     124           0 :   NS_IMETHOD Run() override
     125             :   {
     126           0 :       AUTO_PROFILER_LABEL("AsyncFreeSnowWhite::Run", GCCC);
     127             :       
     128           0 :       TimeStamp start = TimeStamp::Now();
     129           0 :       bool hadSnowWhiteObjects = nsCycleCollector_doDeferredDeletion();
     130           0 :       Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_ASYNC_SNOW_WHITE_FREEING,
     131           0 :                             uint32_t((TimeStamp::Now() - start).ToMilliseconds()));
     132           0 :       if (hadSnowWhiteObjects && !mContinuation) {
     133           0 :           mContinuation = true;
     134           0 :           if (NS_FAILED(Dispatch())) {
     135           0 :               mActive = false;
     136             :           }
     137             :       } else {
     138           0 :           mActive = false;
     139             :       }
     140           0 :       return NS_OK;
     141             :   }
     142             : 
     143           0 :   nsresult Dispatch()
     144             :   {
     145           0 :       nsCOMPtr<nsIRunnable> self(this);
     146           0 :       return NS_IdleDispatchToCurrentThread(self.forget(), 2500);
     147             :   }
     148             : 
     149           0 :   void Start(bool aContinuation = false, bool aPurge = false)
     150             :   {
     151           0 :       if (mContinuation) {
     152           0 :           mContinuation = aContinuation;
     153             :       }
     154           0 :       mPurge = aPurge;
     155           0 :       if (!mActive && NS_SUCCEEDED(Dispatch())) {
     156           0 :           mActive = true;
     157             :       }
     158           0 :   }
     159             : 
     160           1 :   AsyncFreeSnowWhite()
     161           0 :     : Runnable("AsyncFreeSnowWhite")
     162             :     , mContinuation(false)
     163             :     , mActive(false)
     164           1 :     , mPurge(false) {}
     165             : 
     166             : public:
     167             :   bool mContinuation;
     168             :   bool mActive;
     169             :   bool mPurge;
     170             : };
     171             : 
     172             : namespace xpc {
     173             : 
     174          38 : CompartmentPrivate::CompartmentPrivate(JS::Compartment* c)
     175             :     : wantXrays(false)
     176             :     , allowWaivers(true)
     177             :     , isWebExtensionContentScript(false)
     178             :     , allowCPOWs(false)
     179             :     , isContentXBLCompartment(false)
     180             :     , isAddonCompartment(false)
     181             :     , universalXPConnectEnabled(false)
     182             :     , forcePermissiveCOWs(false)
     183             :     , wasNuked(false)
     184           0 :     , mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH))
     185             : {
     186          38 :     MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
     187           0 :     mozilla::PodArrayZero(wrapperDenialWarnings);
     188          38 : }
     189             : 
     190           0 : CompartmentPrivate::~CompartmentPrivate()
     191             : {
     192           0 :     MOZ_COUNT_DTOR(xpc::CompartmentPrivate);
     193           0 :     delete mWrappedJSMap;
     194           0 : }
     195             : 
     196             : void
     197           0 : CompartmentPrivate::SystemIsBeingShutDown()
     198             : {
     199           0 :     mWrappedJSMap->ShutdownMarker();
     200           0 : }
     201             : 
     202          38 : RealmPrivate::RealmPrivate(JS::Realm* realm)
     203             :     : scriptability(realm)
     204          76 :     , scope(nullptr)
     205             : {
     206           1 : }
     207             : 
     208             : static bool
     209           0 : TryParseLocationURICandidate(const nsACString& uristr,
     210             :                              RealmPrivate::LocationHint aLocationHint,
     211             :                              nsIURI** aURI)
     212             : {
     213             :     static NS_NAMED_LITERAL_CSTRING(kGRE, "resource://gre/");
     214             :     static NS_NAMED_LITERAL_CSTRING(kToolkit, "chrome://global/");
     215             :     static NS_NAMED_LITERAL_CSTRING(kBrowser, "chrome://browser/");
     216             : 
     217           0 :     if (aLocationHint == RealmPrivate::LocationHintAddon) {
     218             :         // Blacklist some known locations which are clearly not add-on related.
     219           0 :         if (StringBeginsWith(uristr, kGRE) ||
     220           0 :             StringBeginsWith(uristr, kToolkit) ||
     221           0 :             StringBeginsWith(uristr, kBrowser))
     222             :             return false;
     223             : 
     224             :         // -- GROSS HACK ALERT --
     225             :         // The Yandex Elements 8.10.2 extension implements its own "xb://" URL
     226             :         // scheme. If we call NS_NewURI() on an "xb://..." URL, we'll end up
     227             :         // calling into the extension's own JS-implemented nsIProtocolHandler
     228             :         // object, which we can't allow while we're iterating over the JS heap.
     229             :         // So just skip any such URL.
     230             :         // -- GROSS HACK ALERT --
     231           0 :         if (StringBeginsWith(uristr, NS_LITERAL_CSTRING("xb")))
     232             :             return false;
     233             :     }
     234             : 
     235           0 :     nsCOMPtr<nsIURI> uri;
     236           0 :     if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), uristr)))
     237             :         return false;
     238             : 
     239           0 :     nsAutoCString scheme;
     240           0 :     if (NS_FAILED(uri->GetScheme(scheme)))
     241             :         return false;
     242             : 
     243             :     // Cannot really map data: and blob:.
     244             :     // Also, data: URIs are pretty memory hungry, which is kinda bad
     245             :     // for memory reporter use.
     246           0 :     if (scheme.EqualsLiteral("data") || scheme.EqualsLiteral("blob"))
     247             :         return false;
     248             : 
     249           0 :     uri.forget(aURI);
     250           0 :     return true;
     251             : }
     252             : 
     253             : bool
     254           0 : RealmPrivate::TryParseLocationURI(RealmPrivate::LocationHint aLocationHint,
     255             :                                   nsIURI** aURI)
     256             : {
     257           0 :     if (!aURI)
     258             :         return false;
     259             : 
     260             :     // Need to parse the URI.
     261           0 :     if (location.IsEmpty())
     262             :         return false;
     263             : 
     264             :     // Handle Sandbox location strings.
     265             :     // A sandbox string looks like this, for anonymous sandboxes, and builds
     266             :     // where Sandbox location tagging is enabled:
     267             :     //
     268             :     // <sandboxName> (from: <js-stack-frame-filename>:<lineno>)
     269             :     //
     270             :     // where <sandboxName> is user-provided via Cu.Sandbox()
     271             :     // and <js-stack-frame-filename> and <lineno> is the stack frame location
     272             :     // from where Cu.Sandbox was called.
     273             :     //
     274             :     // Otherwise, it is simply the caller-provided name, which is usually a URI.
     275             :     //
     276             :     // <js-stack-frame-filename> furthermore is "free form", often using a
     277             :     // "uri -> uri -> ..." chain. The following code will and must handle this
     278             :     // common case.
     279             :     //
     280             :     // It should be noted that other parts of the code may already rely on the
     281             :     // "format" of these strings.
     282             : 
     283           0 :     static const nsDependentCString from("(from: ");
     284           0 :     static const nsDependentCString arrow(" -> ");
     285           0 :     static const size_t fromLength = from.Length();
     286           0 :     static const size_t arrowLength = arrow.Length();
     287             : 
     288             :     // See: XPCComponents.cpp#AssembleSandboxMemoryReporterName
     289           0 :     int32_t idx = location.Find(from);
     290           0 :     if (idx < 0)
     291           0 :         return TryParseLocationURICandidate(location, aLocationHint, aURI);
     292             : 
     293             : 
     294             :     // When parsing we're looking for the right-most URI. This URI may be in
     295             :     // <sandboxName>, so we try this first.
     296           0 :     if (TryParseLocationURICandidate(Substring(location, 0, idx), aLocationHint,
     297             :                                      aURI))
     298             :         return true;
     299             : 
     300             :     // Not in <sandboxName> so we need to inspect <js-stack-frame-filename> and
     301             :     // the chain that is potentially contained within and grab the rightmost
     302             :     // item that is actually a URI.
     303             : 
     304             :     // First, hack off the :<lineno>) part as well
     305           0 :     int32_t ridx = location.RFind(NS_LITERAL_CSTRING(":"));
     306           0 :     nsAutoCString chain(Substring(location, idx + fromLength,
     307           0 :                                   ridx - idx - fromLength));
     308             : 
     309             :     // Loop over the "->" chain. This loop also works for non-chains, or more
     310             :     // correctly chains with only one item.
     311             :     for (;;) {
     312           0 :         idx = chain.RFind(arrow);
     313           0 :         if (idx < 0) {
     314             :             // This is the last chain item. Try to parse what is left.
     315           0 :             return TryParseLocationURICandidate(chain, aLocationHint, aURI);
     316             :         }
     317             : 
     318             :         // Try to parse current chain item
     319           0 :         if (TryParseLocationURICandidate(Substring(chain, idx + arrowLength),
     320             :                                          aLocationHint, aURI))
     321             :             return true;
     322             : 
     323             :         // Current chain item couldn't be parsed.
     324             :         // Strip current item and continue.
     325           0 :         chain = Substring(chain, 0, idx);
     326             :     }
     327             : 
     328             :     MOZ_CRASH("Chain parser loop does not terminate");
     329             : }
     330             : 
     331             : static bool
     332          38 : PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal)
     333             : {
     334             :     // System principal gets a free pass.
     335          38 :     if (nsXPConnect::SecurityManager()->IsSystemPrincipal(aPrincipal))
     336             :         return true;
     337             : 
     338          10 :     auto principal = BasePrincipal::Cast(aPrincipal);
     339             : 
     340             :     // ExpandedPrincipal gets a free pass.
     341          10 :     if (principal->Is<ExpandedPrincipal>()) {
     342             :         return true;
     343             :     }
     344             : 
     345             :     // WebExtension principals get a free pass.
     346          10 :     if (principal->AddonPolicy()) {
     347             :         return true;
     348             :     }
     349             : 
     350             :     // Check whether our URI is an "about:" URI that allows scripts.  If it is,
     351             :     // we need to allow JS to run.
     352          16 :     nsCOMPtr<nsIURI> principalURI;
     353           0 :     aPrincipal->GetURI(getter_AddRefs(principalURI));
     354           0 :     MOZ_ASSERT(principalURI);
     355             : 
     356             :     bool isAbout;
     357           0 :     nsresult rv = principalURI->SchemeIs("about", &isAbout);
     358           8 :     if (NS_SUCCEEDED(rv) && isAbout) {
     359           0 :         nsCOMPtr<nsIAboutModule> module;
     360           0 :         rv = NS_GetAboutModule(principalURI, getter_AddRefs(module));
     361           0 :         if (NS_SUCCEEDED(rv)) {
     362             :             uint32_t flags;
     363           0 :             rv = module->GetURIFlags(principalURI, &flags);
     364           0 :             if (NS_SUCCEEDED(rv) &&
     365           0 :                 (flags & nsIAboutModule::ALLOW_SCRIPT)) {
     366           0 :                 return true;
     367             :             }
     368             :         }
     369             :     }
     370             : 
     371             :     return false;
     372             : }
     373             : 
     374           0 : Scriptability::Scriptability(JS::Realm* realm) : mScriptBlocks(0)
     375             :                                                , mDocShellAllowsScript(true)
     376          38 :                                                , mScriptBlockedByPolicy(false)
     377             : {
     378          38 :     nsIPrincipal* prin = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
     379           0 :     mImmuneToScriptPolicy = PrincipalImmuneToScriptPolicy(prin);
     380             : 
     381             :     // If we're not immune, we should have a real principal with a codebase URI.
     382             :     // Check the URI against the new-style domain policy.
     383           0 :     if (!mImmuneToScriptPolicy) {
     384           0 :         nsCOMPtr<nsIURI> codebase;
     385          16 :         nsresult rv = prin->GetURI(getter_AddRefs(codebase));
     386             :         bool policyAllows;
     387          24 :         if (NS_SUCCEEDED(rv) && codebase &&
     388          16 :             NS_SUCCEEDED(nsXPConnect::SecurityManager()->PolicyAllowsScript(codebase, &policyAllows)))
     389             :         {
     390           8 :             mScriptBlockedByPolicy = !policyAllows;
     391             :         } else {
     392             :             // Something went wrong - be safe and block script.
     393           0 :             mScriptBlockedByPolicy = true;
     394             :         }
     395             :     }
     396          38 : }
     397             : 
     398             : bool
     399        4480 : Scriptability::Allowed()
     400             : {
     401        8960 :     return mDocShellAllowsScript && !mScriptBlockedByPolicy &&
     402           1 :            mScriptBlocks == 0;
     403             : }
     404             : 
     405             : bool
     406           0 : Scriptability::IsImmuneToScriptPolicy()
     407             : {
     408           0 :     return mImmuneToScriptPolicy;
     409             : }
     410             : 
     411             : void
     412           0 : Scriptability::Block()
     413             : {
     414           0 :     ++mScriptBlocks;
     415           0 : }
     416             : 
     417             : void
     418           0 : Scriptability::Unblock()
     419             : {
     420           0 :     MOZ_ASSERT(mScriptBlocks > 0);
     421           0 :     --mScriptBlocks;
     422           0 : }
     423             : 
     424             : void
     425          18 : Scriptability::SetDocShellAllowsScript(bool aAllowed)
     426             : {
     427          18 :     mDocShellAllowsScript = aAllowed || mImmuneToScriptPolicy;
     428           0 : }
     429             : 
     430             : /* static */
     431             : Scriptability&
     432        4498 : Scriptability::Get(JSObject* aScope)
     433             : {
     434           0 :     return RealmPrivate::Get(aScope)->scriptability;
     435             : }
     436             : 
     437             : bool
     438           0 : IsContentXBLCompartment(JS::Compartment* compartment)
     439             : {
     440             :     // We always eagerly create compartment privates for content XBL compartments.
     441        4537 :     CompartmentPrivate* priv = CompartmentPrivate::Get(compartment);
     442           0 :     return priv && priv->isContentXBLCompartment;
     443             : }
     444             : 
     445             : bool
     446           0 : IsContentXBLScope(JS::Realm* realm)
     447             : {
     448           0 :     return IsContentXBLCompartment(JS::GetCompartmentForRealm(realm));
     449             : }
     450             : 
     451             : bool
     452        2435 : IsInContentXBLScope(JSObject* obj)
     453             : {
     454           0 :     return IsContentXBLCompartment(js::GetObjectCompartment(obj));
     455             : }
     456             : 
     457             : bool
     458         405 : IsUniversalXPConnectEnabled(JS::Compartment* compartment)
     459             : {
     460         405 :     CompartmentPrivate* priv = CompartmentPrivate::Get(compartment);
     461         405 :     if (!priv)
     462             :         return false;
     463           0 :     return priv->universalXPConnectEnabled;
     464             : }
     465             : 
     466             : bool
     467          64 : IsUniversalXPConnectEnabled(JSContext* cx)
     468             : {
     469          64 :     JS::Compartment* compartment = js::GetContextCompartment(cx);
     470          64 :     if (!compartment)
     471             :         return false;
     472           0 :     return IsUniversalXPConnectEnabled(compartment);
     473             : }
     474             : 
     475             : bool
     476           0 : EnableUniversalXPConnect(JSContext* cx)
     477             : {
     478           0 :     JS::Compartment* compartment = js::GetContextCompartment(cx);
     479           0 :     if (!compartment)
     480             :         return true;
     481             :     // Never set universalXPConnectEnabled on a chrome compartment - it confuses
     482             :     // the security wrapping code.
     483           0 :     if (AccessCheck::isChrome(compartment))
     484             :         return true;
     485           0 :     CompartmentPrivate* priv = CompartmentPrivate::Get(compartment);
     486           0 :     if (!priv)
     487             :         return true;
     488           0 :     if (priv->universalXPConnectEnabled)
     489             :         return true;
     490           0 :     priv->universalXPConnectEnabled = true;
     491             : 
     492             :     // Recompute all the cross-compartment wrappers leaving the newly-privileged
     493             :     // compartment.
     494           0 :     bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
     495           0 :                                     js::AllCompartments());
     496           0 :     NS_ENSURE_TRUE(ok, false);
     497             : 
     498             :     // The Components object normally isn't defined for unprivileged web content,
     499             :     // but we define it when UniversalXPConnect is enabled to support legacy
     500             :     // tests.
     501           0 :     Realm* realm = GetCurrentRealmOrNull(cx);
     502           0 :     XPCWrappedNativeScope* scope = RealmPrivate::Get(realm)->scope;
     503           0 :     if (!scope)
     504             :         return true;
     505           0 :     scope->ForcePrivilegedComponents();
     506           0 :     return scope->AttachComponentsObject(cx);
     507             : }
     508             : 
     509             : JSObject*
     510        4304 : UnprivilegedJunkScope()
     511             : {
     512           0 :     return XPCJSRuntime::Get()->UnprivilegedJunkScope();
     513             : }
     514             : 
     515             : JSObject*
     516          68 : PrivilegedJunkScope()
     517             : {
     518           0 :     return XPCJSRuntime::Get()->PrivilegedJunkScope();
     519             : }
     520             : 
     521             : JSObject*
     522        2524 : CompilationScope()
     523             : {
     524           0 :     return XPCJSRuntime::Get()->CompilationScope();
     525             : }
     526             : 
     527             : nsGlobalWindowInner*
     528        4869 : WindowOrNull(JSObject* aObj)
     529             : {
     530           0 :     MOZ_ASSERT(aObj);
     531           0 :     MOZ_ASSERT(!js::IsWrapper(aObj));
     532             : 
     533        4869 :     nsGlobalWindowInner* win = nullptr;
     534        4869 :     UNWRAP_NON_WRAPPER_OBJECT(Window, aObj, win);
     535           0 :     return win;
     536             : }
     537             : 
     538             : nsGlobalWindowInner*
     539        4458 : WindowGlobalOrNull(JSObject* aObj)
     540             : {
     541        4458 :     MOZ_ASSERT(aObj);
     542        4458 :     JSObject* glob = js::GetGlobalForObjectCrossCompartment(aObj);
     543             : 
     544           0 :     return WindowOrNull(glob);
     545             : }
     546             : 
     547             : nsGlobalWindowInner*
     548           1 : CurrentWindowOrNull(JSContext* cx)
     549             : {
     550           1 :     JSObject* glob = JS::CurrentGlobalOrNull(cx);
     551           1 :     return glob ? WindowOrNull(glob) : nullptr;
     552             : }
     553             : 
     554             : // Nukes all wrappers into or out of the given compartment, and prevents new
     555             : // wrappers from being created. Additionally marks the compartment as
     556             : // unscriptable after wrappers have been nuked.
     557             : //
     558             : // Note: This should *only* be called for browser or extension compartments.
     559             : // Wrappers between web compartments must never be cut in web-observable
     560             : // ways.
     561             : void
     562           0 : NukeAllWrappersForCompartment(JSContext* cx, JS::Compartment* compartment,
     563             :                               js::NukeReferencesToWindow nukeReferencesToWindow)
     564             : {
     565             :     // First, nuke all wrappers into or out of the target compartment. Once
     566             :     // the compartment is marked as nuked, WrapperFactory will refuse to
     567             :     // create new live wrappers for it, in either direction. This means that
     568             :     // we need to be sure that we don't have any existing cross-compartment
     569             :     // wrappers which may be replaced with dead wrappers during unrelated
     570             :     // wrapper recomputation *before* we set that bit.
     571           0 :     js::NukeCrossCompartmentWrappers(cx, js::AllCompartments(), compartment,
     572             :                                      nukeReferencesToWindow,
     573           0 :                                      js::NukeAllReferences);
     574             : 
     575             :     // At this point, we should cross-compartment wrappers for the nuked
     576             :     // compartment. Set the wasNuked bit so WrapperFactory will return a
     577             :     // DeadObjectProxy when asked to create a new wrapper for it, and mark as
     578             :     // unscriptable.
     579           0 :     xpc::CompartmentPrivate::Get(compartment)->wasNuked = true;
     580             : 
     581           0 :     auto blockScriptability = [](JSContext*, void*, Handle<Realm*> realm) {
     582           0 :         xpc::RealmPrivate::Get(realm)->scriptability.Block();
     583           0 :     };
     584           0 :     JS::IterateRealmsInCompartment(cx, compartment, nullptr, blockScriptability);
     585           0 : }
     586             : 
     587             : } // namespace xpc
     588             : 
     589             : static void
     590           5 : CompartmentDestroyedCallback(JSFreeOp* fop, JS::Compartment* compartment)
     591             : {
     592             :     // NB - This callback may be called in JS_DestroyContext, which happens
     593             :     // after the XPCJSRuntime has been torn down.
     594             : 
     595             :     // Get the current compartment private into an AutoPtr (which will do the
     596             :     // cleanup for us), and null out the private (which may already be null).
     597           0 :     nsAutoPtr<CompartmentPrivate> priv(CompartmentPrivate::Get(compartment));
     598           5 :     JS_SetCompartmentPrivate(compartment, nullptr);
     599           0 : }
     600             : 
     601             : static size_t
     602           0 : CompartmentSizeOfIncludingThisCallback(MallocSizeOf mallocSizeOf, JS::Compartment* compartment)
     603             : {
     604           0 :     CompartmentPrivate* priv = CompartmentPrivate::Get(compartment);
     605           0 :     return priv ? priv->SizeOfIncludingThis(mallocSizeOf) : 0;
     606             : }
     607             : 
     608             : /*
     609             :  * Return true if there exists a non-system inner window which is a current
     610             :  * inner window and whose reflector is gray.  We don't merge system
     611             :  * compartments, so we don't use them to trigger merging CCs.
     612             :  */
     613           0 : bool XPCJSRuntime::UsefulToMergeZones() const
     614             : {
     615           0 :     MOZ_ASSERT(NS_IsMainThread());
     616             : 
     617             :     // Turns out, actually making this return true often enough makes Windows
     618             :     // mochitest-gl OOM a lot.  Need to figure out what's going on there; see
     619             :     // bug 1277036.
     620             : 
     621           0 :     return false;
     622             : }
     623             : 
     624           0 : void XPCJSRuntime::TraceNativeBlackRoots(JSTracer* trc)
     625             : {
     626           0 :     for (CycleCollectedJSContext* ccx : Contexts()) {
     627           0 :         auto* cx = static_cast<const XPCJSContext*>(ccx);
     628           0 :         if (AutoMarkingPtr* roots = cx->mAutoRoots)
     629           0 :             roots->TraceJSAll(trc);
     630             :     }
     631             : 
     632           0 :     dom::TraceBlackJS(trc, nsXPConnect::XPConnect()->IsShuttingDown());
     633           0 : }
     634             : 
     635           0 : void XPCJSRuntime::TraceAdditionalNativeGrayRoots(JSTracer* trc)
     636             : {
     637           0 :     XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(trc);
     638             : 
     639           0 :     for (XPCRootSetElem* e = mVariantRoots; e ; e = e->GetNextRoot())
     640           0 :         static_cast<XPCTraceableVariant*>(e)->TraceJS(trc);
     641             : 
     642           0 :     for (XPCRootSetElem* e = mWrappedJSRoots; e ; e = e->GetNextRoot())
     643           0 :         static_cast<nsXPCWrappedJS*>(e)->TraceJS(trc);
     644           0 : }
     645             : 
     646             : void
     647           0 : XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& cb)
     648             : {
     649           0 :     XPCWrappedNativeScope::SuspectAllWrappers(cb);
     650             : 
     651           0 :     for (XPCRootSetElem* e = mVariantRoots; e ; e = e->GetNextRoot()) {
     652           0 :         XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(e);
     653           0 :         if (nsCCUncollectableMarker::InGeneration(cb,
     654             :                                                   v->CCGeneration())) {
     655           0 :            JS::Value val = v->GetJSValPreserveColor();
     656           0 :            if (val.isObject() && !JS::ObjectIsMarkedGray(&val.toObject()))
     657           0 :                continue;
     658             :         }
     659             :         cb.NoteXPCOMRoot(v,
     660           0 :                          XPCTraceableVariant::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant());
     661             :     }
     662             : 
     663           0 :     for (XPCRootSetElem* e = mWrappedJSRoots; e ; e = e->GetNextRoot()) {
     664           0 :         cb.NoteXPCOMRoot(ToSupports(static_cast<nsXPCWrappedJS*>(e)),
     665           0 :                          nsXPCWrappedJS::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant());
     666             :     }
     667           0 : }
     668             : 
     669             : void
     670           0 : XPCJSRuntime::UnmarkSkippableJSHolders()
     671             : {
     672           0 :     CycleCollectedJSRuntime::UnmarkSkippableJSHolders();
     673           0 : }
     674             : 
     675             : void
     676           0 : XPCJSRuntime::PrepareForForgetSkippable()
     677             : {
     678           0 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     679           0 :     if (obs) {
     680           0 :         obs->NotifyObservers(nullptr, "cycle-collector-forget-skippable", nullptr);
     681             :     }
     682           0 : }
     683             : 
     684             : void
     685           0 : XPCJSRuntime::BeginCycleCollectionCallback()
     686             : {
     687           0 :     nsJSContext::BeginCycleCollectionCallback();
     688             : 
     689           0 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     690           0 :     if (obs) {
     691           0 :         obs->NotifyObservers(nullptr, "cycle-collector-begin", nullptr);
     692             :     }
     693           0 : }
     694             : 
     695             : void
     696           0 : XPCJSRuntime::EndCycleCollectionCallback(CycleCollectorResults& aResults)
     697             : {
     698           0 :     nsJSContext::EndCycleCollectionCallback(aResults);
     699             : 
     700           0 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     701           0 :     if (obs) {
     702           0 :         obs->NotifyObservers(nullptr, "cycle-collector-end", nullptr);
     703             :     }
     704           0 : }
     705             : 
     706             : void
     707           0 : XPCJSRuntime::DispatchDeferredDeletion(bool aContinuation, bool aPurge)
     708             : {
     709           0 :     mAsyncSnowWhiteFreer->Start(aContinuation, aPurge);
     710           0 : }
     711             : 
     712             : void
     713           0 : xpc_UnmarkSkippableJSHolders()
     714             : {
     715           0 :     if (nsXPConnect::GetRuntimeInstance()) {
     716           0 :         nsXPConnect::GetRuntimeInstance()->UnmarkSkippableJSHolders();
     717             :     }
     718           0 : }
     719             : 
     720             : /* static */ void
     721           0 : XPCJSRuntime::GCSliceCallback(JSContext* cx,
     722             :                               JS::GCProgress progress,
     723             :                               const JS::GCDescription& desc)
     724             : {
     725           0 :     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     726           0 :     if (!self)
     727             :         return;
     728             : 
     729           0 :     CrashReporter::SetGarbageCollecting(progress == JS::GC_CYCLE_BEGIN);
     730             : 
     731           0 :     if (self->mPrevGCSliceCallback)
     732           0 :         (*self->mPrevGCSliceCallback)(cx, progress, desc);
     733             : }
     734             : 
     735             : /* static */ void
     736           0 : XPCJSRuntime::DoCycleCollectionCallback(JSContext* cx)
     737             : {
     738             :     // The GC has detected that a CC at this point would collect a tremendous
     739             :     // amount of garbage that is being revivified unnecessarily.
     740           0 :     NS_DispatchToCurrentThread(
     741           0 :       NS_NewRunnableFunction("XPCJSRuntime::DoCycleCollectionCallback",
     742           0 :                              []() { nsJSContext::CycleCollectNow(nullptr); }));
     743             : 
     744           0 :     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     745           0 :     if (!self)
     746             :         return;
     747             : 
     748           0 :     if (self->mPrevDoCycleCollectionCallback)
     749           0 :         (*self->mPrevDoCycleCollectionCallback)(cx);
     750             : }
     751             : 
     752             : void
     753           0 : XPCJSRuntime::CustomGCCallback(JSGCStatus status)
     754             : {
     755           0 :     nsTArray<xpcGCCallback> callbacks(extraGCCallbacks);
     756           0 :     for (uint32_t i = 0; i < callbacks.Length(); ++i)
     757           0 :         callbacks[i](status);
     758           0 : }
     759             : 
     760             : /* static */ void
     761           0 : XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
     762             :                                JSFinalizeStatus status,
     763             :                                void* data)
     764             : {
     765           0 :     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     766           0 :     if (!self)
     767             :         return;
     768             : 
     769           0 :     switch (status) {
     770             :         case JSFINALIZE_GROUP_PREPARE:
     771             :         {
     772           0 :             MOZ_ASSERT(!self->mDoingFinalization, "bad state");
     773             : 
     774           0 :             MOZ_ASSERT(!self->mGCIsRunning, "bad state");
     775           0 :             self->mGCIsRunning = true;
     776             : 
     777           0 :             self->mDoingFinalization = true;
     778             : 
     779           0 :             break;
     780             :         }
     781             :         case JSFINALIZE_GROUP_START:
     782             :         {
     783           0 :             MOZ_ASSERT(self->mDoingFinalization, "bad state");
     784             : 
     785           0 :             MOZ_ASSERT(self->mGCIsRunning, "bad state");
     786           0 :             self->mGCIsRunning = false;
     787             : 
     788           0 :             break;
     789             :         }
     790             :         case JSFINALIZE_GROUP_END:
     791             :         {
     792             :             // Sweep scopes needing cleanup
     793           0 :             XPCWrappedNativeScope::KillDyingScopes();
     794             : 
     795           0 :             MOZ_ASSERT(self->mDoingFinalization, "bad state");
     796           0 :             self->mDoingFinalization = false;
     797             : 
     798           0 :             break;
     799             :         }
     800             :         case JSFINALIZE_COLLECTION_END:
     801             :         {
     802           0 :             MOZ_ASSERT(!self->mGCIsRunning, "bad state");
     803           0 :             self->mGCIsRunning = true;
     804             : 
     805           0 :             for (CycleCollectedJSContext* ccx : self->Contexts()) {
     806           0 :                 auto* cx = static_cast<const XPCJSContext*>(ccx);
     807           0 :                 if (AutoMarkingPtr* roots = cx->mAutoRoots)
     808           0 :                     roots->MarkAfterJSFinalizeAll();
     809             : 
     810             :                 // Now we are going to recycle any unused WrappedNativeTearoffs.
     811             :                 // We do this by iterating all the live callcontexts
     812             :                 // and marking the tearoffs in use. And then we
     813             :                 // iterate over all the WrappedNative wrappers and sweep their
     814             :                 // tearoffs.
     815             :                 //
     816             :                 // This allows us to perhaps minimize the growth of the
     817             :                 // tearoffs. And also makes us not hold references to interfaces
     818             :                 // on our wrapped natives that we are not actually using.
     819             :                 //
     820             :                 // XXX We may decide to not do this on *every* gc cycle.
     821             : 
     822           0 :                 XPCCallContext* ccxp = cx->GetCallContext();
     823           0 :                 while (ccxp) {
     824             :                     // Deal with the strictness of callcontext that
     825             :                     // complains if you ask for a tearoff when
     826             :                     // it is in a state where the tearoff could not
     827             :                     // possibly be valid.
     828           0 :                     if (ccxp->CanGetTearOff()) {
     829             :                         XPCWrappedNativeTearOff* to =
     830           0 :                             ccxp->GetTearOff();
     831           0 :                         if (to)
     832           0 :                             to->Mark();
     833             :                     }
     834           0 :                     ccxp = ccxp->GetPrevCallContext();
     835             :                 }
     836             :             }
     837             : 
     838           0 :             XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs();
     839             : 
     840             :             // Now we need to kill the 'Dying' XPCWrappedNativeProtos.
     841             :             // We transfered these native objects to this table when their
     842             :             // JSObject's were finalized. We did not destroy them immediately
     843             :             // at that point because the ordering of JS finalization is not
     844             :             // deterministic and we did not yet know if any wrappers that
     845             :             // might still be referencing the protos where still yet to be
     846             :             // finalized and destroyed. We *do* know that the protos'
     847             :             // JSObjects would not have been finalized if there were any
     848             :             // wrappers that referenced the proto but where not themselves
     849             :             // slated for finalization in this gc cycle. So... at this point
     850             :             // we know that any and all wrappers that might have been
     851             :             // referencing the protos in the dying list are themselves dead.
     852             :             // So, we can safely delete all the protos in the list.
     853             : 
     854           0 :             for (auto i = self->mDyingWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
     855           0 :                 auto entry = static_cast<XPCWrappedNativeProtoMap::Entry*>(i.Get());
     856           0 :                 delete static_cast<const XPCWrappedNativeProto*>(entry->key);
     857           0 :                 i.Remove();
     858             :             }
     859             : 
     860           0 :             MOZ_ASSERT(self->mGCIsRunning, "bad state");
     861           0 :             self->mGCIsRunning = false;
     862             : 
     863           0 :             break;
     864             :         }
     865             :     }
     866             : }
     867             : 
     868             : /* static */ void
     869           0 : XPCJSRuntime::WeakPointerZonesCallback(JSContext* cx, void* data)
     870             : {
     871             :     // Called before each sweeping slice -- after processing any final marking
     872             :     // triggered by barriers -- to clear out any references to things that are
     873             :     // about to be finalized and update any pointers to moved GC things.
     874           0 :     XPCJSRuntime* self = static_cast<XPCJSRuntime*>(data);
     875             : 
     876           0 :     self->mWrappedJSMap->UpdateWeakPointersAfterGC();
     877             : 
     878           0 :     XPCWrappedNativeScope::UpdateWeakPointersInAllScopesAfterGC();
     879           0 : }
     880             : 
     881             : /* static */ void
     882           0 : XPCJSRuntime::WeakPointerCompartmentCallback(JSContext* cx, JS::Compartment* comp, void* data)
     883             : {
     884             :     // Called immediately after the ZoneGroup weak pointer callback, but only
     885             :     // once for each compartment that is being swept.
     886           0 :     CompartmentPrivate* xpcComp = CompartmentPrivate::Get(comp);
     887           0 :     if (xpcComp)
     888           0 :         xpcComp->UpdateWeakPointersAfterGC();
     889           0 : }
     890             : 
     891             : void
     892           0 : CompartmentPrivate::UpdateWeakPointersAfterGC()
     893             : {
     894           0 :     mWrappedJSMap->UpdateWeakPointersAfterGC();
     895           0 : }
     896             : 
     897             : void
     898           0 : XPCJSRuntime::CustomOutOfMemoryCallback()
     899             : {
     900           0 :     if (!Preferences::GetBool("memory.dump_reports_on_oom")) {
     901           0 :         return;
     902             :     }
     903             : 
     904             :     nsCOMPtr<nsIMemoryInfoDumper> dumper =
     905           0 :         do_GetService("@mozilla.org/memory-info-dumper;1");
     906           0 :     if (!dumper) {
     907           0 :         return;
     908             :     }
     909             : 
     910             :     // If this fails, it fails silently.
     911           0 :     dumper->DumpMemoryInfoToTempDir(NS_LITERAL_STRING("due-to-JS-OOM"),
     912             :                                     /* anonymize = */ false,
     913           0 :                                     /* minimizeMemoryUsage = */ false);
     914             : }
     915             : 
     916             : void
     917           0 : XPCJSRuntime::OnLargeAllocationFailure()
     918             : {
     919           0 :     CycleCollectedJSRuntime::SetLargeAllocationFailure(OOMState::Reporting);
     920             : 
     921           0 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     922           0 :     if (os) {
     923           0 :         os->NotifyObservers(nullptr, "memory-pressure", u"heap-minimize");
     924             :     }
     925             : 
     926           0 :     CycleCollectedJSRuntime::SetLargeAllocationFailure(OOMState::Reported);
     927           0 : }
     928             : 
     929             : class LargeAllocationFailureRunnable final : public Runnable
     930             : {
     931             :     Mutex mMutex;
     932             :     CondVar mCondVar;
     933             :     bool mWaiting;
     934             : 
     935           0 :     virtual ~LargeAllocationFailureRunnable()
     936           0 :     {
     937           0 :         MOZ_ASSERT(!mWaiting);
     938           0 :     }
     939             : 
     940             :   protected:
     941           0 :     NS_IMETHOD Run() override
     942             :     {
     943           0 :         MOZ_ASSERT(NS_IsMainThread());
     944             : 
     945           0 :         XPCJSRuntime::Get()->OnLargeAllocationFailure();
     946             : 
     947           0 :         MutexAutoLock lock(mMutex);
     948           0 :         MOZ_ASSERT(mWaiting);
     949             : 
     950           0 :         mWaiting = false;
     951           0 :         mCondVar.Notify();
     952           0 :         return NS_OK;
     953             :     }
     954             : 
     955             :   public:
     956           0 :     LargeAllocationFailureRunnable()
     957           0 :       : mozilla::Runnable("LargeAllocationFailureRunnable")
     958             :       , mMutex("LargeAllocationFailureRunnable::mMutex")
     959             :       , mCondVar(mMutex, "LargeAllocationFailureRunnable::mCondVar")
     960           0 :       , mWaiting(true)
     961             :     {
     962           0 :         MOZ_ASSERT(!NS_IsMainThread());
     963           0 :     }
     964             : 
     965           0 :     void BlockUntilDone()
     966             :     {
     967           0 :         MOZ_ASSERT(!NS_IsMainThread());
     968             : 
     969           0 :         MutexAutoLock lock(mMutex);
     970           0 :         while (mWaiting) {
     971           0 :             mCondVar.Wait();
     972             :         }
     973           0 :     }
     974             : };
     975             : 
     976             : static void
     977           0 : OnLargeAllocationFailureCallback()
     978             : {
     979             :     // This callback can be called from any thread, including internal JS helper
     980             :     // and DOM worker threads. We need to send the low-memory event via the
     981             :     // observer service which can only be called on the main thread, so proxy to
     982             :     // the main thread if we're not there already. The purpose of this callback
     983             :     // is to synchronously free some memory so the caller can retry a failed
     984             :     // allocation, so block on the completion.
     985             : 
     986           0 :     if (NS_IsMainThread()) {
     987           0 :         XPCJSRuntime::Get()->OnLargeAllocationFailure();
     988           0 :         return;
     989             :     }
     990             : 
     991           0 :     RefPtr<LargeAllocationFailureRunnable> r = new LargeAllocationFailureRunnable;
     992           0 :     if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)))) {
     993           0 :         return;
     994             :     }
     995             : 
     996           0 :     r->BlockUntilDone();
     997             : }
     998             : 
     999             : size_t
    1000           0 : XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
    1001             : {
    1002           0 :     size_t n = 0;
    1003           0 :     n += mallocSizeOf(this);
    1004           0 :     n += mWrappedJSMap->SizeOfIncludingThis(mallocSizeOf);
    1005           0 :     n += mIID2NativeInterfaceMap->SizeOfIncludingThis(mallocSizeOf);
    1006           0 :     n += mClassInfo2NativeSetMap->ShallowSizeOfIncludingThis(mallocSizeOf);
    1007           0 :     n += mNativeSetMap->SizeOfIncludingThis(mallocSizeOf);
    1008             : 
    1009           0 :     n += CycleCollectedJSRuntime::SizeOfExcludingThis(mallocSizeOf);
    1010             : 
    1011             :     // There are other XPCJSRuntime members that could be measured; the above
    1012             :     // ones have been seen by DMD to be worth measuring.  More stuff may be
    1013             :     // added later.
    1014             : 
    1015           0 :     return n;
    1016             : }
    1017             : 
    1018             : size_t
    1019           0 : CompartmentPrivate::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
    1020             : {
    1021           0 :     size_t n = mallocSizeOf(this);
    1022           0 :     n += mWrappedJSMap->SizeOfIncludingThis(mallocSizeOf);
    1023           0 :     n += mWrappedJSMap->SizeOfWrappedJS(mallocSizeOf);
    1024           0 :     return n;
    1025             : }
    1026             : 
    1027             : /***************************************************************************/
    1028             : 
    1029             : void
    1030           0 : XPCJSRuntime::SystemIsBeingShutDown()
    1031             : {
    1032             :     // We don't want to track wrapped JS roots after this point since we're
    1033             :     // making them !IsValid anyway through SystemIsBeingShutDown.
    1034           0 :     mWrappedJSRoots = nullptr;
    1035           0 : }
    1036             : 
    1037             : void
    1038           0 : XPCJSRuntime::Shutdown(JSContext* cx)
    1039             : {
    1040             :     // This destructor runs before ~CycleCollectedJSContext, which does the
    1041             :     // actual JS_DestroyContext() call. But destroying the context triggers
    1042             :     // one final GC, which can call back into the context with various
    1043             :     // callbacks if we aren't careful. Null out the relevant callbacks.
    1044           0 :     JS_RemoveFinalizeCallback(cx, FinalizeCallback);
    1045           0 :     JS_RemoveWeakPointerZonesCallback(cx, WeakPointerZonesCallback);
    1046           0 :     JS_RemoveWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback);
    1047           0 :     xpc_DelocalizeRuntime(JS_GetRuntime(cx));
    1048             : 
    1049           0 :     JS::SetGCSliceCallback(cx, mPrevGCSliceCallback);
    1050             : 
    1051             :     // clean up and destroy maps...
    1052           0 :     mWrappedJSMap->ShutdownMarker();
    1053           0 :     delete mWrappedJSMap;
    1054           0 :     mWrappedJSMap = nullptr;
    1055             : 
    1056           0 :     delete mWrappedJSClassMap;
    1057           0 :     mWrappedJSClassMap = nullptr;
    1058             : 
    1059           0 :     delete mIID2NativeInterfaceMap;
    1060           0 :     mIID2NativeInterfaceMap = nullptr;
    1061             : 
    1062           0 :     delete mClassInfo2NativeSetMap;
    1063           0 :     mClassInfo2NativeSetMap = nullptr;
    1064             : 
    1065           0 :     delete mNativeSetMap;
    1066           0 :     mNativeSetMap = nullptr;
    1067             : 
    1068           0 :     delete mDyingWrappedNativeProtoMap;
    1069           0 :     mDyingWrappedNativeProtoMap = nullptr;
    1070             : 
    1071           0 :     CycleCollectedJSRuntime::Shutdown(cx);
    1072           0 : }
    1073             : 
    1074           0 : XPCJSRuntime::~XPCJSRuntime()
    1075             : {
    1076           0 :     MOZ_COUNT_DTOR_INHERITED(XPCJSRuntime, CycleCollectedJSRuntime);
    1077           0 : }
    1078             : 
    1079             : // If |*anonymizeID| is non-zero and this is a user realm, the name will
    1080             : // be anonymized.
    1081             : static void
    1082           0 : GetRealmName(JS::Realm* realm, nsCString& name, int* anonymizeID,
    1083             :              bool replaceSlashes)
    1084             : {
    1085           0 :     if (*anonymizeID && !js::IsSystemRealm(realm)) {
    1086           0 :         name.AppendPrintf("<anonymized-%d>", *anonymizeID);
    1087           0 :         *anonymizeID += 1;
    1088           0 :     } else if (JSPrincipals* principals = JS::GetRealmPrincipals(realm)) {
    1089           0 :         nsresult rv = nsJSPrincipals::get(principals)->GetScriptLocation(name);
    1090           0 :         if (NS_FAILED(rv)) {
    1091           0 :             name.AssignLiteral("(unknown)");
    1092             :         }
    1093             : 
    1094             :         // If the realm's location (name) differs from the principal's script
    1095             :         // location, append the realm's location to allow differentiation of
    1096             :         // multiple realms owned by the same principal (e.g. components owned
    1097             :         // by the system or null principal).
    1098           0 :         RealmPrivate* realmPrivate = RealmPrivate::Get(realm);
    1099           0 :         if (realmPrivate) {
    1100           0 :             const nsACString& location = realmPrivate->GetLocation();
    1101           0 :             if (!location.IsEmpty() && !location.Equals(name)) {
    1102           0 :                 name.AppendLiteral(", ");
    1103           0 :                 name.Append(location);
    1104             :             }
    1105             :         }
    1106             : 
    1107           0 :         if (*anonymizeID) {
    1108             :             // We might have a file:// URL that includes a path from the local
    1109             :             // filesystem, which should be omitted if we're anonymizing.
    1110             :             static const char* filePrefix = "file://";
    1111           0 :             int filePos = name.Find(filePrefix);
    1112           0 :             if (filePos >= 0) {
    1113           0 :                 int pathPos = filePos + strlen(filePrefix);
    1114           0 :                 int lastSlashPos = -1;
    1115           0 :                 for (int i = pathPos; i < int(name.Length()); i++) {
    1116           0 :                     if (name[i] == '/' || name[i] == '\\') {
    1117           0 :                         lastSlashPos = i;
    1118             :                     }
    1119             :                 }
    1120           0 :                 if (lastSlashPos != -1) {
    1121           0 :                     name.ReplaceASCII(pathPos, lastSlashPos - pathPos,
    1122           0 :                                       "<anonymized>");
    1123             :                 } else {
    1124             :                     // Something went wrong. Anonymize the entire path to be
    1125             :                     // safe.
    1126           0 :                     name.Truncate(pathPos);
    1127           0 :                     name += "<anonymized?!>";
    1128             :                 }
    1129             :             }
    1130             : 
    1131             :             // We might have a location like this:
    1132             :             //   inProcessTabChildGlobal?ownedBy=http://www.example.com/
    1133             :             // The owner should be omitted if it's not a chrome: URI and we're
    1134             :             // anonymizing.
    1135             :             static const char* ownedByPrefix =
    1136             :                 "inProcessTabChildGlobal?ownedBy=";
    1137           0 :             int ownedByPos = name.Find(ownedByPrefix);
    1138           0 :             if (ownedByPos >= 0) {
    1139           0 :                 const char* chrome = "chrome:";
    1140           0 :                 int ownerPos = ownedByPos + strlen(ownedByPrefix);
    1141             :                 const nsDependentCSubstring& ownerFirstPart =
    1142           0 :                     Substring(name, ownerPos, strlen(chrome));
    1143           0 :                 if (!ownerFirstPart.EqualsASCII(chrome)) {
    1144           0 :                     name.Truncate(ownerPos);
    1145           0 :                     name += "<anonymized>";
    1146             :                 }
    1147             :             }
    1148             :         }
    1149             : 
    1150             :         // A hack: replace forward slashes with '\\' so they aren't
    1151             :         // treated as path separators.  Users of the reporters
    1152             :         // (such as about:memory) have to undo this change.
    1153           0 :         if (replaceSlashes)
    1154           0 :             name.ReplaceChar('/', '\\');
    1155             :     } else {
    1156           0 :         name.AssignLiteral("null-principal");
    1157             :     }
    1158           0 : }
    1159             : 
    1160             : extern void
    1161           0 : xpc::GetCurrentRealmName(JSContext* cx, nsCString& name)
    1162             : {
    1163           0 :     RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
    1164           0 :     if (!global) {
    1165           0 :         name.AssignLiteral("no global");
    1166           0 :         return;
    1167             :     }
    1168             : 
    1169           0 :     JS::Realm* realm = GetNonCCWObjectRealm(global);
    1170           0 :     int anonymizeID = 0;
    1171           0 :     GetRealmName(realm, name, &anonymizeID, false);
    1172             : }
    1173             : 
    1174             : void
    1175           0 : xpc::AddGCCallback(xpcGCCallback cb)
    1176             : {
    1177           0 :     XPCJSRuntime::Get()->AddGCCallback(cb);
    1178           0 : }
    1179             : 
    1180             : void
    1181           0 : xpc::RemoveGCCallback(xpcGCCallback cb)
    1182             : {
    1183           0 :     XPCJSRuntime::Get()->RemoveGCCallback(cb);
    1184           0 : }
    1185             : 
    1186             : static int64_t
    1187           0 : JSMainRuntimeGCHeapDistinguishedAmount()
    1188             : {
    1189           0 :     JSContext* cx = danger::GetJSContext();
    1190           0 :     return int64_t(JS_GetGCParameter(cx, JSGC_TOTAL_CHUNKS)) *
    1191           0 :            js::gc::ChunkSize;
    1192             : }
    1193             : 
    1194             : static int64_t
    1195           0 : JSMainRuntimeTemporaryPeakDistinguishedAmount()
    1196             : {
    1197           0 :     JSContext* cx = danger::GetJSContext();
    1198           0 :     return JS::PeakSizeOfTemporary(cx);
    1199             : }
    1200             : 
    1201             : static int64_t
    1202           0 : JSMainRuntimeRealmsSystemDistinguishedAmount()
    1203             : {
    1204           0 :     JSContext* cx = danger::GetJSContext();
    1205           0 :     return JS::SystemRealmCount(cx);
    1206             : }
    1207             : 
    1208             : static int64_t
    1209           0 : JSMainRuntimeRealmsUserDistinguishedAmount()
    1210             : {
    1211           0 :     JSContext* cx = XPCJSContext::Get()->Context();
    1212           0 :     return JS::UserRealmCount(cx);
    1213             : }
    1214             : 
    1215           3 : class JSMainRuntimeTemporaryPeakReporter final : public nsIMemoryReporter
    1216             : {
    1217           0 :     ~JSMainRuntimeTemporaryPeakReporter() {}
    1218             : 
    1219             :   public:
    1220             :     NS_DECL_ISUPPORTS
    1221             : 
    1222           0 :     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
    1223             :                               nsISupports* aData, bool aAnonymize) override
    1224             :     {
    1225           0 :         MOZ_COLLECT_REPORT(
    1226             :             "js-main-runtime-temporary-peak", KIND_OTHER, UNITS_BYTES,
    1227             :             JSMainRuntimeTemporaryPeakDistinguishedAmount(),
    1228             :             "Peak transient data size in the main JSRuntime (the current size "
    1229             :             "of which is reported as "
    1230           0 :             "'explicit/js-non-window/runtime/temporary').");
    1231             : 
    1232           0 :         return NS_OK;
    1233             :     }
    1234             : };
    1235             : 
    1236          46 : NS_IMPL_ISUPPORTS(JSMainRuntimeTemporaryPeakReporter, nsIMemoryReporter)
    1237             : 
    1238             : // The REPORT* macros do an unconditional report.  The ZRREPORT* macros are for
    1239             : // realms and zones; they aggregate any entries smaller than
    1240             : // SUNDRIES_THRESHOLD into the "sundries/gc-heap" and "sundries/malloc-heap"
    1241             : // entries for the realm.
    1242             : 
    1243             : #define SUNDRIES_THRESHOLD js::MemoryReportingSundriesThreshold()
    1244             : 
    1245             : #define REPORT(_path, _kind, _units, _amount, _desc) \
    1246             :     handleReport->Callback(EmptyCString(), _path, \
    1247             :                            nsIMemoryReporter::_kind, \
    1248             :                            nsIMemoryReporter::_units, _amount, \
    1249             :                            NS_LITERAL_CSTRING(_desc), data); \
    1250             : 
    1251             : #define REPORT_BYTES(_path, _kind, _amount, _desc) \
    1252             :     REPORT(_path, _kind, UNITS_BYTES, _amount, _desc);
    1253             : 
    1254             : #define REPORT_GC_BYTES(_path, _amount, _desc) \
    1255             :     do { \
    1256             :         size_t amount = _amount;  /* evaluate _amount only once */ \
    1257             :         handleReport->Callback(EmptyCString(), _path, \
    1258             :                                nsIMemoryReporter::KIND_NONHEAP, \
    1259             :                                nsIMemoryReporter::UNITS_BYTES, amount, \
    1260             :                                NS_LITERAL_CSTRING(_desc), data); \
    1261             :         gcTotal += amount; \
    1262             :     } while (0)
    1263             : 
    1264             : // Report realm/zone non-GC (KIND_HEAP) bytes.
    1265             : #define ZRREPORT_BYTES(_path, _amount, _desc) \
    1266             :     do { \
    1267             :         /* Assign _descLiteral plus "" into a char* to prove that it's */ \
    1268             :         /* actually a literal. */ \
    1269             :         size_t amount = _amount;  /* evaluate _amount only once */ \
    1270             :         if (amount >= SUNDRIES_THRESHOLD) { \
    1271             :             handleReport->Callback(EmptyCString(), _path, \
    1272             :                                    nsIMemoryReporter::KIND_HEAP, \
    1273             :                                    nsIMemoryReporter::UNITS_BYTES, amount, \
    1274             :                                    NS_LITERAL_CSTRING(_desc), data); \
    1275             :         } else { \
    1276             :             sundriesMallocHeap += amount; \
    1277             :         } \
    1278             :     } while (0)
    1279             : 
    1280             : // Report realm/zone GC bytes.
    1281             : #define ZRREPORT_GC_BYTES(_path, _amount, _desc) \
    1282             :     do { \
    1283             :         size_t amount = _amount;  /* evaluate _amount only once */ \
    1284             :         if (amount >= SUNDRIES_THRESHOLD) { \
    1285             :             handleReport->Callback(EmptyCString(), _path, \
    1286             :                                    nsIMemoryReporter::KIND_NONHEAP, \
    1287             :                                    nsIMemoryReporter::UNITS_BYTES, amount, \
    1288             :                                    NS_LITERAL_CSTRING(_desc), data); \
    1289             :             gcTotal += amount; \
    1290             :         } else { \
    1291             :             sundriesGCHeap += amount; \
    1292             :         } \
    1293             :     } while (0)
    1294             : 
    1295             : // Report runtime bytes.
    1296             : #define RREPORT_BYTES(_path, _kind, _amount, _desc) \
    1297             :     do { \
    1298             :         size_t amount = _amount;  /* evaluate _amount only once */ \
    1299             :         handleReport->Callback(EmptyCString(), _path, \
    1300             :                                nsIMemoryReporter::_kind, \
    1301             :                                nsIMemoryReporter::UNITS_BYTES, amount, \
    1302             :                                NS_LITERAL_CSTRING(_desc), data); \
    1303             :         rtTotal += amount; \
    1304             :     } while (0)
    1305             : 
    1306             : // Report GC thing bytes.
    1307             : #define MREPORT_BYTES(_path, _kind, _amount, _desc) \
    1308             :     do { \
    1309             :         size_t amount = _amount;  /* evaluate _amount only once */ \
    1310             :         handleReport->Callback(EmptyCString(), _path, \
    1311             :                                nsIMemoryReporter::_kind, \
    1312             :                                nsIMemoryReporter::UNITS_BYTES, amount, \
    1313             :                                NS_LITERAL_CSTRING(_desc), data); \
    1314             :         gcThingTotal += amount; \
    1315             :     } while (0)
    1316             : 
    1317           0 : MOZ_DEFINE_MALLOC_SIZE_OF(JSMallocSizeOf)
    1318             : 
    1319             : namespace xpc {
    1320             : 
    1321             : static void
    1322           0 : ReportZoneStats(const JS::ZoneStats& zStats,
    1323             :                 const xpc::ZoneStatsExtras& extras,
    1324             :                 nsIHandleReportCallback* handleReport,
    1325             :                 nsISupports* data,
    1326             :                 bool anonymize,
    1327             :                 size_t* gcTotalOut = nullptr)
    1328             : {
    1329           0 :     const nsCString& pathPrefix = extras.pathPrefix;
    1330           0 :     size_t gcTotal = 0, sundriesGCHeap = 0, sundriesMallocHeap = 0;
    1331             : 
    1332           0 :     MOZ_ASSERT(!gcTotalOut == zStats.isTotals);
    1333             : 
    1334           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("symbols/gc-heap"),
    1335             :         zStats.symbolsGCHeap,
    1336             :         "Symbols.");
    1337             : 
    1338           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-arena-admin"),
    1339             :         zStats.gcHeapArenaAdmin,
    1340             :         "Bookkeeping information and alignment padding within GC arenas.");
    1341             : 
    1342           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("unused-gc-things"),
    1343             :         zStats.unusedGCThings.totalSize(),
    1344             :         "Unused GC thing cells within non-empty arenas.");
    1345             : 
    1346           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("unique-id-map"),
    1347             :         zStats.uniqueIdMap,
    1348             :         "Address-independent cell identities.");
    1349             : 
    1350           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("shape-tables"),
    1351             :         zStats.shapeTables,
    1352             :         "Tables storing shape information.");
    1353             : 
    1354           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("compartments/compartment-objects"),
    1355             :         zStats.compartmentObjects,
    1356             :         "The JS::Compartment objects in this zone.");
    1357             : 
    1358           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("compartments/cross-compartment-wrapper-tables"),
    1359             :         zStats.crossCompartmentWrappersTables,
    1360             :         "The cross-compartment wrapper tables.");
    1361             : 
    1362           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("compartments/private-data"),
    1363             :         zStats.compartmentsPrivateData,
    1364             :         "Extra data attached to each compartment by XPConnect, including "
    1365             :         "its wrapped-js.");
    1366             : 
    1367           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("lazy-scripts/gc-heap"),
    1368             :         zStats.lazyScriptsGCHeap,
    1369             :         "Scripts that haven't executed yet.");
    1370             : 
    1371           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("lazy-scripts/malloc-heap"),
    1372             :         zStats.lazyScriptsMallocHeap,
    1373             :         "Lazy script tables containing closed-over bindings or inner functions.");
    1374             : 
    1375           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("jit-codes-gc-heap"),
    1376             :         zStats.jitCodesGCHeap,
    1377             :         "References to executable code pools used by the JITs.");
    1378             : 
    1379           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("object-groups/gc-heap"),
    1380             :         zStats.objectGroupsGCHeap,
    1381             :         "Classification and type inference information about objects.");
    1382             : 
    1383           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("object-groups/malloc-heap"),
    1384             :         zStats.objectGroupsMallocHeap,
    1385             :         "Object group addenda.");
    1386             : 
    1387           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("scopes/gc-heap"),
    1388             :         zStats.scopesGCHeap,
    1389             :         "Scope information for scripts.");
    1390             : 
    1391           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("scopes/malloc-heap"),
    1392             :         zStats.scopesMallocHeap,
    1393             :         "Arrays of binding names and other binding-related data.");
    1394             : 
    1395           0 :     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("regexp-shareds/gc-heap"),
    1396             :         zStats.regExpSharedsGCHeap,
    1397             :         "Shared compiled regexp data.");
    1398             : 
    1399           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("regexp-shareds/malloc-heap"),
    1400             :         zStats.regExpSharedsMallocHeap,
    1401             :         "Shared compiled regexp data.");
    1402             : 
    1403           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("type-pool"),
    1404             :         zStats.typePool,
    1405             :         "Type sets and related data.");
    1406             : 
    1407           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("regexp-zone"),
    1408             :         zStats.regexpZone,
    1409             :         "The regexp zone and regexp data.");
    1410             : 
    1411           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("jit-zone"),
    1412             :         zStats.jitZone,
    1413             :         "The JIT zone.");
    1414             : 
    1415           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("baseline/optimized-stubs"),
    1416             :         zStats.baselineStubsOptimized,
    1417             :         "The Baseline JIT's optimized IC stubs (excluding code).");
    1418             : 
    1419           0 :     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("jit-cached-cfg"),
    1420             :         zStats.cachedCFG,
    1421             :         "The cached CFG to construct Ion code out of it.");
    1422             : 
    1423           0 :     size_t stringsNotableAboutMemoryGCHeap = 0;
    1424           0 :     size_t stringsNotableAboutMemoryMallocHeap = 0;
    1425             : 
    1426             :     #define MAYBE_INLINE \
    1427             :         "The characters may be inline or on the malloc heap."
    1428             :     #define MAYBE_OVERALLOCATED \
    1429             :         "Sometimes over-allocated to simplify string concatenation."
    1430             : 
    1431           0 :     for (size_t i = 0; i < zStats.notableStrings.length(); i++) {
    1432           0 :         const JS::NotableStringInfo& info = zStats.notableStrings[i];
    1433             : 
    1434           0 :         MOZ_ASSERT(!zStats.isTotals);
    1435             : 
    1436             :         // We don't do notable string detection when anonymizing, because
    1437             :         // there's a good chance its for crash submission, and the memory
    1438             :         // required for notable string detection is high.
    1439           0 :         MOZ_ASSERT(!anonymize);
    1440             : 
    1441           0 :         nsDependentCString notableString(info.buffer);
    1442             : 
    1443             :         // Viewing about:memory generates many notable strings which contain
    1444             :         // "string(length=".  If we report these as notable, then we'll create
    1445             :         // even more notable strings the next time we open about:memory (unless
    1446             :         // there's a GC in the meantime), and so on ad infinitum.
    1447             :         //
    1448             :         // To avoid cluttering up about:memory like this, we stick notable
    1449             :         // strings which contain "string(length=" into their own bucket.
    1450             : #       define STRING_LENGTH "string(length="
    1451           0 :         if (FindInReadable(NS_LITERAL_CSTRING(STRING_LENGTH), notableString)) {
    1452           0 :             stringsNotableAboutMemoryGCHeap += info.gcHeapLatin1;
    1453           0 :             stringsNotableAboutMemoryGCHeap += info.gcHeapTwoByte;
    1454           0 :             stringsNotableAboutMemoryMallocHeap += info.mallocHeapLatin1;
    1455           0 :             stringsNotableAboutMemoryMallocHeap += info.mallocHeapTwoByte;
    1456           0 :             continue;
    1457             :         }
    1458             : 
    1459             :         // Escape / to \ before we put notableString into the memory reporter
    1460             :         // path, because we don't want any forward slashes in the string to
    1461             :         // count as path separators.
    1462           0 :         nsCString escapedString(notableString);
    1463           0 :         escapedString.ReplaceSubstring("/", "\\");
    1464             : 
    1465           0 :         bool truncated = notableString.Length() < info.length;
    1466             : 
    1467           0 :         nsCString path = pathPrefix +
    1468           0 :             nsPrintfCString("strings/" STRING_LENGTH "%zu, copies=%d, \"%s\"%s)/",
    1469           0 :                             info.length, info.numCopies, escapedString.get(),
    1470           0 :                             truncated ? " (truncated)" : "");
    1471             : 
    1472           0 :         if (info.gcHeapLatin1 > 0) {
    1473           0 :             REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("gc-heap/latin1"),
    1474             :                 info.gcHeapLatin1,
    1475             :                 "Latin1 strings. " MAYBE_INLINE);
    1476             :         }
    1477             : 
    1478           0 :         if (info.gcHeapTwoByte > 0) {
    1479           0 :             REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("gc-heap/two-byte"),
    1480             :                 info.gcHeapTwoByte,
    1481             :                 "TwoByte strings. " MAYBE_INLINE);
    1482             :         }
    1483             : 
    1484           0 :         if (info.mallocHeapLatin1 > 0) {
    1485           0 :             REPORT_BYTES(path + NS_LITERAL_CSTRING("malloc-heap/latin1"),
    1486             :                 KIND_HEAP, info.mallocHeapLatin1,
    1487             :                 "Non-inline Latin1 string characters. " MAYBE_OVERALLOCATED);
    1488             :         }
    1489             : 
    1490           0 :         if (info.mallocHeapTwoByte > 0) {
    1491           0 :             REPORT_BYTES(path + NS_LITERAL_CSTRING("malloc-heap/two-byte"),
    1492             :                 KIND_HEAP, info.mallocHeapTwoByte,
    1493             :                 "Non-inline TwoByte string characters. " MAYBE_OVERALLOCATED);
    1494             :         }
    1495             :     }
    1496             : 
    1497           0 :     nsCString nonNotablePath = pathPrefix;
    1498           0 :     nonNotablePath += (zStats.isTotals || anonymize)
    1499           0 :                     ? NS_LITERAL_CSTRING("strings/")
    1500           0 :                     : NS_LITERAL_CSTRING("strings/string(<non-notable strings>)/");
    1501             : 
    1502           0 :     if (zStats.stringInfo.gcHeapLatin1 > 0) {
    1503           0 :         REPORT_GC_BYTES(nonNotablePath + NS_LITERAL_CSTRING("gc-heap/latin1"),
    1504             :             zStats.stringInfo.gcHeapLatin1,
    1505             :             "Latin1 strings. " MAYBE_INLINE);
    1506             :     }
    1507             : 
    1508           0 :     if (zStats.stringInfo.gcHeapTwoByte > 0) {
    1509           0 :         REPORT_GC_BYTES(nonNotablePath + NS_LITERAL_CSTRING("gc-heap/two-byte"),
    1510             :             zStats.stringInfo.gcHeapTwoByte,
    1511             :             "TwoByte strings. " MAYBE_INLINE);
    1512             :     }
    1513             : 
    1514           0 :     if (zStats.stringInfo.mallocHeapLatin1 > 0) {
    1515           0 :         REPORT_BYTES(nonNotablePath + NS_LITERAL_CSTRING("malloc-heap/latin1"),
    1516             :             KIND_HEAP, zStats.stringInfo.mallocHeapLatin1,
    1517             :             "Non-inline Latin1 string characters. " MAYBE_OVERALLOCATED);
    1518             :     }
    1519             : 
    1520           0 :     if (zStats.stringInfo.mallocHeapTwoByte > 0) {
    1521           0 :         REPORT_BYTES(nonNotablePath + NS_LITERAL_CSTRING("malloc-heap/two-byte"),
    1522             :             KIND_HEAP, zStats.stringInfo.mallocHeapTwoByte,
    1523             :             "Non-inline TwoByte string characters. " MAYBE_OVERALLOCATED);
    1524             :     }
    1525             : 
    1526           0 :     if (stringsNotableAboutMemoryGCHeap > 0) {
    1527           0 :         MOZ_ASSERT(!zStats.isTotals);
    1528           0 :         REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("strings/string(<about-memory>)/gc-heap"),
    1529             :             stringsNotableAboutMemoryGCHeap,
    1530             :             "Strings that contain the characters '" STRING_LENGTH "', which "
    1531             :             "are probably from about:memory itself." MAYBE_INLINE
    1532             :             " We filter them out rather than display them, because displaying "
    1533             :             "them would create even more such strings every time about:memory "
    1534             :             "is refreshed.");
    1535             :     }
    1536             : 
    1537           0 :     if (stringsNotableAboutMemoryMallocHeap > 0) {
    1538           0 :         MOZ_ASSERT(!zStats.isTotals);
    1539           0 :         REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("strings/string(<about-memory>)/malloc-heap"),
    1540             :             KIND_HEAP, stringsNotableAboutMemoryMallocHeap,
    1541             :             "Non-inline string characters of strings that contain the "
    1542             :             "characters '" STRING_LENGTH "', which are probably from "
    1543             :             "about:memory itself. " MAYBE_OVERALLOCATED
    1544             :             " We filter them out rather than display them, because displaying "
    1545             :             "them would create even more such strings every time about:memory "
    1546             :             "is refreshed.");
    1547             :     }
    1548             : 
    1549           0 :     const JS::ShapeInfo& shapeInfo = zStats.shapeInfo;
    1550           0 :     if (shapeInfo.shapesGCHeapTree > 0) {
    1551           0 :         REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("shapes/gc-heap/tree"),
    1552             :             shapeInfo.shapesGCHeapTree,
    1553             :         "Shapes in a property tree.");
    1554             :     }
    1555             : 
    1556           0 :     if (shapeInfo.shapesGCHeapDict > 0) {
    1557           0 :         REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("shapes/gc-heap/dict"),
    1558             :             shapeInfo.shapesGCHeapDict,
    1559             :         "Shapes in dictionary mode.");
    1560             :     }
    1561             : 
    1562           0 :     if (shapeInfo.shapesGCHeapBase > 0) {
    1563           0 :         REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("shapes/gc-heap/base"),
    1564             :             shapeInfo.shapesGCHeapBase,
    1565             :             "Base shapes, which collate data common to many shapes.");
    1566             :     }
    1567             : 
    1568           0 :     if (shapeInfo.shapesMallocHeapTreeTables > 0) {
    1569           0 :         REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-tables"),
    1570             :             KIND_HEAP, shapeInfo.shapesMallocHeapTreeTables,
    1571             :             "Property tables of shapes in a property tree.");
    1572             :     }
    1573             : 
    1574           0 :     if (shapeInfo.shapesMallocHeapDictTables > 0) {
    1575           0 :         REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("shapes/malloc-heap/dict-tables"),
    1576             :             KIND_HEAP, shapeInfo.shapesMallocHeapDictTables,
    1577             :             "Property tables of shapes in dictionary mode.");
    1578             :     }
    1579             : 
    1580           0 :     if (shapeInfo.shapesMallocHeapTreeKids > 0) {
    1581           0 :         REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-kids"),
    1582             :             KIND_HEAP, shapeInfo.shapesMallocHeapTreeKids,
    1583             :             "Kid hashes of shapes in a property tree.");
    1584             :     }
    1585             : 
    1586           0 :     if (sundriesGCHeap > 0) {
    1587             :         // We deliberately don't use ZRREPORT_GC_BYTES here.
    1588           0 :         REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("sundries/gc-heap"),
    1589             :             sundriesGCHeap,
    1590             :             "The sum of all 'gc-heap' measurements that are too small to be "
    1591             :             "worth showing individually.");
    1592             :     }
    1593             : 
    1594           0 :     if (sundriesMallocHeap > 0) {
    1595             :         // We deliberately don't use ZRREPORT_BYTES here.
    1596           0 :         REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("sundries/malloc-heap"),
    1597             :             KIND_HEAP, sundriesMallocHeap,
    1598             :             "The sum of all 'malloc-heap' measurements that are too small to "
    1599             :             "be worth showing individually.");
    1600             :     }
    1601             : 
    1602           0 :     if (gcTotalOut)
    1603           0 :         *gcTotalOut += gcTotal;
    1604             : 
    1605             : #   undef STRING_LENGTH
    1606           0 : }
    1607             : 
    1608             : static void
    1609           0 : ReportClassStats(const ClassInfo& classInfo, const nsACString& path,
    1610             :                  nsIHandleReportCallback* handleReport,
    1611             :                  nsISupports* data, size_t& gcTotal)
    1612             : {
    1613             :     // We deliberately don't use ZRREPORT_BYTES, so that these per-class values
    1614             :     // don't go into sundries.
    1615             : 
    1616           0 :     if (classInfo.objectsGCHeap > 0) {
    1617           0 :         REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("objects/gc-heap"),
    1618             :             classInfo.objectsGCHeap,
    1619             :             "Objects, including fixed slots.");
    1620             :     }
    1621             : 
    1622           0 :     if (classInfo.objectsMallocHeapSlots > 0) {
    1623           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/slots"),
    1624             :             KIND_HEAP, classInfo.objectsMallocHeapSlots,
    1625             :             "Non-fixed object slots.");
    1626             :     }
    1627             : 
    1628           0 :     if (classInfo.objectsMallocHeapElementsNormal > 0) {
    1629           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/elements/normal"),
    1630             :             KIND_HEAP, classInfo.objectsMallocHeapElementsNormal,
    1631             :             "Normal (non-wasm) indexed elements.");
    1632             :     }
    1633             : 
    1634           0 :     if (classInfo.objectsMallocHeapElementsAsmJS > 0) {
    1635           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/elements/asm.js"),
    1636             :             KIND_HEAP, classInfo.objectsMallocHeapElementsAsmJS,
    1637             :             "asm.js array buffer elements allocated in the malloc heap.");
    1638             :     }
    1639             : 
    1640           0 :     if (classInfo.objectsMallocHeapMisc > 0) {
    1641           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/misc"),
    1642             :             KIND_HEAP, classInfo.objectsMallocHeapMisc,
    1643             :             "Miscellaneous object data.");
    1644             :     }
    1645             : 
    1646           0 :     if (classInfo.objectsNonHeapElementsNormal > 0) {
    1647           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/normal"),
    1648             :             KIND_NONHEAP, classInfo.objectsNonHeapElementsNormal,
    1649             :             "Memory-mapped non-shared array buffer elements.");
    1650             :     }
    1651             : 
    1652           0 :     if (classInfo.objectsNonHeapElementsShared > 0) {
    1653           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/shared"),
    1654             :             KIND_NONHEAP, classInfo.objectsNonHeapElementsShared,
    1655             :             "Memory-mapped shared array buffer elements. These elements are "
    1656             :             "shared between one or more runtimes; the reported size is divided "
    1657             :             "by the buffer's refcount.");
    1658             :     }
    1659             : 
    1660             :     // WebAssembly memories are always non-heap-allocated (mmap). We never put
    1661             :     // these under sundries, because (a) in practice they're almost always
    1662             :     // larger than the sundries threshold, and (b) we'd need a third category of
    1663             :     // sundries ("non-heap"), which would be a pain.
    1664           0 :     if (classInfo.objectsNonHeapElementsWasm > 0) {
    1665           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/wasm"),
    1666             :             KIND_NONHEAP, classInfo.objectsNonHeapElementsWasm,
    1667             :             "wasm/asm.js array buffer elements allocated outside both the "
    1668             :             "malloc heap and the GC heap.");
    1669             :     }
    1670             : 
    1671           0 :     if (classInfo.objectsNonHeapCodeWasm > 0) {
    1672           0 :         REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/code/wasm"),
    1673             :             KIND_NONHEAP, classInfo.objectsNonHeapCodeWasm,
    1674             :             "AOT-compiled wasm/asm.js code.");
    1675             :     }
    1676             : 
    1677             :     // Although wasm guard pages aren't committed in memory they can be very
    1678             :     // large and contribute greatly to vsize and so are worth reporting.
    1679           0 :     if (classInfo.wasmGuardPages > 0) {
    1680           0 :         REPORT_BYTES(NS_LITERAL_CSTRING("wasm-guard-pages"),
    1681             :             KIND_OTHER, classInfo.wasmGuardPages,
    1682             :             "Guard pages mapped after the end of wasm memories, reserved for "
    1683             :             "optimization tricks, but not committed and thus never contributing"
    1684             :             " to RSS, only vsize.");
    1685             :     }
    1686           0 : }
    1687             : 
    1688             : static void
    1689           0 : ReportRealmStats(const JS::RealmStats& realmStats,
    1690             :                  const xpc::RealmStatsExtras& extras,
    1691             :                  nsIHandleReportCallback* handleReport,
    1692             :                  nsISupports* data, size_t* gcTotalOut = nullptr)
    1693             : {
    1694           0 :     static const nsDependentCString addonPrefix("explicit/add-ons/");
    1695             : 
    1696           0 :     size_t gcTotal = 0, sundriesGCHeap = 0, sundriesMallocHeap = 0;
    1697           0 :     nsAutoCString realmJSPathPrefix(extras.jsPathPrefix);
    1698           0 :     nsAutoCString realmDOMPathPrefix(extras.domPathPrefix);
    1699             : 
    1700           0 :     MOZ_ASSERT(!gcTotalOut == realmStats.isTotals);
    1701             : 
    1702           0 :     nsCString nonNotablePath = realmJSPathPrefix;
    1703           0 :     nonNotablePath += realmStats.isTotals
    1704           0 :                     ? NS_LITERAL_CSTRING("classes/")
    1705           0 :                     : NS_LITERAL_CSTRING("classes/class(<non-notable classes>)/");
    1706             : 
    1707           0 :     ReportClassStats(realmStats.classInfo, nonNotablePath, handleReport, data,
    1708           0 :                      gcTotal);
    1709             : 
    1710           0 :     for (size_t i = 0; i < realmStats.notableClasses.length(); i++) {
    1711           0 :         MOZ_ASSERT(!realmStats.isTotals);
    1712           0 :         const JS::NotableClassInfo& classInfo = realmStats.notableClasses[i];
    1713             : 
    1714           0 :         nsCString classPath = realmJSPathPrefix +
    1715           0 :             nsPrintfCString("classes/class(%s)/", classInfo.className_);
    1716             : 
    1717           0 :         ReportClassStats(classInfo, classPath, handleReport, data, gcTotal);
    1718             :     }
    1719             : 
    1720             :     // Note that we use realmDOMPathPrefix here.  This is because we measure orphan
    1721             :     // DOM nodes in the JS reporter, but we want to report them in a "dom"
    1722             :     // sub-tree rather than a "js" sub-tree.
    1723           0 :     ZRREPORT_BYTES(realmDOMPathPrefix + NS_LITERAL_CSTRING("orphan-nodes"),
    1724             :         realmStats.objectsPrivate,
    1725             :         "Orphan DOM nodes, i.e. those that are only reachable from JavaScript "
    1726             :         "objects.");
    1727             : 
    1728           0 :     ZRREPORT_GC_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("scripts/gc-heap"),
    1729             :         realmStats.scriptsGCHeap,
    1730             :         "JSScript instances. There is one per user-defined function in a "
    1731             :         "script, and one for the top-level code in a script.");
    1732             : 
    1733           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("scripts/malloc-heap/data"),
    1734             :         realmStats.scriptsMallocHeapData,
    1735             :         "Various variable-length tables in JSScripts.");
    1736             : 
    1737           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("baseline/data"),
    1738             :         realmStats.baselineData,
    1739             :         "The Baseline JIT's compilation data (BaselineScripts).");
    1740             : 
    1741           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("baseline/fallback-stubs"),
    1742             :         realmStats.baselineStubsFallback,
    1743             :         "The Baseline JIT's fallback IC stubs (excluding code).");
    1744             : 
    1745           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("ion-data"),
    1746             :         realmStats.ionData,
    1747             :         "The IonMonkey JIT's compilation data (IonScripts).");
    1748             : 
    1749           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("type-inference/type-scripts"),
    1750             :         realmStats.typeInferenceTypeScripts,
    1751             :         "Type sets associated with scripts.");
    1752             : 
    1753           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("type-inference/allocation-site-tables"),
    1754             :         realmStats.typeInferenceAllocationSiteTables,
    1755             :         "Tables of type objects associated with allocation sites.");
    1756             : 
    1757           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("type-inference/array-type-tables"),
    1758             :         realmStats.typeInferenceArrayTypeTables,
    1759             :         "Tables of type objects associated with array literals.");
    1760             : 
    1761           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("type-inference/object-type-tables"),
    1762             :         realmStats.typeInferenceObjectTypeTables,
    1763             :         "Tables of type objects associated with object literals.");
    1764             : 
    1765           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("realm-object"),
    1766             :         realmStats.realmObject,
    1767             :         "The JS::Realm object itself.");
    1768             : 
    1769           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("realm-tables"),
    1770             :         realmStats.realmTables,
    1771             :         "Realm-wide tables storing object group information and wasm instances.");
    1772             : 
    1773           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("inner-views"),
    1774             :         realmStats.innerViewsTable,
    1775             :         "The table for array buffer inner views.");
    1776             : 
    1777           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("lazy-array-buffers"),
    1778             :         realmStats.lazyArrayBuffersTable,
    1779             :         "The table for typed object lazy array buffers.");
    1780             : 
    1781           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("object-metadata"),
    1782             :         realmStats.objectMetadataTable,
    1783             :         "The table used by debugging tools for tracking object metadata");
    1784             : 
    1785           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("saved-stacks-set"),
    1786             :         realmStats.savedStacksSet,
    1787             :         "The saved stacks set.");
    1788             : 
    1789           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("non-syntactic-lexical-scopes-table"),
    1790             :         realmStats.nonSyntacticLexicalScopesTable,
    1791             :         "The non-syntactic lexical scopes table.");
    1792             : 
    1793           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("jit-realm"),
    1794             :         realmStats.jitRealm,
    1795             :         "The JIT realm.");
    1796             : 
    1797           0 :     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("script-counts-map"),
    1798             :         realmStats.scriptCountsMap,
    1799             :         "Profiling-related information for scripts.");
    1800             : 
    1801           0 :     if (sundriesGCHeap > 0) {
    1802             :         // We deliberately don't use ZRREPORT_GC_BYTES here.
    1803           0 :         REPORT_GC_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("sundries/gc-heap"),
    1804             :             sundriesGCHeap,
    1805             :             "The sum of all 'gc-heap' measurements that are too small to be "
    1806             :             "worth showing individually.");
    1807             :     }
    1808             : 
    1809           0 :     if (sundriesMallocHeap > 0) {
    1810             :         // We deliberately don't use ZRREPORT_BYTES here.
    1811           0 :         REPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("sundries/malloc-heap"),
    1812             :             KIND_HEAP, sundriesMallocHeap,
    1813             :             "The sum of all 'malloc-heap' measurements that are too small to "
    1814             :             "be worth showing individually.");
    1815             :     }
    1816             : 
    1817           0 :     if (gcTotalOut)
    1818           0 :         *gcTotalOut += gcTotal;
    1819           0 : }
    1820             : 
    1821             : static void
    1822           0 : ReportScriptSourceStats(const ScriptSourceInfo& scriptSourceInfo,
    1823             :                         const nsACString& path,
    1824             :                         nsIHandleReportCallback* handleReport,
    1825             :                         nsISupports* data, size_t& rtTotal)
    1826             : {
    1827           0 :     if (scriptSourceInfo.misc > 0) {
    1828           0 :         RREPORT_BYTES(path + NS_LITERAL_CSTRING("misc"),
    1829             :             KIND_HEAP, scriptSourceInfo.misc,
    1830             :             "Miscellaneous data relating to JavaScript source code.");
    1831             :     }
    1832           0 : }
    1833             : 
    1834             : void
    1835           0 : ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats& rtStats,
    1836             :                                  const nsACString& rtPath,
    1837             :                                  nsIHandleReportCallback* handleReport,
    1838             :                                  nsISupports* data,
    1839             :                                  bool anonymize,
    1840             :                                  size_t* rtTotalOut)
    1841             : {
    1842           0 :     size_t gcTotal = 0;
    1843             : 
    1844           0 :     for (size_t i = 0; i < rtStats.zoneStatsVector.length(); i++) {
    1845           0 :         const JS::ZoneStats& zStats = rtStats.zoneStatsVector[i];
    1846             :         const xpc::ZoneStatsExtras* extras =
    1847           0 :           static_cast<const xpc::ZoneStatsExtras*>(zStats.extra);
    1848           0 :         ReportZoneStats(zStats, *extras, handleReport, data, anonymize,
    1849           0 :                         &gcTotal);
    1850             :     }
    1851             : 
    1852           0 :     for (size_t i = 0; i < rtStats.realmStatsVector.length(); i++) {
    1853           0 :         const JS::RealmStats& realmStats = rtStats.realmStatsVector[i];
    1854             :         const xpc::RealmStatsExtras* extras =
    1855           0 :             static_cast<const xpc::RealmStatsExtras*>(realmStats.extra);
    1856             : 
    1857           0 :         ReportRealmStats(realmStats, *extras, handleReport, data, &gcTotal);
    1858             :     }
    1859             : 
    1860             :     // Report the rtStats.runtime numbers under "runtime/", and compute their
    1861             :     // total for later.
    1862             : 
    1863           0 :     size_t rtTotal = 0;
    1864             : 
    1865           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/runtime-object"),
    1866             :         KIND_HEAP, rtStats.runtime.object,
    1867             :         "The JSRuntime object.");
    1868             : 
    1869           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/atoms-table"),
    1870             :         KIND_HEAP, rtStats.runtime.atomsTable,
    1871             :         "The atoms table.");
    1872             : 
    1873           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/atoms-mark-bitmaps"),
    1874             :         KIND_HEAP, rtStats.runtime.atomsMarkBitmaps,
    1875             :         "Mark bitmaps for atoms held by each zone.");
    1876             : 
    1877           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/contexts"),
    1878             :         KIND_HEAP, rtStats.runtime.contexts,
    1879             :         "JSContext objects and structures that belong to them.");
    1880             : 
    1881           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/temporary"),
    1882             :         KIND_HEAP, rtStats.runtime.temporary,
    1883             :         "Transient data (mostly parse nodes) held by the JSRuntime during "
    1884             :         "compilation.");
    1885             : 
    1886           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/interpreter-stack"),
    1887             :         KIND_HEAP, rtStats.runtime.interpreterStack,
    1888             :         "JS interpreter frames.");
    1889             : 
    1890           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/math-cache"),
    1891             :         KIND_HEAP, rtStats.runtime.mathCache,
    1892             :         "The math cache.");
    1893             : 
    1894           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/shared-immutable-strings-cache"),
    1895             :         KIND_HEAP, rtStats.runtime.sharedImmutableStringsCache,
    1896             :         "Immutable strings (such as JS scripts' source text) shared across all JSRuntimes.");
    1897             : 
    1898           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/shared-intl-data"),
    1899             :         KIND_HEAP, rtStats.runtime.sharedIntlData,
    1900             :         "Shared internationalization data.");
    1901             : 
    1902           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/uncompressed-source-cache"),
    1903             :         KIND_HEAP, rtStats.runtime.uncompressedSourceCache,
    1904             :         "The uncompressed source code cache.");
    1905             : 
    1906           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-data"),
    1907             :         KIND_HEAP, rtStats.runtime.scriptData,
    1908             :         "The table holding script data shared in the runtime.");
    1909             : 
    1910           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/tracelogger"),
    1911             :         KIND_HEAP, rtStats.runtime.tracelogger,
    1912             :         "The memory used for the tracelogger (per-runtime).");
    1913             : 
    1914             :     nsCString nonNotablePath =
    1915           0 :         rtPath + nsPrintfCString("runtime/script-sources/source(scripts=%d, <non-notable files>)/",
    1916           0 :                                  rtStats.runtime.scriptSourceInfo.numScripts);
    1917             : 
    1918           0 :     ReportScriptSourceStats(rtStats.runtime.scriptSourceInfo,
    1919           0 :                             nonNotablePath, handleReport, data, rtTotal);
    1920             : 
    1921           0 :     for (size_t i = 0; i < rtStats.runtime.notableScriptSources.length(); i++) {
    1922             :         const JS::NotableScriptSourceInfo& scriptSourceInfo =
    1923           0 :             rtStats.runtime.notableScriptSources[i];
    1924             : 
    1925             :         // Escape / to \ before we put the filename into the memory reporter
    1926             :         // path, because we don't want any forward slashes in the string to
    1927             :         // count as path separators. Consumers of memory reporters (e.g.
    1928             :         // about:memory) will convert them back to / after doing path
    1929             :         // splitting.
    1930           0 :         nsCString escapedFilename;
    1931           0 :         if (anonymize) {
    1932           0 :             escapedFilename.AppendPrintf("<anonymized-source-%d>", int(i));
    1933             :         } else {
    1934           0 :             nsDependentCString filename(scriptSourceInfo.filename_);
    1935           0 :             escapedFilename.Append(filename);
    1936           0 :             escapedFilename.ReplaceSubstring("/", "\\");
    1937             :         }
    1938             : 
    1939           0 :         nsCString notablePath = rtPath +
    1940           0 :             nsPrintfCString("runtime/script-sources/source(scripts=%d, %s)/",
    1941           0 :                             scriptSourceInfo.numScripts, escapedFilename.get());
    1942             : 
    1943           0 :         ReportScriptSourceStats(scriptSourceInfo, notablePath,
    1944           0 :                                 handleReport, data, rtTotal);
    1945             :     }
    1946             : 
    1947           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/ion"),
    1948             :         KIND_NONHEAP, rtStats.runtime.code.ion,
    1949             :         "Code generated by the IonMonkey JIT.");
    1950             : 
    1951           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/baseline"),
    1952             :         KIND_NONHEAP, rtStats.runtime.code.baseline,
    1953             :         "Code generated by the Baseline JIT.");
    1954             : 
    1955           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/regexp"),
    1956             :         KIND_NONHEAP, rtStats.runtime.code.regexp,
    1957             :         "Code generated by the regexp JIT.");
    1958             : 
    1959           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/other"),
    1960             :         KIND_NONHEAP, rtStats.runtime.code.other,
    1961             :         "Code generated by the JITs for wrappers and trampolines.");
    1962             : 
    1963           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/unused"),
    1964             :         KIND_NONHEAP, rtStats.runtime.code.unused,
    1965             :         "Memory allocated by one of the JITs to hold code, but which is "
    1966             :         "currently unused.");
    1967             : 
    1968           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/marker"),
    1969             :         KIND_HEAP, rtStats.runtime.gc.marker,
    1970             :         "The GC mark stack and gray roots.");
    1971             : 
    1972           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery-committed"),
    1973             :         KIND_NONHEAP, rtStats.runtime.gc.nurseryCommitted,
    1974             :         "Memory being used by the GC's nursery.");
    1975             : 
    1976           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery-malloced-buffers"),
    1977             :         KIND_HEAP, rtStats.runtime.gc.nurseryMallocedBuffers,
    1978             :         "Out-of-line slots and elements belonging to objects in the nursery.");
    1979             : 
    1980           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/vals"),
    1981             :         KIND_HEAP, rtStats.runtime.gc.storeBufferVals,
    1982             :         "Values in the store buffer.");
    1983             : 
    1984           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/cells"),
    1985             :         KIND_HEAP, rtStats.runtime.gc.storeBufferCells,
    1986             :         "Cells in the store buffer.");
    1987             : 
    1988           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/slots"),
    1989             :         KIND_HEAP, rtStats.runtime.gc.storeBufferSlots,
    1990             :         "Slots in the store buffer.");
    1991             : 
    1992           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/whole-cells"),
    1993             :         KIND_HEAP, rtStats.runtime.gc.storeBufferWholeCells,
    1994             :         "Whole cells in the store buffer.");
    1995             : 
    1996           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/generics"),
    1997             :         KIND_HEAP, rtStats.runtime.gc.storeBufferGenerics,
    1998             :         "Generic things in the store buffer.");
    1999             : 
    2000           0 :     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/jit-lazylink"),
    2001             :         KIND_HEAP, rtStats.runtime.jitLazyLink,
    2002             :         "IonMonkey compilations waiting for lazy linking.");
    2003             : 
    2004           0 :     if (rtTotalOut)
    2005           0 :         *rtTotalOut = rtTotal;
    2006             : 
    2007             :     // Report GC numbers that don't belong to a realm.
    2008             : 
    2009             :     // We don't want to report decommitted memory in "explicit", so we just
    2010             :     // change the leading "explicit/" to "decommitted/".
    2011           0 :     nsCString rtPath2(rtPath);
    2012           0 :     rtPath2.ReplaceLiteral(0, strlen("explicit"), "decommitted");
    2013             : 
    2014           0 :     REPORT_GC_BYTES(rtPath2 + NS_LITERAL_CSTRING("gc-heap/decommitted-arenas"),
    2015             :         rtStats.gcHeapDecommittedArenas,
    2016             :         "GC arenas in non-empty chunks that is decommitted, i.e. it takes up "
    2017             :         "address space but no physical memory or swap space.");
    2018             : 
    2019           0 :     REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-chunks"),
    2020             :         rtStats.gcHeapUnusedChunks,
    2021             :         "Empty GC chunks which will soon be released unless claimed for new "
    2022             :         "allocations.");
    2023             : 
    2024           0 :     REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-arenas"),
    2025             :         rtStats.gcHeapUnusedArenas,
    2026             :         "Empty GC arenas within non-empty chunks.");
    2027             : 
    2028           0 :     REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/chunk-admin"),
    2029             :         rtStats.gcHeapChunkAdmin,
    2030             :         "Bookkeeping information within GC chunks.");
    2031             : 
    2032             :     // gcTotal is the sum of everything we've reported for the GC heap.  It
    2033             :     // should equal rtStats.gcHeapChunkTotal.
    2034           0 :     MOZ_ASSERT(gcTotal == rtStats.gcHeapChunkTotal);
    2035           0 : }
    2036             : 
    2037             : 
    2038             : } // namespace xpc
    2039             : 
    2040           0 : class JSMainRuntimeRealmsReporter final : public nsIMemoryReporter
    2041             : {
    2042             : 
    2043           0 :     ~JSMainRuntimeRealmsReporter() {}
    2044             : 
    2045             :   public:
    2046             :     NS_DECL_ISUPPORTS
    2047             : 
    2048           0 :     struct Data {
    2049             :         int anonymizeID;
    2050             :         js::Vector<nsCString, 0, js::SystemAllocPolicy> paths;
    2051             :     };
    2052             : 
    2053           0 :     static void RealmCallback(JSContext* cx, void* vdata, Handle<Realm*> realm) {
    2054             :         // silently ignore OOM errors
    2055           0 :         Data* data = static_cast<Data*>(vdata);
    2056           0 :         nsCString path;
    2057           0 :         GetRealmName(realm, path, &data->anonymizeID, /* replaceSlashes = */ true);
    2058           0 :         path.Insert(js::IsSystemRealm(realm)
    2059           0 :                     ? NS_LITERAL_CSTRING("js-main-runtime-realms/system/")
    2060           0 :                     : NS_LITERAL_CSTRING("js-main-runtime-realms/user/"),
    2061           0 :                     0);
    2062           0 :         mozilla::Unused << data->paths.append(path);
    2063           0 :     }
    2064             : 
    2065           0 :     NS_IMETHOD CollectReports(nsIHandleReportCallback* handleReport,
    2066             :                               nsISupports* data, bool anonymize) override
    2067             :     {
    2068             :         // First we collect the realm paths.  Then we report them.  Doing
    2069             :         // the two steps interleaved is a bad idea, because calling
    2070             :         // |handleReport| from within RealmCallback() leads to all manner
    2071             :         // of assertions.
    2072             : 
    2073           0 :         Data d;
    2074           0 :         d.anonymizeID = anonymize ? 1 : 0;
    2075           0 :         JS::IterateRealms(XPCJSContext::Get()->Context(), &d, RealmCallback);
    2076             : 
    2077           0 :         for (size_t i = 0; i < d.paths.length(); i++)
    2078           0 :             REPORT(nsCString(d.paths[i]), KIND_OTHER, UNITS_COUNT, 1,
    2079             :                 "A live realm in the main JSRuntime.");
    2080             : 
    2081           0 :         return NS_OK;
    2082             :     }
    2083             : };
    2084             : 
    2085          46 : NS_IMPL_ISUPPORTS(JSMainRuntimeRealmsReporter, nsIMemoryReporter)
    2086             : 
    2087           0 : MOZ_DEFINE_MALLOC_SIZE_OF(OrphanMallocSizeOf)
    2088             : 
    2089             : namespace xpc {
    2090             : 
    2091           0 : class OrphanReporter : public JS::ObjectPrivateVisitor
    2092             : {
    2093             :   public:
    2094           0 :     explicit OrphanReporter(GetISupportsFun aGetISupports)
    2095           0 :       : JS::ObjectPrivateVisitor(aGetISupports)
    2096           0 :       , mState(OrphanMallocSizeOf)
    2097           0 :     {}
    2098             : 
    2099           0 :     virtual size_t sizeOfIncludingThis(nsISupports* aSupports) override
    2100             :     {
    2101           0 :         size_t n = 0;
    2102           0 :         nsCOMPtr<nsINode> node = do_QueryInterface(aSupports);
    2103             :         // https://bugzilla.mozilla.org/show_bug.cgi?id=773533#c11 explains
    2104             :         // that we have to skip XBL elements because they violate certain
    2105             :         // assumptions.  Yuk.
    2106           0 :         if (node && !node->IsInUncomposedDoc() &&
    2107           0 :             !(node->IsElement() && node->AsElement()->IsInNamespace(kNameSpaceID_XBL)))
    2108             :         {
    2109             :             // This is an orphan node.  If we haven't already handled the
    2110             :             // sub-tree that this node belongs to, measure the sub-tree's size
    2111             :             // and then record its root so we don't measure it again.
    2112           0 :             nsCOMPtr<nsINode> orphanTree = node->SubtreeRoot();
    2113           0 :             if (orphanTree && !mState.HaveSeenPtr(orphanTree.get())) {
    2114           0 :                 n += SizeOfTreeIncludingThis(orphanTree);
    2115             :             }
    2116             :         }
    2117           0 :         return n;
    2118             :     }
    2119             : 
    2120           0 :     size_t SizeOfTreeIncludingThis(nsINode* tree)
    2121             :     {
    2122           0 :         size_t nodeSize = 0;
    2123           0 :         nsWindowSizes sizes(mState);
    2124           0 :         tree->AddSizeOfIncludingThis(sizes, &nodeSize);
    2125           0 :         for (nsIContent* child = tree->GetFirstChild(); child; child = child->GetNextNode(tree))
    2126           0 :             child->AddSizeOfIncludingThis(sizes, &nodeSize);
    2127             : 
    2128             :         // We combine the node size with nsStyleSizes here. It's not ideal, but
    2129             :         // it's hard to get the style structs measurements out to
    2130             :         // nsWindowMemoryReporter. Also, we drop mServoData in
    2131             :         // UnbindFromTree(), so in theory any non-in-tree element won't have
    2132             :         // any style data to measure.
    2133           0 :         return nodeSize + sizes.getTotalSize();
    2134             :     }
    2135             : 
    2136             :   private:
    2137             :     SizeOfState mState;
    2138             : };
    2139             : 
    2140             : #ifdef DEBUG
    2141             : static bool
    2142           0 : StartsWithExplicit(nsACString& s)
    2143             : {
    2144           0 :     return StringBeginsWith(s, NS_LITERAL_CSTRING("explicit/"));
    2145             : }
    2146             : #endif
    2147             : 
    2148             : class XPCJSRuntimeStats : public JS::RuntimeStats
    2149             : {
    2150             :     WindowPaths* mWindowPaths;
    2151             :     WindowPaths* mTopWindowPaths;
    2152             :     int mAnonymizeID;
    2153             : 
    2154             :   public:
    2155           0 :     XPCJSRuntimeStats(WindowPaths* windowPaths, WindowPaths* topWindowPaths,
    2156             :                       bool anonymize)
    2157           0 :       : JS::RuntimeStats(JSMallocSizeOf),
    2158             :         mWindowPaths(windowPaths),
    2159             :         mTopWindowPaths(topWindowPaths),
    2160           0 :         mAnonymizeID(anonymize ? 1 : 0)
    2161           0 :     {}
    2162             : 
    2163           0 :     ~XPCJSRuntimeStats() {
    2164           0 :         for (size_t i = 0; i != realmStatsVector.length(); ++i)
    2165           0 :             delete static_cast<xpc::RealmStatsExtras*>(realmStatsVector[i].extra);
    2166             : 
    2167           0 :         for (size_t i = 0; i != zoneStatsVector.length(); ++i)
    2168           0 :             delete static_cast<xpc::ZoneStatsExtras*>(zoneStatsVector[i].extra);
    2169           0 :     }
    2170             : 
    2171           0 :     virtual void initExtraZoneStats(JS::Zone* zone, JS::ZoneStats* zStats) override {
    2172           0 :         AutoSafeJSContext cx;
    2173           0 :         xpc::ZoneStatsExtras* extras = new xpc::ZoneStatsExtras;
    2174           0 :         extras->pathPrefix.AssignLiteral("explicit/js-non-window/zones/");
    2175             : 
    2176             :         // Get some global in this zone.
    2177           0 :         Rooted<Realm*> realm(cx, js::GetAnyRealmInZone(zone));
    2178           0 :         if (realm) {
    2179           0 :             RootedObject global(cx, JS::GetRealmGlobalOrNull(realm));
    2180           0 :             if (global) {
    2181           0 :                 RefPtr<nsGlobalWindowInner> window;
    2182           0 :                 if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, window))) {
    2183             :                     // The global is a |window| object.  Use the path prefix that
    2184             :                     // we should have already created for it.
    2185           0 :                     if (mTopWindowPaths->Get(window->WindowID(),
    2186             :                                              &extras->pathPrefix))
    2187           0 :                         extras->pathPrefix.AppendLiteral("/js-");
    2188             :                 }
    2189             :             }
    2190             :         }
    2191             : 
    2192           0 :         extras->pathPrefix += nsPrintfCString("zone(0x%p)/", (void*)zone);
    2193             : 
    2194           0 :         MOZ_ASSERT(StartsWithExplicit(extras->pathPrefix));
    2195             : 
    2196           0 :         zStats->extra = extras;
    2197           0 :     }
    2198             : 
    2199           0 :     virtual void initExtraRealmStats(Handle<Realm*> realm,
    2200             :                                      JS::RealmStats* realmStats) override
    2201             :     {
    2202           0 :         xpc::RealmStatsExtras* extras = new xpc::RealmStatsExtras;
    2203           0 :         nsCString rName;
    2204           0 :         GetRealmName(realm, rName, &mAnonymizeID, /* replaceSlashes = */ true);
    2205             : 
    2206             :         // Get the realm's global.
    2207           0 :         AutoSafeJSContext cx;
    2208           0 :         bool needZone = true;
    2209           0 :         RootedObject global(cx, JS::GetRealmGlobalOrNull(realm));
    2210           0 :         if (global) {
    2211           0 :             RefPtr<nsGlobalWindowInner> window;
    2212           0 :             if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, window))) {
    2213             :                 // The global is a |window| object.  Use the path prefix that
    2214             :                 // we should have already created for it.
    2215           0 :                 if (mWindowPaths->Get(window->WindowID(),
    2216             :                                       &extras->jsPathPrefix)) {
    2217           0 :                     extras->domPathPrefix.Assign(extras->jsPathPrefix);
    2218           0 :                     extras->domPathPrefix.AppendLiteral("/dom/");
    2219           0 :                     extras->jsPathPrefix.AppendLiteral("/js-");
    2220           0 :                     needZone = false;
    2221             :                 } else {
    2222           0 :                     extras->jsPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
    2223           0 :                     extras->domPathPrefix.AssignLiteral("explicit/dom/unknown-window-global?!/");
    2224             :                 }
    2225             :             } else {
    2226           0 :                 extras->jsPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
    2227           0 :                 extras->domPathPrefix.AssignLiteral("explicit/dom/non-window-global?!/");
    2228             :             }
    2229             :         } else {
    2230           0 :             extras->jsPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
    2231           0 :             extras->domPathPrefix.AssignLiteral("explicit/dom/no-global?!/");
    2232             :         }
    2233             : 
    2234           0 :         if (needZone)
    2235           0 :             extras->jsPathPrefix += nsPrintfCString("zone(0x%p)/", (void*)js::GetRealmZone(realm));
    2236             : 
    2237           0 :         extras->jsPathPrefix += NS_LITERAL_CSTRING("realm(") + rName + NS_LITERAL_CSTRING(")/");
    2238             : 
    2239             :         // extras->jsPathPrefix is used for almost all the realm-specific
    2240             :         // reports. At this point it has the form
    2241             :         // "<something>realm(<rname>)/".
    2242             :         //
    2243             :         // extras->domPathPrefix is used for DOM orphan nodes, which are
    2244             :         // counted by the JS reporter but reported as part of the DOM
    2245             :         // measurements. At this point it has the form "<something>/dom/" if
    2246             :         // this realm belongs to an nsGlobalWindow, and
    2247             :         // "explicit/dom/<something>?!/" otherwise (in which case it shouldn't
    2248             :         // be used, because non-nsGlobalWindow realms shouldn't have
    2249             :         // orphan DOM nodes).
    2250             : 
    2251           0 :         MOZ_ASSERT(StartsWithExplicit(extras->jsPathPrefix));
    2252           0 :         MOZ_ASSERT(StartsWithExplicit(extras->domPathPrefix));
    2253             : 
    2254           0 :         realmStats->extra = extras;
    2255           0 :     }
    2256             : };
    2257             : 
    2258             : void
    2259           0 : JSReporter::CollectReports(WindowPaths* windowPaths,
    2260             :                            WindowPaths* topWindowPaths,
    2261             :                            nsIHandleReportCallback* handleReport,
    2262             :                            nsISupports* data,
    2263             :                            bool anonymize)
    2264             : {
    2265           0 :     XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance();
    2266             : 
    2267             :     // In the first step we get all the stats and stash them in a local
    2268             :     // data structure.  In the second step we pass all the stashed stats to
    2269             :     // the callback.  Separating these steps is important because the
    2270             :     // callback may be a JS function, and executing JS while getting these
    2271             :     // stats seems like a bad idea.
    2272             : 
    2273           0 :     XPCJSRuntimeStats rtStats(windowPaths, topWindowPaths, anonymize);
    2274           0 :     OrphanReporter orphanReporter(XPCConvert::GetISupportsFromJSObject);
    2275           0 :     JSContext* cx = XPCJSContext::Get()->Context();
    2276           0 :     if (!JS::CollectRuntimeStats(cx, &rtStats, &orphanReporter,
    2277             :                                  anonymize))
    2278             :     {
    2279           0 :         return;
    2280             :     }
    2281             : 
    2282             :     // Collect JS stats not associated with a Runtime such as helper threads or
    2283             :     // global tracelogger data. We do this here in JSReporter::CollectReports
    2284             :     // as this is used for the main Runtime in process.
    2285           0 :     JS::GlobalStats gStats(JSMallocSizeOf);
    2286           0 :     if (!JS::CollectGlobalStats(&gStats))
    2287             :         return;
    2288             : 
    2289           0 :     size_t xpcJSRuntimeSize = xpcrt->SizeOfIncludingThis(JSMallocSizeOf);
    2290             : 
    2291           0 :     size_t wrappedJSSize = xpcrt->GetMultiCompartmentWrappedJSMap()->SizeOfWrappedJS(JSMallocSizeOf);
    2292             : 
    2293           0 :     XPCWrappedNativeScope::ScopeSizeInfo sizeInfo(JSMallocSizeOf);
    2294           0 :     XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(&sizeInfo);
    2295             : 
    2296           0 :     mozJSComponentLoader* loader = mozJSComponentLoader::Get();
    2297           0 :     size_t jsComponentLoaderSize = loader ? loader->SizeOfIncludingThis(JSMallocSizeOf) : 0;
    2298             : 
    2299             :     // This is the second step (see above).  First we report stuff in the
    2300             :     // "explicit" tree, then we report other stuff.
    2301             : 
    2302           0 :     size_t rtTotal = 0;
    2303           0 :     xpc::ReportJSRuntimeExplicitTreeStats(rtStats,
    2304           0 :                                           NS_LITERAL_CSTRING("explicit/js-non-window/"),
    2305             :                                           handleReport, data,
    2306           0 :                                           anonymize, &rtTotal);
    2307             : 
    2308             :     // Report the sums of the realm numbers.
    2309           0 :     xpc::RealmStatsExtras realmExtrasTotal;
    2310           0 :     realmExtrasTotal.jsPathPrefix.AssignLiteral("js-main-runtime/realms/");
    2311           0 :     realmExtrasTotal.domPathPrefix.AssignLiteral("window-objects/dom/");
    2312           0 :     ReportRealmStats(rtStats.realmTotals, realmExtrasTotal, handleReport, data);
    2313             : 
    2314           0 :     xpc::ZoneStatsExtras zExtrasTotal;
    2315           0 :     zExtrasTotal.pathPrefix.AssignLiteral("js-main-runtime/zones/");
    2316             :     ReportZoneStats(rtStats.zTotals, zExtrasTotal, handleReport, data,
    2317           0 :                     anonymize);
    2318             : 
    2319             :     // Report the sum of the runtime/ numbers.
    2320           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/runtime"),
    2321             :         KIND_OTHER, rtTotal,
    2322             :         "The sum of all measurements under 'explicit/js-non-window/runtime/'.");
    2323             : 
    2324             :     // Report the number of HelperThread
    2325             : 
    2326           0 :     REPORT(NS_LITERAL_CSTRING("js-helper-threads/idle"),
    2327             :         KIND_OTHER, UNITS_COUNT, gStats.helperThread.idleThreadCount,
    2328             :         "The current number of idle JS HelperThreads.");
    2329             : 
    2330           0 :     REPORT(NS_LITERAL_CSTRING("js-helper-threads/active"),
    2331             :         KIND_OTHER, UNITS_COUNT, gStats.helperThread.activeThreadCount,
    2332             :         "The current number of active JS HelperThreads. Memory held by these is"
    2333             :         " not reported.");
    2334             : 
    2335             :     // Report the numbers for memory used by wasm Runtime state.
    2336           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("wasm-runtime"),
    2337             :         KIND_OTHER, rtStats.runtime.wasmRuntime,
    2338             :         "The memory used for wasm runtime bookkeeping.");
    2339             : 
    2340             :     // Report the numbers for memory outside of realms.
    2341             : 
    2342           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/gc-heap/unused-chunks"),
    2343             :         KIND_OTHER, rtStats.gcHeapUnusedChunks,
    2344             :         "The same as 'explicit/js-non-window/gc-heap/unused-chunks'.");
    2345             : 
    2346           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/gc-heap/unused-arenas"),
    2347             :         KIND_OTHER, rtStats.gcHeapUnusedArenas,
    2348             :         "The same as 'explicit/js-non-window/gc-heap/unused-arenas'.");
    2349             : 
    2350           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/gc-heap/chunk-admin"),
    2351             :         KIND_OTHER, rtStats.gcHeapChunkAdmin,
    2352             :         "The same as 'explicit/js-non-window/gc-heap/chunk-admin'.");
    2353             : 
    2354             :     // Report a breakdown of the committed GC space.
    2355             : 
    2356           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/chunks"),
    2357             :         KIND_OTHER, rtStats.gcHeapUnusedChunks,
    2358             :         "The same as 'explicit/js-non-window/gc-heap/unused-chunks'.");
    2359             : 
    2360           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/arenas"),
    2361             :         KIND_OTHER, rtStats.gcHeapUnusedArenas,
    2362             :         "The same as 'explicit/js-non-window/gc-heap/unused-arenas'.");
    2363             : 
    2364           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/objects"),
    2365             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.object,
    2366             :         "Unused object cells within non-empty arenas.");
    2367             : 
    2368           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/strings"),
    2369             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.string,
    2370             :         "Unused string cells within non-empty arenas.");
    2371             : 
    2372           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/symbols"),
    2373             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.symbol,
    2374             :         "Unused symbol cells within non-empty arenas.");
    2375             : 
    2376           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/shapes"),
    2377             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.shape,
    2378             :         "Unused shape cells within non-empty arenas.");
    2379             : 
    2380           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/base-shapes"),
    2381             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.baseShape,
    2382             :         "Unused base shape cells within non-empty arenas.");
    2383             : 
    2384           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/object-groups"),
    2385             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.objectGroup,
    2386             :         "Unused object group cells within non-empty arenas.");
    2387             : 
    2388           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/scopes"),
    2389             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.scope,
    2390             :         "Unused scope cells within non-empty arenas.");
    2391             : 
    2392           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/scripts"),
    2393             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.script,
    2394             :         "Unused script cells within non-empty arenas.");
    2395             : 
    2396           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/lazy-scripts"),
    2397             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.lazyScript,
    2398             :         "Unused lazy script cells within non-empty arenas.");
    2399             : 
    2400           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/jitcode"),
    2401             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.jitcode,
    2402             :         "Unused jitcode cells within non-empty arenas.");
    2403             : 
    2404           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things/regexp-shareds"),
    2405             :         KIND_OTHER, rtStats.zTotals.unusedGCThings.regExpShared,
    2406             :         "Unused regexpshared cells within non-empty arenas.");
    2407             : 
    2408           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/chunk-admin"),
    2409             :         KIND_OTHER, rtStats.gcHeapChunkAdmin,
    2410             :         "The same as 'explicit/js-non-window/gc-heap/chunk-admin'.");
    2411             : 
    2412           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/arena-admin"),
    2413             :         KIND_OTHER, rtStats.zTotals.gcHeapArenaAdmin,
    2414             :         "The same as 'js-main-runtime/zones/gc-heap-arena-admin'.");
    2415             : 
    2416           0 :     size_t gcThingTotal = 0;
    2417             : 
    2418           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/objects"),
    2419             :         KIND_OTHER, rtStats.realmTotals.classInfo.objectsGCHeap,
    2420             :         "Used object cells.");
    2421             : 
    2422           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/strings"),
    2423             :         KIND_OTHER, rtStats.zTotals.stringInfo.sizeOfLiveGCThings(),
    2424             :         "Used string cells.");
    2425             : 
    2426           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/symbols"),
    2427             :         KIND_OTHER, rtStats.zTotals.symbolsGCHeap,
    2428             :         "Used symbol cells.");
    2429             : 
    2430           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/shapes"),
    2431             :         KIND_OTHER,
    2432             :         rtStats.zTotals.shapeInfo.shapesGCHeapTree + rtStats.zTotals.shapeInfo.shapesGCHeapDict,
    2433             :         "Used shape cells.");
    2434             : 
    2435           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/base-shapes"),
    2436             :         KIND_OTHER, rtStats.zTotals.shapeInfo.shapesGCHeapBase,
    2437             :         "Used base shape cells.");
    2438             : 
    2439           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/object-groups"),
    2440             :         KIND_OTHER, rtStats.zTotals.objectGroupsGCHeap,
    2441             :         "Used object group cells.");
    2442             : 
    2443           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/scopes"),
    2444             :         KIND_OTHER, rtStats.zTotals.scopesGCHeap,
    2445             :         "Used scope cells.");
    2446             : 
    2447           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/scripts"),
    2448             :         KIND_OTHER, rtStats.realmTotals.scriptsGCHeap,
    2449             :         "Used script cells.");
    2450             : 
    2451           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/lazy-scripts"),
    2452             :         KIND_OTHER, rtStats.zTotals.lazyScriptsGCHeap,
    2453             :         "Used lazy script cells.");
    2454             : 
    2455           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/jitcode"),
    2456             :         KIND_OTHER, rtStats.zTotals.jitCodesGCHeap,
    2457             :         "Used jitcode cells.");
    2458             : 
    2459           0 :     MREPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/gc-things/regexp-shareds"),
    2460             :         KIND_OTHER, rtStats.zTotals.regExpSharedsGCHeap,
    2461             :         "Used regexpshared cells.");
    2462             : 
    2463           0 :     MOZ_ASSERT(gcThingTotal == rtStats.gcHeapGCThings);
    2464             : 
    2465             :     // Report xpconnect.
    2466             : 
    2467           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/xpconnect/runtime"),
    2468             :         KIND_HEAP, xpcJSRuntimeSize,
    2469             :         "The XPConnect runtime.");
    2470             : 
    2471           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/xpconnect/wrappedjs"),
    2472             :         KIND_HEAP, wrappedJSSize,
    2473             :         "Wrappers used to implement XPIDL interfaces with JS.");
    2474             : 
    2475           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/xpconnect/scopes"),
    2476             :         KIND_HEAP, sizeInfo.mScopeAndMapSize,
    2477             :         "XPConnect scopes.");
    2478             : 
    2479           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/xpconnect/proto-iface-cache"),
    2480             :         KIND_HEAP, sizeInfo.mProtoAndIfaceCacheSize,
    2481             :         "Prototype and interface binding caches.");
    2482             : 
    2483           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/xpconnect/js-component-loader"),
    2484             :         KIND_HEAP, jsComponentLoaderSize,
    2485             :         "XPConnect's JS component loader.");
    2486             : 
    2487             :     // Report tracelogger (global).
    2488             : 
    2489           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/js-non-window/tracelogger"),
    2490             :         KIND_HEAP, gStats.tracelogger,
    2491             :         "The memory used for the tracelogger, including the graph and events.");
    2492             : 
    2493             :     // Report HelperThreadState.
    2494             : 
    2495           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/js-non-window/helper-thread/heap-other"),
    2496             :         KIND_HEAP, gStats.helperThread.stateData,
    2497             :         "Memory used by HelperThreadState.");
    2498             : 
    2499           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/js-non-window/helper-thread/parse-task"),
    2500             :         KIND_HEAP, gStats.helperThread.parseTask,
    2501             :         "The memory used by ParseTasks waiting in HelperThreadState.");
    2502             : 
    2503           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/js-non-window/helper-thread/ion-builder"),
    2504             :         KIND_HEAP, gStats.helperThread.ionBuilder,
    2505             :         "The memory used by IonBuilders waiting in HelperThreadState.");
    2506             : 
    2507           0 :     REPORT_BYTES(NS_LITERAL_CSTRING("explicit/js-non-window/helper-thread/wasm-compile"),
    2508             :         KIND_HEAP, gStats.helperThread.parseTask,
    2509             :         "The memory used by Wasm compilations waiting in HelperThreadState.");
    2510             : }
    2511             : 
    2512             : static nsresult
    2513           0 : JSSizeOfTab(JSObject* objArg, size_t* jsObjectsSize, size_t* jsStringsSize,
    2514             :             size_t* jsPrivateSize, size_t* jsOtherSize)
    2515             : {
    2516           0 :     JSContext* cx = XPCJSContext::Get()->Context();
    2517           0 :     JS::RootedObject obj(cx, objArg);
    2518             : 
    2519           0 :     TabSizes sizes;
    2520           0 :     OrphanReporter orphanReporter(XPCConvert::GetISupportsFromJSObject);
    2521           0 :     NS_ENSURE_TRUE(JS::AddSizeOfTab(cx, obj, moz_malloc_size_of,
    2522             :                                     &orphanReporter, &sizes),
    2523             :                    NS_ERROR_OUT_OF_MEMORY);
    2524             : 
    2525           0 :     *jsObjectsSize = sizes.objects;
    2526           0 :     *jsStringsSize = sizes.strings;
    2527           0 :     *jsPrivateSize = sizes.private_;
    2528           0 :     *jsOtherSize   = sizes.other;
    2529           0 :     return NS_OK;
    2530             : }
    2531             : 
    2532             : } // namespace xpc
    2533             : 
    2534             : static void
    2535          24 : AccumulateTelemetryCallback(int id, uint32_t sample, const char* key)
    2536             : {
    2537           0 :     switch (id) {
    2538             :       case JS_TELEMETRY_GC_REASON:
    2539           0 :         Telemetry::Accumulate(Telemetry::GC_REASON_2, sample);
    2540           0 :         break;
    2541             :       case JS_TELEMETRY_GC_IS_ZONE_GC:
    2542           0 :         Telemetry::Accumulate(Telemetry::GC_IS_COMPARTMENTAL, sample);
    2543           0 :         break;
    2544             :       case JS_TELEMETRY_GC_MS:
    2545           0 :         Telemetry::Accumulate(Telemetry::GC_MS, sample);
    2546           0 :         break;
    2547             :       case JS_TELEMETRY_GC_BUDGET_MS:
    2548           0 :         Telemetry::Accumulate(Telemetry::GC_BUDGET_MS, sample);
    2549           0 :         break;
    2550             :       case JS_TELEMETRY_GC_BUDGET_OVERRUN:
    2551           0 :         Telemetry::Accumulate(Telemetry::GC_BUDGET_OVERRUN, sample);
    2552           0 :         break;
    2553             :       case JS_TELEMETRY_GC_ANIMATION_MS:
    2554           0 :         Telemetry::Accumulate(Telemetry::GC_ANIMATION_MS, sample);
    2555           0 :         break;
    2556             :       case JS_TELEMETRY_GC_MAX_PAUSE_MS_2:
    2557           0 :         Telemetry::Accumulate(Telemetry::GC_MAX_PAUSE_MS_2, sample);
    2558           0 :         break;
    2559             :       case JS_TELEMETRY_GC_MARK_MS:
    2560           0 :         Telemetry::Accumulate(Telemetry::GC_MARK_MS, sample);
    2561           0 :         break;
    2562             :       case JS_TELEMETRY_GC_SWEEP_MS:
    2563           0 :         Telemetry::Accumulate(Telemetry::GC_SWEEP_MS, sample);
    2564           0 :         break;
    2565             :       case JS_TELEMETRY_GC_COMPACT_MS:
    2566           0 :         Telemetry::Accumulate(Telemetry::GC_COMPACT_MS, sample);
    2567           0 :         break;
    2568             :       case JS_TELEMETRY_GC_MARK_ROOTS_MS:
    2569           0 :         Telemetry::Accumulate(Telemetry::GC_MARK_ROOTS_MS, sample);
    2570           0 :         break;
    2571             :       case JS_TELEMETRY_GC_MARK_GRAY_MS:
    2572           0 :         Telemetry::Accumulate(Telemetry::GC_MARK_GRAY_MS, sample);
    2573           0 :         break;
    2574             :       case JS_TELEMETRY_GC_SLICE_MS:
    2575           0 :         Telemetry::Accumulate(Telemetry::GC_SLICE_MS, sample);
    2576           0 :         break;
    2577             :       case JS_TELEMETRY_GC_SLOW_PHASE:
    2578           0 :         Telemetry::Accumulate(Telemetry::GC_SLOW_PHASE, sample);
    2579           0 :         break;
    2580             :       case JS_TELEMETRY_GC_SLOW_TASK:
    2581           0 :         Telemetry::Accumulate(Telemetry::GC_SLOW_TASK, sample);
    2582           0 :         break;
    2583             :       case JS_TELEMETRY_GC_MMU_50:
    2584           0 :         Telemetry::Accumulate(Telemetry::GC_MMU_50, sample);
    2585           0 :         break;
    2586             :       case JS_TELEMETRY_GC_RESET:
    2587           0 :         Telemetry::Accumulate(Telemetry::GC_RESET, sample);
    2588           0 :         break;
    2589             :       case JS_TELEMETRY_GC_RESET_REASON:
    2590           0 :         Telemetry::Accumulate(Telemetry::GC_RESET_REASON, sample);
    2591           0 :         break;
    2592             :       case JS_TELEMETRY_GC_INCREMENTAL_DISABLED:
    2593           0 :         Telemetry::Accumulate(Telemetry::GC_INCREMENTAL_DISABLED, sample);
    2594           0 :         break;
    2595             :       case JS_TELEMETRY_GC_NON_INCREMENTAL:
    2596           0 :         Telemetry::Accumulate(Telemetry::GC_NON_INCREMENTAL, sample);
    2597           0 :         break;
    2598             :       case JS_TELEMETRY_GC_NON_INCREMENTAL_REASON:
    2599           0 :         Telemetry::Accumulate(Telemetry::GC_NON_INCREMENTAL_REASON, sample);
    2600           0 :         break;
    2601             :       case JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS:
    2602           0 :         Telemetry::Accumulate(Telemetry::GC_SCC_SWEEP_TOTAL_MS, sample);
    2603           0 :         break;
    2604             :       case JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS:
    2605           0 :         Telemetry::Accumulate(Telemetry::GC_SCC_SWEEP_MAX_PAUSE_MS, sample);
    2606           0 :         break;
    2607             :       case JS_TELEMETRY_GC_MINOR_REASON:
    2608           0 :         Telemetry::Accumulate(Telemetry::GC_MINOR_REASON, sample);
    2609           0 :         break;
    2610             :       case JS_TELEMETRY_GC_MINOR_REASON_LONG:
    2611           0 :         Telemetry::Accumulate(Telemetry::GC_MINOR_REASON_LONG, sample);
    2612           0 :         break;
    2613             :       case JS_TELEMETRY_GC_MINOR_US:
    2614           0 :         Telemetry::Accumulate(Telemetry::GC_MINOR_US, sample);
    2615           0 :         break;
    2616             :       case JS_TELEMETRY_GC_NURSERY_BYTES:
    2617           1 :         Telemetry::Accumulate(Telemetry::GC_NURSERY_BYTES, sample);
    2618           1 :         break;
    2619             :       case JS_TELEMETRY_GC_PRETENURE_COUNT:
    2620           1 :         Telemetry::Accumulate(Telemetry::GC_PRETENURE_COUNT, sample);
    2621           1 :         break;
    2622             :       case JS_TELEMETRY_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS:
    2623           0 :         Telemetry::Accumulate(Telemetry::JS_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS, sample);
    2624           0 :         break;
    2625             :       case JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS:
    2626           0 :         Telemetry::Accumulate(Telemetry::JS_WEB_PARSER_COMPILE_LAZY_AFTER_MS, sample);
    2627           0 :         break;
    2628             :       default:
    2629           0 :         MOZ_ASSERT_UNREACHABLE("Unexpected JS_TELEMETRY id");
    2630             :     }
    2631          24 : }
    2632             : 
    2633             : static void
    2634           0 : SetUseCounterCallback(JSObject* obj, JSUseCounter counter)
    2635             : {
    2636           0 :     switch (counter) {
    2637             :       case JSUseCounter::ASMJS:
    2638           0 :         SetDocumentAndPageUseCounter(obj, eUseCounter_custom_JS_asmjs);
    2639           0 :         break;
    2640             :       case JSUseCounter::WASM:
    2641           0 :         SetDocumentAndPageUseCounter(obj, eUseCounter_custom_JS_wasm);
    2642           0 :         break;
    2643             :       default:
    2644           0 :         MOZ_ASSERT_UNREACHABLE("Unexpected JSUseCounter id");
    2645             :     }
    2646           0 : }
    2647             : 
    2648             : static void
    2649           0 : GetRealmNameCallback(JSContext* cx, Handle<Realm*> realm,
    2650             :                      char* buf, size_t bufsize)
    2651             : {
    2652           0 :     nsCString name;
    2653             :     // This is called via the JSAPI and isn't involved in memory reporting, so
    2654             :     // we don't need to anonymize realm names.
    2655           0 :     int anonymizeID = 0;
    2656           0 :     GetRealmName(realm, name, &anonymizeID, /* replaceSlashes = */ false);
    2657           0 :     if (name.Length() >= bufsize)
    2658           0 :         name.Truncate(bufsize - 1);
    2659           0 :     memcpy(buf, name.get(), name.Length() + 1);
    2660           0 : }
    2661             : 
    2662             : static void
    2663           0 : DestroyRealm(JSFreeOp* fop, JS::Realm* realm)
    2664             : {
    2665             :     // Get the current compartment private into an AutoPtr (which will do the
    2666             :     // cleanup for us), and null out the private field.
    2667          15 :     mozilla::UniquePtr<RealmPrivate> priv(RealmPrivate::Get(realm));
    2668           0 :     JS::SetRealmPrivate(realm, nullptr);
    2669           0 : }
    2670             : 
    2671             : static bool
    2672           5 : PreserveWrapper(JSContext* cx, JSObject* obj)
    2673             : {
    2674           5 :     MOZ_ASSERT(cx);
    2675           0 :     MOZ_ASSERT(obj);
    2676           0 :     MOZ_ASSERT(IS_WN_REFLECTOR(obj) || mozilla::dom::IsDOMObject(obj));
    2677             : 
    2678           5 :     return mozilla::dom::IsDOMObject(obj) && mozilla::dom::TryPreserveWrapper(obj);
    2679             : }
    2680             : 
    2681             : static nsresult
    2682           2 : ReadSourceFromFilename(JSContext* cx, const char* filename, char16_t** src, size_t* len)
    2683             : {
    2684             :     nsresult rv;
    2685             : 
    2686             :     // mozJSSubScriptLoader prefixes the filenames of the scripts it loads with
    2687             :     // the filename of its caller. Axe that if present.
    2688             :     const char* arrow;
    2689           4 :     while ((arrow = strstr(filename, " -> ")))
    2690           0 :         filename = arrow + strlen(" -> ");
    2691             : 
    2692             :     // Get the URI.
    2693           4 :     nsCOMPtr<nsIURI> uri;
    2694           0 :     rv = NS_NewURI(getter_AddRefs(uri), filename);
    2695           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2696             : 
    2697           4 :     nsCOMPtr<nsIChannel> scriptChannel;
    2698           0 :     rv = NS_NewChannel(getter_AddRefs(scriptChannel),
    2699             :                        uri,
    2700             :                        nsContentUtils::GetSystemPrincipal(),
    2701             :                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
    2702           2 :                        nsIContentPolicy::TYPE_OTHER);
    2703           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2704             : 
    2705             :     // Only allow local reading.
    2706           4 :     nsCOMPtr<nsIURI> actualUri;
    2707           0 :     rv = scriptChannel->GetURI(getter_AddRefs(actualUri));
    2708           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2709           0 :     nsCString scheme;
    2710           0 :     rv = actualUri->GetScheme(scheme);
    2711           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2712           0 :     if (!scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar"))
    2713             :         return NS_OK;
    2714             : 
    2715             :     // Explicitly set the content type so that we don't load the
    2716             :     // exthandler to guess it.
    2717           6 :     scriptChannel->SetContentType(NS_LITERAL_CSTRING("text/plain"));
    2718             : 
    2719           4 :     nsCOMPtr<nsIInputStream> scriptStream;
    2720           0 :     rv = scriptChannel->Open2(getter_AddRefs(scriptStream));
    2721           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2722             : 
    2723             :     uint64_t rawLen;
    2724           2 :     rv = scriptStream->Available(&rawLen);
    2725           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2726           0 :     if (!rawLen)
    2727             :         return NS_ERROR_FAILURE;
    2728             : 
    2729             :     // Technically, this should be SIZE_MAX, but we don't run on machines
    2730             :     // where that would be less than UINT32_MAX, and the latter is already
    2731             :     // well beyond a reasonable limit.
    2732           2 :     if (rawLen > UINT32_MAX)
    2733             :         return NS_ERROR_FILE_TOO_BIG;
    2734             : 
    2735             :     // Allocate an internal buf the size of the file.
    2736           2 :     auto buf = MakeUniqueFallible<unsigned char[]>(rawLen);
    2737           0 :     if (!buf)
    2738             :         return NS_ERROR_OUT_OF_MEMORY;
    2739             : 
    2740           2 :     unsigned char* ptr = buf.get();
    2741           0 :     unsigned char* end = ptr + rawLen;
    2742           0 :     while (ptr < end) {
    2743             :         uint32_t bytesRead;
    2744           2 :         rv = scriptStream->Read(reinterpret_cast<char*>(ptr), end - ptr, &bytesRead);
    2745           0 :         if (NS_FAILED(rv))
    2746           0 :             return rv;
    2747           1 :         MOZ_ASSERT(bytesRead > 0, "stream promised more bytes before EOF");
    2748           0 :         ptr += bytesRead;
    2749             :     }
    2750             : 
    2751           6 :     rv = ScriptLoader::ConvertToUTF16(scriptChannel, buf.get(), rawLen,
    2752           0 :                                       EmptyString(), nullptr, *src, *len);
    2753           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2754             : 
    2755           2 :     if (!*src)
    2756             :         return NS_ERROR_FAILURE;
    2757             : 
    2758             :     // Historically this method used JS_malloc() which updates the GC memory
    2759             :     // accounting.  Since ConvertToUTF16() now uses js_malloc() instead we
    2760             :     // update the accounting manually after the fact.
    2761           2 :     JS_updateMallocCounter(cx, *len);
    2762             : 
    2763           2 :     return NS_OK;
    2764             : }
    2765             : 
    2766             : // The JS engine calls this object's 'load' member function when it needs
    2767             : // the source for a chrome JS function. See the comment in the XPCJSRuntime
    2768             : // constructor.
    2769           1 : class XPCJSSourceHook: public js::SourceHook {
    2770           0 :     bool load(JSContext* cx, const char* filename, char16_t** src, size_t* length) override {
    2771           0 :         *src = nullptr;
    2772           0 :         *length = 0;
    2773             : 
    2774           2 :         if (!nsContentUtils::IsSystemCaller(cx))
    2775             :             return true;
    2776             : 
    2777           2 :         if (!filename)
    2778             :             return true;
    2779             : 
    2780           2 :         nsresult rv = ReadSourceFromFilename(cx, filename, src, length);
    2781           0 :         if (NS_FAILED(rv)) {
    2782           0 :             xpc::Throw(cx, rv);
    2783           0 :             return false;
    2784             :         }
    2785             : 
    2786             :         return true;
    2787             :     }
    2788             : };
    2789             : 
    2790             : static const JSWrapObjectCallbacks WrapObjectCallbacks = {
    2791             :     xpc::WrapperFactory::Rewrap,
    2792             :     xpc::WrapperFactory::PrepareForWrapping
    2793             : };
    2794             : 
    2795           1 : XPCJSRuntime::XPCJSRuntime(JSContext* aCx)
    2796             :  : CycleCollectedJSRuntime(aCx),
    2797           1 :    mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH)),
    2798           0 :    mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_LENGTH)),
    2799           0 :    mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_LENGTH)),
    2800           0 :    mClassInfo2NativeSetMap(ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_LENGTH)),
    2801           0 :    mNativeSetMap(NativeSetMap::newMap(XPC_NATIVE_SET_MAP_LENGTH)),
    2802           0 :    mDyingWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_LENGTH)),
    2803             :    mGCIsRunning(false),
    2804             :    mNativesToReleaseArray(),
    2805             :    mDoingFinalization(false),
    2806             :    mVariantRoots(nullptr),
    2807             :    mWrappedJSRoots(nullptr),
    2808          13 :    mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite())
    2809             : {
    2810           1 :     MOZ_COUNT_CTOR_INHERITED(XPCJSRuntime, CycleCollectedJSRuntime);
    2811           0 : }
    2812             : 
    2813             : /* static */
    2814             : XPCJSRuntime*
    2815       11753 : XPCJSRuntime::Get()
    2816             : {
    2817       18649 :     return nsXPConnect::GetRuntimeInstance();
    2818             : }
    2819             : 
    2820             : void
    2821           1 : XPCJSRuntime::Initialize(JSContext* cx)
    2822             : {
    2823           1 :     mUnprivilegedJunkScope.init(cx, nullptr);
    2824           0 :     mPrivilegedJunkScope.init(cx, nullptr);
    2825           0 :     mCompilationScope.init(cx, nullptr);
    2826             : 
    2827             :     // these jsids filled in later when we have a JSContext to work with.
    2828           1 :     mStrIDs[0] = JSID_VOID;
    2829             : 
    2830             :     // Unconstrain the runtime's threshold on nominal heap size, to avoid
    2831             :     // triggering GC too often if operating continuously near an arbitrary
    2832             :     // finite threshold (0xffffffff is infinity for uint32_t parameters).
    2833             :     // This leaves the maximum-JS_malloc-bytes threshold still in effect
    2834             :     // to cause period, and we hope hygienic, last-ditch GCs from within
    2835             :     // the GC's allocator.
    2836           1 :     JS_SetGCParameter(cx, JSGC_MAX_BYTES, 0xffffffff);
    2837             : 
    2838           1 :     JS_SetDestroyCompartmentCallback(cx, CompartmentDestroyedCallback);
    2839           0 :     JS_SetSizeOfIncludingThisCompartmentCallback(cx, CompartmentSizeOfIncludingThisCallback);
    2840           0 :     JS::SetDestroyRealmCallback(cx, DestroyRealm);
    2841           0 :     JS::SetRealmNameCallback(cx, GetRealmNameCallback);
    2842           0 :     mPrevGCSliceCallback = JS::SetGCSliceCallback(cx, GCSliceCallback);
    2843           0 :     mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx,
    2844             :             DoCycleCollectionCallback);
    2845           0 :     JS_AddFinalizeCallback(cx, FinalizeCallback, nullptr);
    2846           1 :     JS_AddWeakPointerZonesCallback(cx, WeakPointerZonesCallback, this);
    2847           0 :     JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this);
    2848           0 :     JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks);
    2849           0 :     js::SetPreserveWrapperCallback(cx, PreserveWrapper);
    2850           0 :     JS_InitReadPrincipalsCallback(cx, nsJSPrincipals::ReadPrincipals);
    2851           0 :     JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback);
    2852           0 :     JS_SetSetUseCounterCallback(cx, SetUseCounterCallback);
    2853           0 :     js::SetWindowProxyClass(cx, &OuterWindowProxyClass);
    2854           0 :     js::SetXrayJitInfo(&gXrayJitInfo);
    2855           0 :     JS::SetProcessLargeAllocationFailureCallback(OnLargeAllocationFailureCallback);
    2856             : 
    2857             :     // The JS engine needs to keep the source code around in order to implement
    2858             :     // Function.prototype.toSource(). It'd be nice to not have to do this for
    2859             :     // chrome code and simply stub out requests for source on it. Life is not so
    2860             :     // easy, unfortunately. Nobody relies on chrome toSource() working in core
    2861             :     // browser code, but chrome tests use it. The worst offenders are addons,
    2862             :     // which like to monkeypatch chrome functions by calling toSource() on them
    2863             :     // and using regular expressions to modify them. We avoid keeping most browser
    2864             :     // JS source code in memory by setting LAZY_SOURCE on JS::CompileOptions when
    2865             :     // compiling some chrome code. This causes the JS engine not save the source
    2866             :     // code in memory. When the JS engine is asked to provide the source for a
    2867             :     // function compiled with LAZY_SOURCE, it calls SourceHook to load it.
    2868             :     ///
    2869             :     // Note we do have to retain the source code in memory for scripts compiled in
    2870             :     // isRunOnce mode and compiled function bodies (from
    2871             :     // JS::CompileFunction). In practice, this means content scripts and event
    2872             :     // handlers.
    2873           4 :     mozilla::UniquePtr<XPCJSSourceHook> hook(new XPCJSSourceHook);
    2874           2 :     js::SetSourceHook(cx, std::move(hook));
    2875             : 
    2876             :     // Register memory reporters and distinguished amount functions.
    2877           1 :     RegisterStrongMemoryReporter(new JSMainRuntimeRealmsReporter());
    2878           1 :     RegisterStrongMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
    2879           0 :     RegisterJSMainRuntimeGCHeapDistinguishedAmount(JSMainRuntimeGCHeapDistinguishedAmount);
    2880           0 :     RegisterJSMainRuntimeTemporaryPeakDistinguishedAmount(JSMainRuntimeTemporaryPeakDistinguishedAmount);
    2881           0 :     RegisterJSMainRuntimeRealmsSystemDistinguishedAmount(JSMainRuntimeRealmsSystemDistinguishedAmount);
    2882           0 :     RegisterJSMainRuntimeRealmsUserDistinguishedAmount(JSMainRuntimeRealmsUserDistinguishedAmount);
    2883           0 :     mozilla::RegisterJSSizeOfTab(JSSizeOfTab);
    2884             : 
    2885           0 :     xpc_LocalizeRuntime(JS_GetRuntime(cx));
    2886           1 : }
    2887             : 
    2888             : bool
    2889           1 : XPCJSRuntime::InitializeStrings(JSContext* cx)
    2890             : {
    2891           0 :     JSAutoRequest ar(cx);
    2892             : 
    2893             :     // if it is our first context then we need to generate our string ids
    2894           1 :     if (JSID_IS_VOID(mStrIDs[0])) {
    2895           2 :         RootedString str(cx);
    2896           0 :         for (unsigned i = 0; i < XPCJSContext::IDX_TOTAL_COUNT; i++) {
    2897           0 :             str = JS_AtomizeAndPinString(cx, mStrings[i]);
    2898           0 :             if (!str) {
    2899           0 :                 mStrIDs[0] = JSID_VOID;
    2900           0 :                 return false;
    2901             :             }
    2902           1 :             mStrIDs[i] = INTERNED_STRING_TO_JSID(cx, str);
    2903          35 :             mStrJSVals[i].setString(str);
    2904             :         }
    2905             : 
    2906           1 :         if (!mozilla::dom::DefineStaticJSVals(cx)) {
    2907             :             return false;
    2908             :         }
    2909             :     }
    2910             : 
    2911             :     return true;
    2912             : }
    2913             : 
    2914             : bool
    2915           0 : XPCJSRuntime::DescribeCustomObjects(JSObject* obj, const js::Class* clasp,
    2916             :                                     char (&name)[72]) const
    2917             : {
    2918             : 
    2919           0 :     if (clasp != &XPC_WN_Proto_JSClass) {
    2920             :         return false;
    2921             :     }
    2922             : 
    2923             :     XPCWrappedNativeProto* p =
    2924           0 :         static_cast<XPCWrappedNativeProto*>(xpc_GetJSPrivate(obj));
    2925           0 :     nsCOMPtr<nsIXPCScriptable> scr = p->GetScriptable();
    2926           0 :     if (!scr) {
    2927             :         return false;
    2928             :     }
    2929             : 
    2930             :     SprintfLiteral(name, "JS Object (%s - %s)",
    2931           0 :                    clasp->name, scr->GetJSClass()->name);
    2932           0 :     return true;
    2933             : }
    2934             : 
    2935             : bool
    2936           0 : XPCJSRuntime::NoteCustomGCThingXPCOMChildren(const js::Class* clasp, JSObject* obj,
    2937             :                                              nsCycleCollectionTraversalCallback& cb) const
    2938             : {
    2939           0 :     if (clasp != &XPC_WN_Tearoff_JSClass) {
    2940             :         return false;
    2941             :     }
    2942             : 
    2943             :     // A tearoff holds a strong reference to its native object
    2944             :     // (see XPCWrappedNative::FlatJSObjectFinalized). Its XPCWrappedNative
    2945             :     // will be held alive through the parent of the JSObject of the tearoff.
    2946             :     XPCWrappedNativeTearOff* to =
    2947           0 :         static_cast<XPCWrappedNativeTearOff*>(xpc_GetJSPrivate(obj));
    2948           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)->mNative");
    2949           0 :     cb.NoteXPCOMChild(to->GetNative());
    2950           0 :     return true;
    2951             : }
    2952             : 
    2953             : /***************************************************************************/
    2954             : 
    2955             : void
    2956           0 : XPCJSRuntime::DebugDump(int16_t depth)
    2957             : {
    2958             : #ifdef DEBUG
    2959           0 :     depth--;
    2960           0 :     XPC_LOG_ALWAYS(("XPCJSRuntime @ %p", this));
    2961           0 :         XPC_LOG_INDENT();
    2962             : 
    2963           0 :         XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %p with %d wrapperclasses(s)",
    2964             :                         mWrappedJSClassMap, mWrappedJSClassMap->Count()));
    2965             :         // iterate wrappersclasses...
    2966           0 :         if (depth && mWrappedJSClassMap->Count()) {
    2967           0 :             XPC_LOG_INDENT();
    2968           0 :             for (auto i = mWrappedJSClassMap->Iter(); !i.Done(); i.Next()) {
    2969           0 :                 auto entry = static_cast<IID2WrappedJSClassMap::Entry*>(i.Get());
    2970           0 :                 entry->value->DebugDump(depth);
    2971             :             }
    2972           0 :             XPC_LOG_OUTDENT();
    2973             :         }
    2974             : 
    2975             :         // iterate wrappers...
    2976           0 :         XPC_LOG_ALWAYS(("mWrappedJSMap @ %p with %d wrappers(s)",
    2977             :                         mWrappedJSMap, mWrappedJSMap->Count()));
    2978           0 :         if (depth && mWrappedJSMap->Count()) {
    2979           0 :             XPC_LOG_INDENT();
    2980           0 :             mWrappedJSMap->Dump(depth);
    2981           0 :             XPC_LOG_OUTDENT();
    2982             :         }
    2983             : 
    2984           0 :         XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %p with %d interface(s)",
    2985             :                         mIID2NativeInterfaceMap,
    2986             :                         mIID2NativeInterfaceMap->Count()));
    2987             : 
    2988           0 :         XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %p with %d sets(s)",
    2989             :                         mClassInfo2NativeSetMap,
    2990             :                         mClassInfo2NativeSetMap->Count()));
    2991             : 
    2992           0 :         XPC_LOG_ALWAYS(("mNativeSetMap @ %p with %d sets(s)",
    2993             :                         mNativeSetMap, mNativeSetMap->Count()));
    2994             : 
    2995             :         // iterate sets...
    2996           0 :         if (depth && mNativeSetMap->Count()) {
    2997           0 :             XPC_LOG_INDENT();
    2998           0 :             for (auto i = mNativeSetMap->Iter(); !i.Done(); i.Next()) {
    2999           0 :                 auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
    3000           0 :                 entry->key_value->DebugDump(depth);
    3001             :             }
    3002           0 :             XPC_LOG_OUTDENT();
    3003             :         }
    3004             : 
    3005           0 :         XPC_LOG_OUTDENT();
    3006             : #endif
    3007           0 : }
    3008             : 
    3009             : /***************************************************************************/
    3010             : 
    3011             : void
    3012         719 : XPCRootSetElem::AddToRootSet(XPCRootSetElem** listHead)
    3013             : {
    3014           0 :     MOZ_ASSERT(!mSelfp, "Must be not linked");
    3015             : 
    3016           0 :     mSelfp = listHead;
    3017         719 :     mNext = *listHead;
    3018           0 :     if (mNext) {
    3019           0 :         MOZ_ASSERT(mNext->mSelfp == listHead, "Must be list start");
    3020           0 :         mNext->mSelfp = &mNext;
    3021             :     }
    3022           0 :     *listHead = this;
    3023         719 : }
    3024             : 
    3025             : void
    3026         244 : XPCRootSetElem::RemoveFromRootSet()
    3027             : {
    3028           0 :     JS::NotifyGCRootsRemoved(XPCJSContext::Get()->Context());
    3029             : 
    3030           0 :     MOZ_ASSERT(mSelfp, "Must be linked");
    3031             : 
    3032           0 :     MOZ_ASSERT(*mSelfp == this, "Link invariant");
    3033         244 :     *mSelfp = mNext;
    3034           0 :     if (mNext)
    3035           0 :         mNext->mSelfp = mSelfp;
    3036             : #ifdef DEBUG
    3037           0 :     mSelfp = nullptr;
    3038         244 :     mNext = nullptr;
    3039             : #endif
    3040           0 : }
    3041             : 
    3042             : void
    3043           0 : XPCJSRuntime::AddGCCallback(xpcGCCallback cb)
    3044             : {
    3045           0 :     MOZ_ASSERT(cb, "null callback");
    3046           0 :     extraGCCallbacks.AppendElement(cb);
    3047           0 : }
    3048             : 
    3049             : void
    3050           0 : XPCJSRuntime::RemoveGCCallback(xpcGCCallback cb)
    3051             : {
    3052           0 :     MOZ_ASSERT(cb, "null callback");
    3053           0 :     bool found = extraGCCallbacks.RemoveElement(cb);
    3054           0 :     if (!found) {
    3055           0 :         NS_ERROR("Removing a callback which was never added.");
    3056             :     }
    3057           0 : }
    3058             : 
    3059             : void
    3060           1 : XPCJSRuntime::InitSingletonScopes()
    3061             : {
    3062             :     // This all happens very early, so we don't bother with cx pushing.
    3063           1 :     JSContext* cx = XPCJSContext::Get()->Context();
    3064           3 :     JSAutoRequest ar(cx);
    3065           0 :     RootedValue v(cx);
    3066             :     nsresult rv;
    3067             : 
    3068             :     // Create the Unprivileged Junk Scope.
    3069           2 :     SandboxOptions unprivilegedJunkScopeOptions;
    3070           1 :     unprivilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Junk Compartment");
    3071           0 :     unprivilegedJunkScopeOptions.invisibleToDebugger = true;
    3072           0 :     rv = CreateSandboxObject(cx, &v, nullptr, unprivilegedJunkScopeOptions);
    3073           0 :     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
    3074           0 :     mUnprivilegedJunkScope = js::UncheckedUnwrap(&v.toObject());
    3075             : 
    3076             :     // Create the Privileged Junk Scope.
    3077           2 :     SandboxOptions privilegedJunkScopeOptions;
    3078           1 :     privilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Privileged Junk Compartment");
    3079           0 :     privilegedJunkScopeOptions.invisibleToDebugger = true;
    3080           0 :     privilegedJunkScopeOptions.wantComponents = false;
    3081           0 :     rv = CreateSandboxObject(cx, &v, nsXPConnect::SystemPrincipal(), privilegedJunkScopeOptions);
    3082           0 :     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
    3083           0 :     mPrivilegedJunkScope = js::UncheckedUnwrap(&v.toObject());
    3084             : 
    3085             :     // Create the Compilation Scope.
    3086           2 :     SandboxOptions compilationScopeOptions;
    3087           1 :     compilationScopeOptions.sandboxName.AssignLiteral("XPConnect Compilation Compartment");
    3088           0 :     compilationScopeOptions.invisibleToDebugger = true;
    3089           0 :     compilationScopeOptions.discardSource = ShouldDiscardSystemSource();
    3090           0 :     rv = CreateSandboxObject(cx, &v, /* principal = */ nullptr, compilationScopeOptions);
    3091           0 :     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
    3092           0 :     mCompilationScope = js::UncheckedUnwrap(&v.toObject());
    3093           0 : }
    3094             : 
    3095             : void
    3096           0 : XPCJSRuntime::DeleteSingletonScopes()
    3097             : {
    3098             :     // We're pretty late in shutdown, so we call ReleaseWrapper on the scopes. This way
    3099             :     // the GC can collect them immediately, and we don't rely on the CC to clean up.
    3100           0 :     RefPtr<SandboxPrivate> sandbox = SandboxPrivate::GetPrivate(mUnprivilegedJunkScope);
    3101           0 :     sandbox->ReleaseWrapper(sandbox);
    3102           0 :     mUnprivilegedJunkScope = nullptr;
    3103           0 :     sandbox = SandboxPrivate::GetPrivate(mPrivilegedJunkScope);
    3104           0 :     sandbox->ReleaseWrapper(sandbox);
    3105           0 :     mPrivilegedJunkScope = nullptr;
    3106           0 :     sandbox = SandboxPrivate::GetPrivate(mCompilationScope);
    3107           0 :     sandbox->ReleaseWrapper(sandbox);
    3108           0 :     mCompilationScope = nullptr;
    3109           0 : }

Generated by: LCOV version 1.13-14-ga5dd952