js/xpconnect/src/XPCWrappedNativeScope.cpp

branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
equal deleted inserted replaced
-1:000000000000 0:14702de6fb02
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 /* Class used to manage the wrapped native objects within a JS scope. */
8
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"
16
17 #include "mozilla/dom/BindingUtils.h"
18
19 using namespace mozilla;
20 using namespace xpc;
21 using namespace JS;
22
23 /***************************************************************************/
24
25 XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr;
26 XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
27
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 }
38
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;
45
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;
54
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;
60
61 // If this domain isn't whitelisted, we're done.
62 if (!nsContentUtils::AllowXULXBLForPrincipal(aPrincipal))
63 return false;
64
65 // Check the pref to determine how we should behave.
66 return !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
67 }
68
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
87
88 mNext = gScopes;
89 gScopes = this;
90
91 // Grab the XPCContext associated with our context.
92 mContext = XPCContext::GetXPCContext(cx);
93 mContext->AddScope(this);
94 }
95
96 MOZ_COUNT_CTOR(XPCWrappedNativeScope);
97
98 // Attach ourselves to the compartment private.
99 CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal);
100 priv->scope = this;
101
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);
107
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 }
120
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 }
131
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 }
142
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;
150
151 if (NS_WARN_IF(!val.isObject()))
152 return false;
153
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 }
161
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 }
174
175 bool
176 XPCWrappedNativeScope::AttachComponentsObject(JSContext* aCx)
177 {
178 RootedObject components(aCx);
179 if (!GetComponentsJSObject(&components))
180 return false;
181
182 RootedObject global(aCx, GetGlobalJSObject());
183 MOZ_ASSERT(js::IsObjectInContextCompartment(global, aCx));
184
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 }
189
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"));
198
199 // If we already have a special XBL scope object, we know what to use.
200 if (mXBLScope)
201 return mXBLScope;
202
203 // If this scope doesn't need an XBL scope, just return the global.
204 if (!mUseXBLScope)
205 return global;
206
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;
220
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);
228
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();
234
235 // Tag it.
236 EnsureCompartmentPrivate(js::UncheckedUnwrap(mXBLScope))->scope->mIsXBLScope = true;
237
238 // Good to go!
239 return mXBLScope;
240 }
241
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 }
250
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 }
262
263 bool AllowXBLScope(JSCompartment *c)
264 {
265 XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
266 return scope && scope->AllowXBLScope();
267 }
268
269 bool UseXBLScope(JSCompartment *c)
270 {
271 XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
272 return scope && scope->UseXBLScope();
273 }
274
275 } /* namespace xpc */
276
277 XPCWrappedNativeScope::~XPCWrappedNativeScope()
278 {
279 MOZ_COUNT_DTOR(XPCWrappedNativeScope);
280
281 // We can do additional cleanup assertions here...
282
283 if (mWrappedNativeMap) {
284 MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
285 delete mWrappedNativeMap;
286 }
287
288 if (mWrappedNativeProtoMap) {
289 MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
290 delete mWrappedNativeProtoMap;
291 }
292
293 if (mContext)
294 mContext->RemoveScope(this);
295
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;
300
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;
304
305 if (mXrayExpandos.initialized())
306 mXrayExpandos.destroy();
307
308 JSRuntime *rt = XPCJSRuntime::Get()->Runtime();
309 mXBLScope.finalize(rt);
310 mGlobalJSObject.finalize(rt);
311 }
312
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);
320
321 return PL_DHASH_NEXT;
322 }
323
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 }
338
339 static PLDHashOperator
340 WrappedNativeSuspecter(PLDHashTable *table, PLDHashEntryHdr *hdr,
341 uint32_t number, void *arg)
342 {
343 XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
344
345 if (wrapper->HasExternalReference()) {
346 nsCycleCollectionNoteRootCallback *cb =
347 static_cast<nsCycleCollectionNoteRootCallback *>(arg);
348 XPCJSRuntime::SuspectWrappedNative(wrapper, *cb);
349 }
350
351 return PL_DHASH_NEXT;
352 }
353
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 }
361
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 }
375
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");
384
385 XPCWrappedNativeScope* prev = nullptr;
386 XPCWrappedNativeScope* cur = gScopes;
387
388 while (cur) {
389 // Sweep waivers.
390 if (cur->mWaiverWrapperMap)
391 cur->mWaiverWrapperMap->Sweep();
392
393 XPCWrappedNativeScope* next = cur->mNext;
394
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 }
411
412 // static
413 void
414 XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC()
415 {
416 KillDyingScopes();
417 }
418
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 }
426
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 }
436
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 }
446
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 }
455
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 }
463
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
474
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 }
482
483 // static
484 void
485 XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs()
486 {
487 for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
488 cur->mWrappedNativeMap->Enumerate(WrappedNativeTearoffSweeper, nullptr);
489 }
490
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 }
505
506 struct ShutdownData
507 {
508 ShutdownData()
509 : wrapperCount(0),
510 protoCount(0) {}
511 int wrapperCount;
512 int protoCount;
513 };
514
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;
521
522 if (wrapper->IsValid()) {
523 wrapper->SystemIsBeingShutDown();
524 data->wrapperCount++;
525 }
526 return PL_DHASH_REMOVE;
527 }
528
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 }
539
540 //static
541 void
542 XPCWrappedNativeScope::SystemIsBeingShutDown()
543 {
544 int liveScopeCount = 0;
545
546 ShutdownData data;
547
548 XPCWrappedNativeScope* cur;
549
550 // First move all the scopes to the dying list.
551
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;
561
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.
565
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();
570
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 }
578
579 // Now it is safe to kill all the scopes.
580 KillDyingScopes();
581 }
582
583
584 /***************************************************************************/
585
586 static PLDHashOperator
587 WNProtoRemover(PLDHashTable *table, PLDHashEntryHdr *hdr,
588 uint32_t number, void *arg)
589 {
590 XPCWrappedNativeProtoMap* detachedMap = (XPCWrappedNativeProtoMap*)arg;
591
592 XPCWrappedNativeProto* proto = (XPCWrappedNativeProto*)
593 ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value;
594
595 detachedMap->Add(proto);
596
597 return PL_DHASH_REMOVE;
598 }
599
600 void
601 XPCWrappedNativeScope::RemoveWrappedNativeProtos()
602 {
603 mWrappedNativeProtoMap->Enumerate(WNProtoRemover,
604 GetRuntime()->GetDetachedWrappedNativeProtoMap());
605 }
606
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 }
615
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 }
627
628 /***************************************************************************/
629
630 // static
631 void
632 XPCWrappedNativeScope::DebugDumpAllScopes(int16_t depth)
633 {
634 #ifdef DEBUG
635 depth-- ;
636
637 // get scope count.
638 int count = 0;
639 XPCWrappedNativeScope* cur;
640 for (cur = gScopes; cur; cur = cur->mNext)
641 count++ ;
642
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 }
652
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
669
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()));
680
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 }
690
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 }
703
704 void
705 XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo)
706 {
707 for (XPCWrappedNativeScope *cur = gScopes; cur; cur = cur->mNext)
708 cur->AddSizeOfIncludingThis(scopeSizeInfo);
709 }
710
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);
719
720 if (dom::HasProtoAndIfaceCache(mGlobalJSObject)) {
721 dom::ProtoAndIfaceCache* cache = dom::GetProtoAndIfaceCache(mGlobalJSObject);
722 scopeSizeInfo->mProtoAndIfaceCacheSize +=
723 cache->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf);
724 }
725
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