js/xpconnect/src/XPCWrappedNativeScope.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 /* Class used to manage the wrapped native objects within a JS scope. */
     9 #include "xpcprivate.h"
    10 #include "XPCWrapper.h"
    11 #include "nsContentUtils.h"
    12 #include "nsCycleCollectionNoteRootCallback.h"
    13 #include "nsPrincipal.h"
    14 #include "mozilla/MemoryReporting.h"
    15 #include "mozilla/Preferences.h"
    17 #include "mozilla/dom/BindingUtils.h"
    19 using namespace mozilla;
    20 using namespace xpc;
    21 using namespace JS;
    23 /***************************************************************************/
    25 XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr;
    26 XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
    28 // static
    29 XPCWrappedNativeScope*
    30 XPCWrappedNativeScope::GetNewOrUsed(JSContext *cx, JS::HandleObject aGlobal)
    31 {
    32     XPCWrappedNativeScope* scope = GetObjectScope(aGlobal);
    33     if (!scope) {
    34         scope = new XPCWrappedNativeScope(cx, aGlobal);
    35     }
    36     return scope;
    37 }
    39 static bool
    40 RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal)
    41 {
    42   // Check for random JSD scopes that don't have a principal.
    43   if (!aPrincipal)
    44       return false;
    46   // The SafeJSContext is lazily created, and tends to be created at really
    47   // weird times, at least for xpcshell (often very early in startup or late
    48   // in shutdown). Its scope isn't system principal, so if we proceeded we'd
    49   // end up calling into AllowXULXBLForPrincipal, which depends on all kinds
    50   // of persistent storage and permission machinery that may or not be running.
    51   // We know the answer to the question here, so just short-circuit.
    52   if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass)
    53       return false;
    55   // AllowXULXBLForPrincipal will return true for system principal, but we
    56   // don't want that here.
    57   MOZ_ASSERT(nsContentUtils::IsInitialized());
    58   if (nsContentUtils::IsSystemPrincipal(aPrincipal))
    59       return false;
    61   // If this domain isn't whitelisted, we're done.
    62   if (!nsContentUtils::AllowXULXBLForPrincipal(aPrincipal))
    63       return false;
    65   // Check the pref to determine how we should behave.
    66   return !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
    67 }
    69 XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext *cx,
    70                                              JS::HandleObject aGlobal)
    71       : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)),
    72         mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)),
    73         mComponents(nullptr),
    74         mNext(nullptr),
    75         mGlobalJSObject(aGlobal),
    76         mIsXBLScope(false)
    77 {
    78     // add ourselves to the scopes list
    79     {
    80         MOZ_ASSERT(aGlobal);
    81         MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
    82                                                          JSCLASS_HAS_PRIVATE)); 
    83 #ifdef DEBUG
    84         for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
    85             MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object");
    86 #endif
    88         mNext = gScopes;
    89         gScopes = this;
    91         // Grab the XPCContext associated with our context.
    92         mContext = XPCContext::GetXPCContext(cx);
    93         mContext->AddScope(this);
    94     }
    96     MOZ_COUNT_CTOR(XPCWrappedNativeScope);
    98     // Attach ourselves to the compartment private.
    99     CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal);
   100     priv->scope = this;
   102     // Determine whether we would allow an XBL scope in this situation.
   103     // In addition to being pref-controlled, we also disable XBL scopes for
   104     // remote XUL domains, _except_ if we have an additional pref override set.
   105     nsIPrincipal *principal = GetPrincipal();
   106     mAllowXBLScope = !RemoteXULForbidsXBLScope(principal, aGlobal);
   108     // Determine whether to use an XBL scope.
   109     mUseXBLScope = mAllowXBLScope;
   110     if (mUseXBLScope) {
   111       const js::Class *clasp = js::GetObjectClass(mGlobalJSObject);
   112       mUseXBLScope = !strcmp(clasp->name, "Window") ||
   113                      !strcmp(clasp->name, "ChromeWindow") ||
   114                      !strcmp(clasp->name, "ModalContentWindow");
   115     }
   116     if (mUseXBLScope) {
   117       mUseXBLScope = principal && !nsContentUtils::IsSystemPrincipal(principal);
   118     }
   119 }
   121 // static
   122 bool
   123 XPCWrappedNativeScope::IsDyingScope(XPCWrappedNativeScope *scope)
   124 {
   125     for (XPCWrappedNativeScope *cur = gDyingScopes; cur; cur = cur->mNext) {
   126         if (scope == cur)
   127             return true;
   128     }
   129     return false;
   130 }
   132 bool
   133 XPCWrappedNativeScope::GetComponentsJSObject(JS::MutableHandleObject obj)
   134 {
   135     AutoJSContext cx;
   136     if (!mComponents) {
   137         nsIPrincipal *p = GetPrincipal();
   138         bool system = XPCWrapper::GetSecurityManager()->IsSystemPrincipal(p);
   139         mComponents = system ? new nsXPCComponents(this)
   140                              : new nsXPCComponentsBase(this);
   141     }
   143     RootedValue val(cx);
   144     xpcObjectHelper helper(mComponents);
   145     bool ok = XPCConvert::NativeInterface2JSObject(&val, nullptr, helper,
   146                                                    nullptr, nullptr, false,
   147                                                    nullptr);
   148     if (NS_WARN_IF(!ok))
   149         return false;
   151     if (NS_WARN_IF(!val.isObject()))
   152         return false;
   154     // The call to wrap() here is necessary even though the object is same-
   155     // compartment, because it applies our security wrapper.
   156     obj.set(&val.toObject());
   157     if (NS_WARN_IF(!JS_WrapObject(cx, obj)))
   158         return false;
   159     return true;
   160 }
   162 void
   163 XPCWrappedNativeScope::ForcePrivilegedComponents()
   164 {
   165     // This may only be called on unprivileged scopes during automation where
   166     // we allow insecure things.
   167     MOZ_RELEASE_ASSERT(Preferences::GetBool("security.turn_off_all_security_so_"
   168                                             "that_viruses_can_take_over_this_"
   169                                             "computer"));
   170     nsCOMPtr<nsIXPCComponents> c = do_QueryInterface(mComponents);
   171     if (!c)
   172         mComponents = new nsXPCComponents(this);
   173 }
   175 bool
   176 XPCWrappedNativeScope::AttachComponentsObject(JSContext* aCx)
   177 {
   178     RootedObject components(aCx);
   179     if (!GetComponentsJSObject(&components))
   180         return false;
   182     RootedObject global(aCx, GetGlobalJSObject());
   183     MOZ_ASSERT(js::IsObjectInContextCompartment(global, aCx));
   185     RootedId id(aCx, XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS));
   186     return JS_DefinePropertyById(aCx, global, id, ObjectValue(*components),
   187                                  nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY);
   188 }
   190 JSObject*
   191 XPCWrappedNativeScope::EnsureXBLScope(JSContext *cx)
   192 {
   193     JS::RootedObject global(cx, GetGlobalJSObject());
   194     MOZ_ASSERT(js::IsObjectInContextCompartment(global, cx));
   195     MOZ_ASSERT(!mIsXBLScope);
   196     MOZ_ASSERT(strcmp(js::GetObjectClass(global)->name,
   197                       "nsXBLPrototypeScript compilation scope"));
   199     // If we already have a special XBL scope object, we know what to use.
   200     if (mXBLScope)
   201         return mXBLScope;
   203     // If this scope doesn't need an XBL scope, just return the global.
   204     if (!mUseXBLScope)
   205         return global;
   207     // Set up the sandbox options. Note that we use the DOM global as the
   208     // sandboxPrototype so that the XBL scope can access all the DOM objects
   209     // it's accustomed to accessing.
   210     //
   211     // NB: One would think that wantXrays wouldn't make a difference here.
   212     // However, wantXrays lives a secret double life, and one of its other
   213     // hobbies is to waive Xray on the returned sandbox when set to false.
   214     // So make sure to keep this set to true, here.
   215     SandboxOptions options;
   216     options.wantXrays = true;
   217     options.wantComponents = true;
   218     options.proto = global;
   219     options.sameZoneAs = global;
   221     // Use an nsExpandedPrincipal to create asymmetric security.
   222     nsIPrincipal *principal = GetPrincipal();
   223     nsCOMPtr<nsIExpandedPrincipal> ep;
   224     MOZ_ASSERT(!(ep = do_QueryInterface(principal)));
   225     nsTArray< nsCOMPtr<nsIPrincipal> > principalAsArray(1);
   226     principalAsArray.AppendElement(principal);
   227     ep = new nsExpandedPrincipal(principalAsArray);
   229     // Create the sandbox.
   230     RootedValue v(cx);
   231     nsresult rv = CreateSandboxObject(cx, &v, ep, options);
   232     NS_ENSURE_SUCCESS(rv, nullptr);
   233     mXBLScope = &v.toObject();
   235     // Tag it.
   236     EnsureCompartmentPrivate(js::UncheckedUnwrap(mXBLScope))->scope->mIsXBLScope = true;
   238     // Good to go!
   239     return mXBLScope;
   240 }
   242 bool
   243 XPCWrappedNativeScope::AllowXBLScope()
   244 {
   245     // We only disallow XBL scopes in remote XUL situations.
   246     MOZ_ASSERT_IF(!mAllowXBLScope,
   247                   nsContentUtils::AllowXULXBLForPrincipal(GetPrincipal()));
   248     return mAllowXBLScope;
   249 }
   251 namespace xpc {
   252 JSObject *GetXBLScope(JSContext *cx, JSObject *contentScopeArg)
   253 {
   254     JS::RootedObject contentScope(cx, contentScopeArg);
   255     JSAutoCompartment ac(cx, contentScope);
   256     JSObject *scope = EnsureCompartmentPrivate(contentScope)->scope->EnsureXBLScope(cx);
   257     NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
   258     scope = js::UncheckedUnwrap(scope);
   259     JS::ExposeObjectToActiveJS(scope);
   260     return scope;
   261 }
   263 bool AllowXBLScope(JSCompartment *c)
   264 {
   265   XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
   266   return scope && scope->AllowXBLScope();
   267 }
   269 bool UseXBLScope(JSCompartment *c)
   270 {
   271   XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
   272   return scope && scope->UseXBLScope();
   273 }
   275 } /* namespace xpc */
   277 XPCWrappedNativeScope::~XPCWrappedNativeScope()
   278 {
   279     MOZ_COUNT_DTOR(XPCWrappedNativeScope);
   281     // We can do additional cleanup assertions here...
   283     if (mWrappedNativeMap) {
   284         MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
   285         delete mWrappedNativeMap;
   286     }
   288     if (mWrappedNativeProtoMap) {
   289         MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
   290         delete mWrappedNativeProtoMap;
   291     }
   293     if (mContext)
   294         mContext->RemoveScope(this);
   296     // This should not be necessary, since the Components object should die
   297     // with the scope but just in case.
   298     if (mComponents)
   299         mComponents->mScope = nullptr;
   301     // XXX we should assert that we are dead or that xpconnect has shutdown
   302     // XXX might not want to do this at xpconnect shutdown time???
   303     mComponents = nullptr;
   305     if (mXrayExpandos.initialized())
   306         mXrayExpandos.destroy();
   308     JSRuntime *rt = XPCJSRuntime::Get()->Runtime();
   309     mXBLScope.finalize(rt);
   310     mGlobalJSObject.finalize(rt);
   311 }
   313 static PLDHashOperator
   314 WrappedNativeJSGCThingTracer(PLDHashTable *table, PLDHashEntryHdr *hdr,
   315                              uint32_t number, void *arg)
   316 {
   317     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
   318     if (wrapper->HasExternalReference() && !wrapper->IsWrapperExpired())
   319         wrapper->TraceSelf((JSTracer *)arg);
   321     return PL_DHASH_NEXT;
   322 }
   324 // static
   325 void
   326 XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt)
   327 {
   328     // Do JS_CallTracer for all wrapped natives with external references, as
   329     // well as any DOM expando objects.
   330     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
   331         cur->mWrappedNativeMap->Enumerate(WrappedNativeJSGCThingTracer, trc);
   332         if (cur->mDOMExpandoSet) {
   333             for (DOMExpandoSet::Enum e(*cur->mDOMExpandoSet); !e.empty(); e.popFront())
   334                 JS_CallHashSetObjectTracer(trc, e, e.front(), "DOM expando object");
   335         }
   336     }
   337 }
   339 static PLDHashOperator
   340 WrappedNativeSuspecter(PLDHashTable *table, PLDHashEntryHdr *hdr,
   341                        uint32_t number, void *arg)
   342 {
   343     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
   345     if (wrapper->HasExternalReference()) {
   346         nsCycleCollectionNoteRootCallback *cb =
   347             static_cast<nsCycleCollectionNoteRootCallback *>(arg);
   348         XPCJSRuntime::SuspectWrappedNative(wrapper, *cb);
   349     }
   351     return PL_DHASH_NEXT;
   352 }
   354 static void
   355 SuspectDOMExpandos(JSObject *obj, nsCycleCollectionNoteRootCallback &cb)
   356 {
   357     MOZ_ASSERT(dom::GetDOMClass(obj) && dom::GetDOMClass(obj)->mDOMObjectIsISupports);
   358     nsISupports* native = dom::UnwrapDOMObject<nsISupports>(obj);
   359     cb.NoteXPCOMRoot(native);
   360 }
   362 // static
   363 void
   364 XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
   365                                           nsCycleCollectionNoteRootCallback& cb)
   366 {
   367     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
   368         cur->mWrappedNativeMap->Enumerate(WrappedNativeSuspecter, &cb);
   369         if (cur->mDOMExpandoSet) {
   370             for (DOMExpandoSet::Range r = cur->mDOMExpandoSet->all(); !r.empty(); r.popFront())
   371                 SuspectDOMExpandos(r.front(), cb);
   372         }
   373     }
   374 }
   376 // static
   377 void
   378 XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt)
   379 {
   380     // We are in JSGC_MARK_END and JSGC_FINALIZE_END must always follow it
   381     // calling FinishedFinalizationPhaseOfGC and clearing gDyingScopes in
   382     // KillDyingScopes.
   383     MOZ_ASSERT(!gDyingScopes, "JSGC_MARK_END without JSGC_FINALIZE_END");
   385     XPCWrappedNativeScope* prev = nullptr;
   386     XPCWrappedNativeScope* cur = gScopes;
   388     while (cur) {
   389         // Sweep waivers.
   390         if (cur->mWaiverWrapperMap)
   391             cur->mWaiverWrapperMap->Sweep();
   393         XPCWrappedNativeScope* next = cur->mNext;
   395         if (cur->mGlobalJSObject && cur->mGlobalJSObject.isAboutToBeFinalized()) {
   396             cur->mGlobalJSObject.finalize(fop->runtime());
   397             // Move this scope from the live list to the dying list.
   398             if (prev)
   399                 prev->mNext = next;
   400             else
   401                 gScopes = next;
   402             cur->mNext = gDyingScopes;
   403             gDyingScopes = cur;
   404             cur = nullptr;
   405         }
   406         if (cur)
   407             prev = cur;
   408         cur = next;
   409     }
   410 }
   412 // static
   413 void
   414 XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC()
   415 {
   416     KillDyingScopes();
   417 }
   419 static PLDHashOperator
   420 WrappedNativeMarker(PLDHashTable *table, PLDHashEntryHdr *hdr,
   421                     uint32_t number_t, void *arg)
   422 {
   423     ((Native2WrappedNativeMap::Entry*)hdr)->value->Mark();
   424     return PL_DHASH_NEXT;
   425 }
   427 // We need to explicitly mark all the protos too because some protos may be
   428 // alive in the hashtable but not currently in use by any wrapper
   429 static PLDHashOperator
   430 WrappedNativeProtoMarker(PLDHashTable *table, PLDHashEntryHdr *hdr,
   431                          uint32_t number, void *arg)
   432 {
   433     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->Mark();
   434     return PL_DHASH_NEXT;
   435 }
   437 // static
   438 void
   439 XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos()
   440 {
   441     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
   442         cur->mWrappedNativeMap->Enumerate(WrappedNativeMarker, nullptr);
   443         cur->mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMarker, nullptr);
   444     }
   445 }
   447 #ifdef DEBUG
   448 static PLDHashOperator
   449 ASSERT_WrappedNativeSetNotMarked(PLDHashTable *table, PLDHashEntryHdr *hdr,
   450                                  uint32_t number, void *arg)
   451 {
   452     ((Native2WrappedNativeMap::Entry*)hdr)->value->ASSERT_SetsNotMarked();
   453     return PL_DHASH_NEXT;
   454 }
   456 static PLDHashOperator
   457 ASSERT_WrappedNativeProtoSetNotMarked(PLDHashTable *table, PLDHashEntryHdr *hdr,
   458                                       uint32_t number, void *arg)
   459 {
   460     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->ASSERT_SetNotMarked();
   461     return PL_DHASH_NEXT;
   462 }
   464 // static
   465 void
   466 XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked()
   467 {
   468     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
   469         cur->mWrappedNativeMap->Enumerate(ASSERT_WrappedNativeSetNotMarked, nullptr);
   470         cur->mWrappedNativeProtoMap->Enumerate(ASSERT_WrappedNativeProtoSetNotMarked, nullptr);
   471     }
   472 }
   473 #endif
   475 static PLDHashOperator
   476 WrappedNativeTearoffSweeper(PLDHashTable *table, PLDHashEntryHdr *hdr,
   477                             uint32_t number, void *arg)
   478 {
   479     ((Native2WrappedNativeMap::Entry*)hdr)->value->SweepTearOffs();
   480     return PL_DHASH_NEXT;
   481 }
   483 // static
   484 void
   485 XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs()
   486 {
   487     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
   488         cur->mWrappedNativeMap->Enumerate(WrappedNativeTearoffSweeper, nullptr);
   489 }
   491 // static
   492 void
   493 XPCWrappedNativeScope::KillDyingScopes()
   494 {
   495     XPCWrappedNativeScope* cur = gDyingScopes;
   496     while (cur) {
   497         XPCWrappedNativeScope* next = cur->mNext;
   498         if (cur->mGlobalJSObject)
   499             GetCompartmentPrivate(cur->mGlobalJSObject)->scope = nullptr;
   500         delete cur;
   501         cur = next;
   502     }
   503     gDyingScopes = nullptr;
   504 }
   506 struct ShutdownData
   507 {
   508     ShutdownData()
   509         : wrapperCount(0),
   510           protoCount(0) {}
   511     int wrapperCount;
   512     int protoCount;
   513 };
   515 static PLDHashOperator
   516 WrappedNativeShutdownEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
   517                                 uint32_t number, void *arg)
   518 {
   519     ShutdownData* data = (ShutdownData*) arg;
   520     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
   522     if (wrapper->IsValid()) {
   523         wrapper->SystemIsBeingShutDown();
   524         data->wrapperCount++;
   525     }
   526     return PL_DHASH_REMOVE;
   527 }
   529 static PLDHashOperator
   530 WrappedNativeProtoShutdownEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
   531                                      uint32_t number, void *arg)
   532 {
   533     ShutdownData* data = (ShutdownData*) arg;
   534     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->
   535         SystemIsBeingShutDown();
   536     data->protoCount++;
   537     return PL_DHASH_REMOVE;
   538 }
   540 //static
   541 void
   542 XPCWrappedNativeScope::SystemIsBeingShutDown()
   543 {
   544     int liveScopeCount = 0;
   546     ShutdownData data;
   548     XPCWrappedNativeScope* cur;
   550     // First move all the scopes to the dying list.
   552     cur = gScopes;
   553     while (cur) {
   554         XPCWrappedNativeScope* next = cur->mNext;
   555         cur->mNext = gDyingScopes;
   556         gDyingScopes = cur;
   557         cur = next;
   558         liveScopeCount++;
   559     }
   560     gScopes = nullptr;
   562     // We're forcibly killing scopes, rather than allowing them to go away
   563     // when they're ready. As such, we need to do some cleanup before they
   564     // can safely be destroyed.
   566     for (cur = gDyingScopes; cur; cur = cur->mNext) {
   567         // Give the Components object a chance to try to clean up.
   568         if (cur->mComponents)
   569             cur->mComponents->SystemIsBeingShutDown();
   571         // Walk the protos first. Wrapper shutdown can leave dangling
   572         // proto pointers in the proto map.
   573         cur->mWrappedNativeProtoMap->
   574                 Enumerate(WrappedNativeProtoShutdownEnumerator,  &data);
   575         cur->mWrappedNativeMap->
   576                 Enumerate(WrappedNativeShutdownEnumerator,  &data);
   577     }
   579     // Now it is safe to kill all the scopes.
   580     KillDyingScopes();
   581 }
   584 /***************************************************************************/
   586 static PLDHashOperator
   587 WNProtoRemover(PLDHashTable *table, PLDHashEntryHdr *hdr,
   588                uint32_t number, void *arg)
   589 {
   590     XPCWrappedNativeProtoMap* detachedMap = (XPCWrappedNativeProtoMap*)arg;
   592     XPCWrappedNativeProto* proto = (XPCWrappedNativeProto*)
   593         ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value;
   595     detachedMap->Add(proto);
   597     return PL_DHASH_REMOVE;
   598 }
   600 void
   601 XPCWrappedNativeScope::RemoveWrappedNativeProtos()
   602 {
   603     mWrappedNativeProtoMap->Enumerate(WNProtoRemover,
   604                                       GetRuntime()->GetDetachedWrappedNativeProtoMap());
   605 }
   607 JSObject *
   608 XPCWrappedNativeScope::GetExpandoChain(HandleObject target)
   609 {
   610     MOZ_ASSERT(GetObjectScope(target) == this);
   611     if (!mXrayExpandos.initialized())
   612         return nullptr;
   613     return mXrayExpandos.lookup(target);
   614 }
   616 bool
   617 XPCWrappedNativeScope::SetExpandoChain(JSContext *cx, HandleObject target,
   618                                        HandleObject chain)
   619 {
   620     MOZ_ASSERT(GetObjectScope(target) == this);
   621     MOZ_ASSERT(js::IsObjectInContextCompartment(target, cx));
   622     MOZ_ASSERT_IF(chain, GetObjectScope(chain) == this);
   623     if (!mXrayExpandos.initialized() && !mXrayExpandos.init(cx))
   624         return false;
   625     return mXrayExpandos.put(cx, target, chain);
   626 }
   628 /***************************************************************************/
   630 // static
   631 void
   632 XPCWrappedNativeScope::DebugDumpAllScopes(int16_t depth)
   633 {
   634 #ifdef DEBUG
   635     depth-- ;
   637     // get scope count.
   638     int count = 0;
   639     XPCWrappedNativeScope* cur;
   640     for (cur = gScopes; cur; cur = cur->mNext)
   641         count++ ;
   643     XPC_LOG_ALWAYS(("chain of %d XPCWrappedNativeScope(s)", count));
   644     XPC_LOG_INDENT();
   645         XPC_LOG_ALWAYS(("gDyingScopes @ %x", gDyingScopes));
   646         if (depth)
   647             for (cur = gScopes; cur; cur = cur->mNext)
   648                 cur->DebugDump(depth);
   649     XPC_LOG_OUTDENT();
   650 #endif
   651 }
   653 #ifdef DEBUG
   654 static PLDHashOperator
   655 WrappedNativeMapDumpEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
   656                                uint32_t number, void *arg)
   657 {
   658     ((Native2WrappedNativeMap::Entry*)hdr)->value->DebugDump(*(int16_t*)arg);
   659     return PL_DHASH_NEXT;
   660 }
   661 static PLDHashOperator
   662 WrappedNativeProtoMapDumpEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
   663                                     uint32_t number, void *arg)
   664 {
   665     ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->DebugDump(*(int16_t*)arg);
   666     return PL_DHASH_NEXT;
   667 }
   668 #endif
   670 void
   671 XPCWrappedNativeScope::DebugDump(int16_t depth)
   672 {
   673 #ifdef DEBUG
   674     depth-- ;
   675     XPC_LOG_ALWAYS(("XPCWrappedNativeScope @ %x", this));
   676     XPC_LOG_INDENT();
   677         XPC_LOG_ALWAYS(("mNext @ %x", mNext));
   678         XPC_LOG_ALWAYS(("mComponents @ %x", mComponents.get()));
   679         XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject.get()));
   681         XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)",         \
   682                         mWrappedNativeMap,                                    \
   683                         mWrappedNativeMap ? mWrappedNativeMap->Count() : 0));
   684         // iterate contexts...
   685         if (depth && mWrappedNativeMap && mWrappedNativeMap->Count()) {
   686             XPC_LOG_INDENT();
   687             mWrappedNativeMap->Enumerate(WrappedNativeMapDumpEnumerator, &depth);
   688             XPC_LOG_OUTDENT();
   689         }
   691         XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)",      \
   692                         mWrappedNativeProtoMap,                               \
   693                         mWrappedNativeProtoMap ? mWrappedNativeProtoMap->Count() : 0));
   694         // iterate contexts...
   695         if (depth && mWrappedNativeProtoMap && mWrappedNativeProtoMap->Count()) {
   696             XPC_LOG_INDENT();
   697             mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMapDumpEnumerator, &depth);
   698             XPC_LOG_OUTDENT();
   699         }
   700     XPC_LOG_OUTDENT();
   701 #endif
   702 }
   704 void
   705 XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo)
   706 {
   707     for (XPCWrappedNativeScope *cur = gScopes; cur; cur = cur->mNext)
   708         cur->AddSizeOfIncludingThis(scopeSizeInfo);
   709 }
   711 void
   712 XPCWrappedNativeScope::AddSizeOfIncludingThis(ScopeSizeInfo* scopeSizeInfo)
   713 {
   714     scopeSizeInfo->mScopeAndMapSize += scopeSizeInfo->mMallocSizeOf(this);
   715     scopeSizeInfo->mScopeAndMapSize +=
   716         mWrappedNativeMap->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf);
   717     scopeSizeInfo->mScopeAndMapSize +=
   718         mWrappedNativeProtoMap->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf);
   720     if (dom::HasProtoAndIfaceCache(mGlobalJSObject)) {
   721         dom::ProtoAndIfaceCache* cache = dom::GetProtoAndIfaceCache(mGlobalJSObject);
   722         scopeSizeInfo->mProtoAndIfaceCacheSize +=
   723             cache->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf);
   724     }
   726     // There are other XPCWrappedNativeScope members that could be measured;
   727     // the above ones have been seen by DMD to be worth measuring.  More stuff
   728     // may be added later.
   729 }

mercurial