1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,729 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Class used to manage the wrapped native objects within a JS scope. */ 1.11 + 1.12 +#include "xpcprivate.h" 1.13 +#include "XPCWrapper.h" 1.14 +#include "nsContentUtils.h" 1.15 +#include "nsCycleCollectionNoteRootCallback.h" 1.16 +#include "nsPrincipal.h" 1.17 +#include "mozilla/MemoryReporting.h" 1.18 +#include "mozilla/Preferences.h" 1.19 + 1.20 +#include "mozilla/dom/BindingUtils.h" 1.21 + 1.22 +using namespace mozilla; 1.23 +using namespace xpc; 1.24 +using namespace JS; 1.25 + 1.26 +/***************************************************************************/ 1.27 + 1.28 +XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr; 1.29 +XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr; 1.30 + 1.31 +// static 1.32 +XPCWrappedNativeScope* 1.33 +XPCWrappedNativeScope::GetNewOrUsed(JSContext *cx, JS::HandleObject aGlobal) 1.34 +{ 1.35 + XPCWrappedNativeScope* scope = GetObjectScope(aGlobal); 1.36 + if (!scope) { 1.37 + scope = new XPCWrappedNativeScope(cx, aGlobal); 1.38 + } 1.39 + return scope; 1.40 +} 1.41 + 1.42 +static bool 1.43 +RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal) 1.44 +{ 1.45 + // Check for random JSD scopes that don't have a principal. 1.46 + if (!aPrincipal) 1.47 + return false; 1.48 + 1.49 + // The SafeJSContext is lazily created, and tends to be created at really 1.50 + // weird times, at least for xpcshell (often very early in startup or late 1.51 + // in shutdown). Its scope isn't system principal, so if we proceeded we'd 1.52 + // end up calling into AllowXULXBLForPrincipal, which depends on all kinds 1.53 + // of persistent storage and permission machinery that may or not be running. 1.54 + // We know the answer to the question here, so just short-circuit. 1.55 + if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass) 1.56 + return false; 1.57 + 1.58 + // AllowXULXBLForPrincipal will return true for system principal, but we 1.59 + // don't want that here. 1.60 + MOZ_ASSERT(nsContentUtils::IsInitialized()); 1.61 + if (nsContentUtils::IsSystemPrincipal(aPrincipal)) 1.62 + return false; 1.63 + 1.64 + // If this domain isn't whitelisted, we're done. 1.65 + if (!nsContentUtils::AllowXULXBLForPrincipal(aPrincipal)) 1.66 + return false; 1.67 + 1.68 + // Check the pref to determine how we should behave. 1.69 + return !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false); 1.70 +} 1.71 + 1.72 +XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext *cx, 1.73 + JS::HandleObject aGlobal) 1.74 + : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)), 1.75 + mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)), 1.76 + mComponents(nullptr), 1.77 + mNext(nullptr), 1.78 + mGlobalJSObject(aGlobal), 1.79 + mIsXBLScope(false) 1.80 +{ 1.81 + // add ourselves to the scopes list 1.82 + { 1.83 + MOZ_ASSERT(aGlobal); 1.84 + MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS | 1.85 + JSCLASS_HAS_PRIVATE)); 1.86 +#ifdef DEBUG 1.87 + for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) 1.88 + MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object"); 1.89 +#endif 1.90 + 1.91 + mNext = gScopes; 1.92 + gScopes = this; 1.93 + 1.94 + // Grab the XPCContext associated with our context. 1.95 + mContext = XPCContext::GetXPCContext(cx); 1.96 + mContext->AddScope(this); 1.97 + } 1.98 + 1.99 + MOZ_COUNT_CTOR(XPCWrappedNativeScope); 1.100 + 1.101 + // Attach ourselves to the compartment private. 1.102 + CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal); 1.103 + priv->scope = this; 1.104 + 1.105 + // Determine whether we would allow an XBL scope in this situation. 1.106 + // In addition to being pref-controlled, we also disable XBL scopes for 1.107 + // remote XUL domains, _except_ if we have an additional pref override set. 1.108 + nsIPrincipal *principal = GetPrincipal(); 1.109 + mAllowXBLScope = !RemoteXULForbidsXBLScope(principal, aGlobal); 1.110 + 1.111 + // Determine whether to use an XBL scope. 1.112 + mUseXBLScope = mAllowXBLScope; 1.113 + if (mUseXBLScope) { 1.114 + const js::Class *clasp = js::GetObjectClass(mGlobalJSObject); 1.115 + mUseXBLScope = !strcmp(clasp->name, "Window") || 1.116 + !strcmp(clasp->name, "ChromeWindow") || 1.117 + !strcmp(clasp->name, "ModalContentWindow"); 1.118 + } 1.119 + if (mUseXBLScope) { 1.120 + mUseXBLScope = principal && !nsContentUtils::IsSystemPrincipal(principal); 1.121 + } 1.122 +} 1.123 + 1.124 +// static 1.125 +bool 1.126 +XPCWrappedNativeScope::IsDyingScope(XPCWrappedNativeScope *scope) 1.127 +{ 1.128 + for (XPCWrappedNativeScope *cur = gDyingScopes; cur; cur = cur->mNext) { 1.129 + if (scope == cur) 1.130 + return true; 1.131 + } 1.132 + return false; 1.133 +} 1.134 + 1.135 +bool 1.136 +XPCWrappedNativeScope::GetComponentsJSObject(JS::MutableHandleObject obj) 1.137 +{ 1.138 + AutoJSContext cx; 1.139 + if (!mComponents) { 1.140 + nsIPrincipal *p = GetPrincipal(); 1.141 + bool system = XPCWrapper::GetSecurityManager()->IsSystemPrincipal(p); 1.142 + mComponents = system ? new nsXPCComponents(this) 1.143 + : new nsXPCComponentsBase(this); 1.144 + } 1.145 + 1.146 + RootedValue val(cx); 1.147 + xpcObjectHelper helper(mComponents); 1.148 + bool ok = XPCConvert::NativeInterface2JSObject(&val, nullptr, helper, 1.149 + nullptr, nullptr, false, 1.150 + nullptr); 1.151 + if (NS_WARN_IF(!ok)) 1.152 + return false; 1.153 + 1.154 + if (NS_WARN_IF(!val.isObject())) 1.155 + return false; 1.156 + 1.157 + // The call to wrap() here is necessary even though the object is same- 1.158 + // compartment, because it applies our security wrapper. 1.159 + obj.set(&val.toObject()); 1.160 + if (NS_WARN_IF(!JS_WrapObject(cx, obj))) 1.161 + return false; 1.162 + return true; 1.163 +} 1.164 + 1.165 +void 1.166 +XPCWrappedNativeScope::ForcePrivilegedComponents() 1.167 +{ 1.168 + // This may only be called on unprivileged scopes during automation where 1.169 + // we allow insecure things. 1.170 + MOZ_RELEASE_ASSERT(Preferences::GetBool("security.turn_off_all_security_so_" 1.171 + "that_viruses_can_take_over_this_" 1.172 + "computer")); 1.173 + nsCOMPtr<nsIXPCComponents> c = do_QueryInterface(mComponents); 1.174 + if (!c) 1.175 + mComponents = new nsXPCComponents(this); 1.176 +} 1.177 + 1.178 +bool 1.179 +XPCWrappedNativeScope::AttachComponentsObject(JSContext* aCx) 1.180 +{ 1.181 + RootedObject components(aCx); 1.182 + if (!GetComponentsJSObject(&components)) 1.183 + return false; 1.184 + 1.185 + RootedObject global(aCx, GetGlobalJSObject()); 1.186 + MOZ_ASSERT(js::IsObjectInContextCompartment(global, aCx)); 1.187 + 1.188 + RootedId id(aCx, XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)); 1.189 + return JS_DefinePropertyById(aCx, global, id, ObjectValue(*components), 1.190 + nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY); 1.191 +} 1.192 + 1.193 +JSObject* 1.194 +XPCWrappedNativeScope::EnsureXBLScope(JSContext *cx) 1.195 +{ 1.196 + JS::RootedObject global(cx, GetGlobalJSObject()); 1.197 + MOZ_ASSERT(js::IsObjectInContextCompartment(global, cx)); 1.198 + MOZ_ASSERT(!mIsXBLScope); 1.199 + MOZ_ASSERT(strcmp(js::GetObjectClass(global)->name, 1.200 + "nsXBLPrototypeScript compilation scope")); 1.201 + 1.202 + // If we already have a special XBL scope object, we know what to use. 1.203 + if (mXBLScope) 1.204 + return mXBLScope; 1.205 + 1.206 + // If this scope doesn't need an XBL scope, just return the global. 1.207 + if (!mUseXBLScope) 1.208 + return global; 1.209 + 1.210 + // Set up the sandbox options. Note that we use the DOM global as the 1.211 + // sandboxPrototype so that the XBL scope can access all the DOM objects 1.212 + // it's accustomed to accessing. 1.213 + // 1.214 + // NB: One would think that wantXrays wouldn't make a difference here. 1.215 + // However, wantXrays lives a secret double life, and one of its other 1.216 + // hobbies is to waive Xray on the returned sandbox when set to false. 1.217 + // So make sure to keep this set to true, here. 1.218 + SandboxOptions options; 1.219 + options.wantXrays = true; 1.220 + options.wantComponents = true; 1.221 + options.proto = global; 1.222 + options.sameZoneAs = global; 1.223 + 1.224 + // Use an nsExpandedPrincipal to create asymmetric security. 1.225 + nsIPrincipal *principal = GetPrincipal(); 1.226 + nsCOMPtr<nsIExpandedPrincipal> ep; 1.227 + MOZ_ASSERT(!(ep = do_QueryInterface(principal))); 1.228 + nsTArray< nsCOMPtr<nsIPrincipal> > principalAsArray(1); 1.229 + principalAsArray.AppendElement(principal); 1.230 + ep = new nsExpandedPrincipal(principalAsArray); 1.231 + 1.232 + // Create the sandbox. 1.233 + RootedValue v(cx); 1.234 + nsresult rv = CreateSandboxObject(cx, &v, ep, options); 1.235 + NS_ENSURE_SUCCESS(rv, nullptr); 1.236 + mXBLScope = &v.toObject(); 1.237 + 1.238 + // Tag it. 1.239 + EnsureCompartmentPrivate(js::UncheckedUnwrap(mXBLScope))->scope->mIsXBLScope = true; 1.240 + 1.241 + // Good to go! 1.242 + return mXBLScope; 1.243 +} 1.244 + 1.245 +bool 1.246 +XPCWrappedNativeScope::AllowXBLScope() 1.247 +{ 1.248 + // We only disallow XBL scopes in remote XUL situations. 1.249 + MOZ_ASSERT_IF(!mAllowXBLScope, 1.250 + nsContentUtils::AllowXULXBLForPrincipal(GetPrincipal())); 1.251 + return mAllowXBLScope; 1.252 +} 1.253 + 1.254 +namespace xpc { 1.255 +JSObject *GetXBLScope(JSContext *cx, JSObject *contentScopeArg) 1.256 +{ 1.257 + JS::RootedObject contentScope(cx, contentScopeArg); 1.258 + JSAutoCompartment ac(cx, contentScope); 1.259 + JSObject *scope = EnsureCompartmentPrivate(contentScope)->scope->EnsureXBLScope(cx); 1.260 + NS_ENSURE_TRUE(scope, nullptr); // See bug 858642. 1.261 + scope = js::UncheckedUnwrap(scope); 1.262 + JS::ExposeObjectToActiveJS(scope); 1.263 + return scope; 1.264 +} 1.265 + 1.266 +bool AllowXBLScope(JSCompartment *c) 1.267 +{ 1.268 + XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope; 1.269 + return scope && scope->AllowXBLScope(); 1.270 +} 1.271 + 1.272 +bool UseXBLScope(JSCompartment *c) 1.273 +{ 1.274 + XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope; 1.275 + return scope && scope->UseXBLScope(); 1.276 +} 1.277 + 1.278 +} /* namespace xpc */ 1.279 + 1.280 +XPCWrappedNativeScope::~XPCWrappedNativeScope() 1.281 +{ 1.282 + MOZ_COUNT_DTOR(XPCWrappedNativeScope); 1.283 + 1.284 + // We can do additional cleanup assertions here... 1.285 + 1.286 + if (mWrappedNativeMap) { 1.287 + MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map"); 1.288 + delete mWrappedNativeMap; 1.289 + } 1.290 + 1.291 + if (mWrappedNativeProtoMap) { 1.292 + MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map"); 1.293 + delete mWrappedNativeProtoMap; 1.294 + } 1.295 + 1.296 + if (mContext) 1.297 + mContext->RemoveScope(this); 1.298 + 1.299 + // This should not be necessary, since the Components object should die 1.300 + // with the scope but just in case. 1.301 + if (mComponents) 1.302 + mComponents->mScope = nullptr; 1.303 + 1.304 + // XXX we should assert that we are dead or that xpconnect has shutdown 1.305 + // XXX might not want to do this at xpconnect shutdown time??? 1.306 + mComponents = nullptr; 1.307 + 1.308 + if (mXrayExpandos.initialized()) 1.309 + mXrayExpandos.destroy(); 1.310 + 1.311 + JSRuntime *rt = XPCJSRuntime::Get()->Runtime(); 1.312 + mXBLScope.finalize(rt); 1.313 + mGlobalJSObject.finalize(rt); 1.314 +} 1.315 + 1.316 +static PLDHashOperator 1.317 +WrappedNativeJSGCThingTracer(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.318 + uint32_t number, void *arg) 1.319 +{ 1.320 + XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value; 1.321 + if (wrapper->HasExternalReference() && !wrapper->IsWrapperExpired()) 1.322 + wrapper->TraceSelf((JSTracer *)arg); 1.323 + 1.324 + return PL_DHASH_NEXT; 1.325 +} 1.326 + 1.327 +// static 1.328 +void 1.329 +XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt) 1.330 +{ 1.331 + // Do JS_CallTracer for all wrapped natives with external references, as 1.332 + // well as any DOM expando objects. 1.333 + for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) { 1.334 + cur->mWrappedNativeMap->Enumerate(WrappedNativeJSGCThingTracer, trc); 1.335 + if (cur->mDOMExpandoSet) { 1.336 + for (DOMExpandoSet::Enum e(*cur->mDOMExpandoSet); !e.empty(); e.popFront()) 1.337 + JS_CallHashSetObjectTracer(trc, e, e.front(), "DOM expando object"); 1.338 + } 1.339 + } 1.340 +} 1.341 + 1.342 +static PLDHashOperator 1.343 +WrappedNativeSuspecter(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.344 + uint32_t number, void *arg) 1.345 +{ 1.346 + XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value; 1.347 + 1.348 + if (wrapper->HasExternalReference()) { 1.349 + nsCycleCollectionNoteRootCallback *cb = 1.350 + static_cast<nsCycleCollectionNoteRootCallback *>(arg); 1.351 + XPCJSRuntime::SuspectWrappedNative(wrapper, *cb); 1.352 + } 1.353 + 1.354 + return PL_DHASH_NEXT; 1.355 +} 1.356 + 1.357 +static void 1.358 +SuspectDOMExpandos(JSObject *obj, nsCycleCollectionNoteRootCallback &cb) 1.359 +{ 1.360 + MOZ_ASSERT(dom::GetDOMClass(obj) && dom::GetDOMClass(obj)->mDOMObjectIsISupports); 1.361 + nsISupports* native = dom::UnwrapDOMObject<nsISupports>(obj); 1.362 + cb.NoteXPCOMRoot(native); 1.363 +} 1.364 + 1.365 +// static 1.366 +void 1.367 +XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt, 1.368 + nsCycleCollectionNoteRootCallback& cb) 1.369 +{ 1.370 + for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) { 1.371 + cur->mWrappedNativeMap->Enumerate(WrappedNativeSuspecter, &cb); 1.372 + if (cur->mDOMExpandoSet) { 1.373 + for (DOMExpandoSet::Range r = cur->mDOMExpandoSet->all(); !r.empty(); r.popFront()) 1.374 + SuspectDOMExpandos(r.front(), cb); 1.375 + } 1.376 + } 1.377 +} 1.378 + 1.379 +// static 1.380 +void 1.381 +XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt) 1.382 +{ 1.383 + // We are in JSGC_MARK_END and JSGC_FINALIZE_END must always follow it 1.384 + // calling FinishedFinalizationPhaseOfGC and clearing gDyingScopes in 1.385 + // KillDyingScopes. 1.386 + MOZ_ASSERT(!gDyingScopes, "JSGC_MARK_END without JSGC_FINALIZE_END"); 1.387 + 1.388 + XPCWrappedNativeScope* prev = nullptr; 1.389 + XPCWrappedNativeScope* cur = gScopes; 1.390 + 1.391 + while (cur) { 1.392 + // Sweep waivers. 1.393 + if (cur->mWaiverWrapperMap) 1.394 + cur->mWaiverWrapperMap->Sweep(); 1.395 + 1.396 + XPCWrappedNativeScope* next = cur->mNext; 1.397 + 1.398 + if (cur->mGlobalJSObject && cur->mGlobalJSObject.isAboutToBeFinalized()) { 1.399 + cur->mGlobalJSObject.finalize(fop->runtime()); 1.400 + // Move this scope from the live list to the dying list. 1.401 + if (prev) 1.402 + prev->mNext = next; 1.403 + else 1.404 + gScopes = next; 1.405 + cur->mNext = gDyingScopes; 1.406 + gDyingScopes = cur; 1.407 + cur = nullptr; 1.408 + } 1.409 + if (cur) 1.410 + prev = cur; 1.411 + cur = next; 1.412 + } 1.413 +} 1.414 + 1.415 +// static 1.416 +void 1.417 +XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC() 1.418 +{ 1.419 + KillDyingScopes(); 1.420 +} 1.421 + 1.422 +static PLDHashOperator 1.423 +WrappedNativeMarker(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.424 + uint32_t number_t, void *arg) 1.425 +{ 1.426 + ((Native2WrappedNativeMap::Entry*)hdr)->value->Mark(); 1.427 + return PL_DHASH_NEXT; 1.428 +} 1.429 + 1.430 +// We need to explicitly mark all the protos too because some protos may be 1.431 +// alive in the hashtable but not currently in use by any wrapper 1.432 +static PLDHashOperator 1.433 +WrappedNativeProtoMarker(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.434 + uint32_t number, void *arg) 1.435 +{ 1.436 + ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->Mark(); 1.437 + return PL_DHASH_NEXT; 1.438 +} 1.439 + 1.440 +// static 1.441 +void 1.442 +XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos() 1.443 +{ 1.444 + for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) { 1.445 + cur->mWrappedNativeMap->Enumerate(WrappedNativeMarker, nullptr); 1.446 + cur->mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMarker, nullptr); 1.447 + } 1.448 +} 1.449 + 1.450 +#ifdef DEBUG 1.451 +static PLDHashOperator 1.452 +ASSERT_WrappedNativeSetNotMarked(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.453 + uint32_t number, void *arg) 1.454 +{ 1.455 + ((Native2WrappedNativeMap::Entry*)hdr)->value->ASSERT_SetsNotMarked(); 1.456 + return PL_DHASH_NEXT; 1.457 +} 1.458 + 1.459 +static PLDHashOperator 1.460 +ASSERT_WrappedNativeProtoSetNotMarked(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.461 + uint32_t number, void *arg) 1.462 +{ 1.463 + ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->ASSERT_SetNotMarked(); 1.464 + return PL_DHASH_NEXT; 1.465 +} 1.466 + 1.467 +// static 1.468 +void 1.469 +XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked() 1.470 +{ 1.471 + for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) { 1.472 + cur->mWrappedNativeMap->Enumerate(ASSERT_WrappedNativeSetNotMarked, nullptr); 1.473 + cur->mWrappedNativeProtoMap->Enumerate(ASSERT_WrappedNativeProtoSetNotMarked, nullptr); 1.474 + } 1.475 +} 1.476 +#endif 1.477 + 1.478 +static PLDHashOperator 1.479 +WrappedNativeTearoffSweeper(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.480 + uint32_t number, void *arg) 1.481 +{ 1.482 + ((Native2WrappedNativeMap::Entry*)hdr)->value->SweepTearOffs(); 1.483 + return PL_DHASH_NEXT; 1.484 +} 1.485 + 1.486 +// static 1.487 +void 1.488 +XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs() 1.489 +{ 1.490 + for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) 1.491 + cur->mWrappedNativeMap->Enumerate(WrappedNativeTearoffSweeper, nullptr); 1.492 +} 1.493 + 1.494 +// static 1.495 +void 1.496 +XPCWrappedNativeScope::KillDyingScopes() 1.497 +{ 1.498 + XPCWrappedNativeScope* cur = gDyingScopes; 1.499 + while (cur) { 1.500 + XPCWrappedNativeScope* next = cur->mNext; 1.501 + if (cur->mGlobalJSObject) 1.502 + GetCompartmentPrivate(cur->mGlobalJSObject)->scope = nullptr; 1.503 + delete cur; 1.504 + cur = next; 1.505 + } 1.506 + gDyingScopes = nullptr; 1.507 +} 1.508 + 1.509 +struct ShutdownData 1.510 +{ 1.511 + ShutdownData() 1.512 + : wrapperCount(0), 1.513 + protoCount(0) {} 1.514 + int wrapperCount; 1.515 + int protoCount; 1.516 +}; 1.517 + 1.518 +static PLDHashOperator 1.519 +WrappedNativeShutdownEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.520 + uint32_t number, void *arg) 1.521 +{ 1.522 + ShutdownData* data = (ShutdownData*) arg; 1.523 + XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value; 1.524 + 1.525 + if (wrapper->IsValid()) { 1.526 + wrapper->SystemIsBeingShutDown(); 1.527 + data->wrapperCount++; 1.528 + } 1.529 + return PL_DHASH_REMOVE; 1.530 +} 1.531 + 1.532 +static PLDHashOperator 1.533 +WrappedNativeProtoShutdownEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.534 + uint32_t number, void *arg) 1.535 +{ 1.536 + ShutdownData* data = (ShutdownData*) arg; 1.537 + ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value-> 1.538 + SystemIsBeingShutDown(); 1.539 + data->protoCount++; 1.540 + return PL_DHASH_REMOVE; 1.541 +} 1.542 + 1.543 +//static 1.544 +void 1.545 +XPCWrappedNativeScope::SystemIsBeingShutDown() 1.546 +{ 1.547 + int liveScopeCount = 0; 1.548 + 1.549 + ShutdownData data; 1.550 + 1.551 + XPCWrappedNativeScope* cur; 1.552 + 1.553 + // First move all the scopes to the dying list. 1.554 + 1.555 + cur = gScopes; 1.556 + while (cur) { 1.557 + XPCWrappedNativeScope* next = cur->mNext; 1.558 + cur->mNext = gDyingScopes; 1.559 + gDyingScopes = cur; 1.560 + cur = next; 1.561 + liveScopeCount++; 1.562 + } 1.563 + gScopes = nullptr; 1.564 + 1.565 + // We're forcibly killing scopes, rather than allowing them to go away 1.566 + // when they're ready. As such, we need to do some cleanup before they 1.567 + // can safely be destroyed. 1.568 + 1.569 + for (cur = gDyingScopes; cur; cur = cur->mNext) { 1.570 + // Give the Components object a chance to try to clean up. 1.571 + if (cur->mComponents) 1.572 + cur->mComponents->SystemIsBeingShutDown(); 1.573 + 1.574 + // Walk the protos first. Wrapper shutdown can leave dangling 1.575 + // proto pointers in the proto map. 1.576 + cur->mWrappedNativeProtoMap-> 1.577 + Enumerate(WrappedNativeProtoShutdownEnumerator, &data); 1.578 + cur->mWrappedNativeMap-> 1.579 + Enumerate(WrappedNativeShutdownEnumerator, &data); 1.580 + } 1.581 + 1.582 + // Now it is safe to kill all the scopes. 1.583 + KillDyingScopes(); 1.584 +} 1.585 + 1.586 + 1.587 +/***************************************************************************/ 1.588 + 1.589 +static PLDHashOperator 1.590 +WNProtoRemover(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.591 + uint32_t number, void *arg) 1.592 +{ 1.593 + XPCWrappedNativeProtoMap* detachedMap = (XPCWrappedNativeProtoMap*)arg; 1.594 + 1.595 + XPCWrappedNativeProto* proto = (XPCWrappedNativeProto*) 1.596 + ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value; 1.597 + 1.598 + detachedMap->Add(proto); 1.599 + 1.600 + return PL_DHASH_REMOVE; 1.601 +} 1.602 + 1.603 +void 1.604 +XPCWrappedNativeScope::RemoveWrappedNativeProtos() 1.605 +{ 1.606 + mWrappedNativeProtoMap->Enumerate(WNProtoRemover, 1.607 + GetRuntime()->GetDetachedWrappedNativeProtoMap()); 1.608 +} 1.609 + 1.610 +JSObject * 1.611 +XPCWrappedNativeScope::GetExpandoChain(HandleObject target) 1.612 +{ 1.613 + MOZ_ASSERT(GetObjectScope(target) == this); 1.614 + if (!mXrayExpandos.initialized()) 1.615 + return nullptr; 1.616 + return mXrayExpandos.lookup(target); 1.617 +} 1.618 + 1.619 +bool 1.620 +XPCWrappedNativeScope::SetExpandoChain(JSContext *cx, HandleObject target, 1.621 + HandleObject chain) 1.622 +{ 1.623 + MOZ_ASSERT(GetObjectScope(target) == this); 1.624 + MOZ_ASSERT(js::IsObjectInContextCompartment(target, cx)); 1.625 + MOZ_ASSERT_IF(chain, GetObjectScope(chain) == this); 1.626 + if (!mXrayExpandos.initialized() && !mXrayExpandos.init(cx)) 1.627 + return false; 1.628 + return mXrayExpandos.put(cx, target, chain); 1.629 +} 1.630 + 1.631 +/***************************************************************************/ 1.632 + 1.633 +// static 1.634 +void 1.635 +XPCWrappedNativeScope::DebugDumpAllScopes(int16_t depth) 1.636 +{ 1.637 +#ifdef DEBUG 1.638 + depth-- ; 1.639 + 1.640 + // get scope count. 1.641 + int count = 0; 1.642 + XPCWrappedNativeScope* cur; 1.643 + for (cur = gScopes; cur; cur = cur->mNext) 1.644 + count++ ; 1.645 + 1.646 + XPC_LOG_ALWAYS(("chain of %d XPCWrappedNativeScope(s)", count)); 1.647 + XPC_LOG_INDENT(); 1.648 + XPC_LOG_ALWAYS(("gDyingScopes @ %x", gDyingScopes)); 1.649 + if (depth) 1.650 + for (cur = gScopes; cur; cur = cur->mNext) 1.651 + cur->DebugDump(depth); 1.652 + XPC_LOG_OUTDENT(); 1.653 +#endif 1.654 +} 1.655 + 1.656 +#ifdef DEBUG 1.657 +static PLDHashOperator 1.658 +WrappedNativeMapDumpEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.659 + uint32_t number, void *arg) 1.660 +{ 1.661 + ((Native2WrappedNativeMap::Entry*)hdr)->value->DebugDump(*(int16_t*)arg); 1.662 + return PL_DHASH_NEXT; 1.663 +} 1.664 +static PLDHashOperator 1.665 +WrappedNativeProtoMapDumpEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.666 + uint32_t number, void *arg) 1.667 +{ 1.668 + ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->DebugDump(*(int16_t*)arg); 1.669 + return PL_DHASH_NEXT; 1.670 +} 1.671 +#endif 1.672 + 1.673 +void 1.674 +XPCWrappedNativeScope::DebugDump(int16_t depth) 1.675 +{ 1.676 +#ifdef DEBUG 1.677 + depth-- ; 1.678 + XPC_LOG_ALWAYS(("XPCWrappedNativeScope @ %x", this)); 1.679 + XPC_LOG_INDENT(); 1.680 + XPC_LOG_ALWAYS(("mNext @ %x", mNext)); 1.681 + XPC_LOG_ALWAYS(("mComponents @ %x", mComponents.get())); 1.682 + XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject.get())); 1.683 + 1.684 + XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)", \ 1.685 + mWrappedNativeMap, \ 1.686 + mWrappedNativeMap ? mWrappedNativeMap->Count() : 0)); 1.687 + // iterate contexts... 1.688 + if (depth && mWrappedNativeMap && mWrappedNativeMap->Count()) { 1.689 + XPC_LOG_INDENT(); 1.690 + mWrappedNativeMap->Enumerate(WrappedNativeMapDumpEnumerator, &depth); 1.691 + XPC_LOG_OUTDENT(); 1.692 + } 1.693 + 1.694 + XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)", \ 1.695 + mWrappedNativeProtoMap, \ 1.696 + mWrappedNativeProtoMap ? mWrappedNativeProtoMap->Count() : 0)); 1.697 + // iterate contexts... 1.698 + if (depth && mWrappedNativeProtoMap && mWrappedNativeProtoMap->Count()) { 1.699 + XPC_LOG_INDENT(); 1.700 + mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMapDumpEnumerator, &depth); 1.701 + XPC_LOG_OUTDENT(); 1.702 + } 1.703 + XPC_LOG_OUTDENT(); 1.704 +#endif 1.705 +} 1.706 + 1.707 +void 1.708 +XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo) 1.709 +{ 1.710 + for (XPCWrappedNativeScope *cur = gScopes; cur; cur = cur->mNext) 1.711 + cur->AddSizeOfIncludingThis(scopeSizeInfo); 1.712 +} 1.713 + 1.714 +void 1.715 +XPCWrappedNativeScope::AddSizeOfIncludingThis(ScopeSizeInfo* scopeSizeInfo) 1.716 +{ 1.717 + scopeSizeInfo->mScopeAndMapSize += scopeSizeInfo->mMallocSizeOf(this); 1.718 + scopeSizeInfo->mScopeAndMapSize += 1.719 + mWrappedNativeMap->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf); 1.720 + scopeSizeInfo->mScopeAndMapSize += 1.721 + mWrappedNativeProtoMap->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf); 1.722 + 1.723 + if (dom::HasProtoAndIfaceCache(mGlobalJSObject)) { 1.724 + dom::ProtoAndIfaceCache* cache = dom::GetProtoAndIfaceCache(mGlobalJSObject); 1.725 + scopeSizeInfo->mProtoAndIfaceCacheSize += 1.726 + cache->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf); 1.727 + } 1.728 + 1.729 + // There are other XPCWrappedNativeScope members that could be measured; 1.730 + // the above ones have been seen by DMD to be worth measuring. More stuff 1.731 + // may be added later. 1.732 +}