1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code, released
17 : * March 31, 1998.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * John Bandhauer <jband@netscape.com> (original author)
26 : * Nicholas Nethercote <nnethercote@mozilla.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : /* Per JSRuntime object */
43 :
44 : #include "mozilla/Util.h"
45 :
46 : #include "xpcprivate.h"
47 : #include "xpcpublic.h"
48 : #include "WrapperFactory.h"
49 : #include "dom_quickstubs.h"
50 :
51 : #include "nsIMemoryReporter.h"
52 : #include "nsPrintfCString.h"
53 : #include "mozilla/FunctionTimer.h"
54 : #include "prsystem.h"
55 : #include "mozilla/Preferences.h"
56 : #include "mozilla/Telemetry.h"
57 :
58 : #include "nsContentUtils.h"
59 : #include "nsCCUncollectableMarker.h"
60 : #include "jsfriendapi.h"
61 : #include "js/MemoryMetrics.h"
62 :
63 : #include "nsJSPrincipals.h"
64 :
65 : #ifdef MOZ_CRASHREPORTER
66 : #include "nsExceptionHandler.h"
67 : #endif
68 :
69 : using namespace mozilla;
70 : using namespace mozilla::xpconnect::memory;
71 :
72 : /***************************************************************************/
73 :
74 : const char* XPCJSRuntime::mStrings[] = {
75 : "constructor", // IDX_CONSTRUCTOR
76 : "toString", // IDX_TO_STRING
77 : "toSource", // IDX_TO_SOURCE
78 : "lastResult", // IDX_LAST_RESULT
79 : "returnCode", // IDX_RETURN_CODE
80 : "value", // IDX_VALUE
81 : "QueryInterface", // IDX_QUERY_INTERFACE
82 : "Components", // IDX_COMPONENTS
83 : "wrappedJSObject", // IDX_WRAPPED_JSOBJECT
84 : "Object", // IDX_OBJECT
85 : "Function", // IDX_FUNCTION
86 : "prototype", // IDX_PROTOTYPE
87 : "createInstance", // IDX_CREATE_INSTANCE
88 : "item", // IDX_ITEM
89 : "__proto__", // IDX_PROTO
90 : "__iterator__", // IDX_ITERATOR
91 : "__exposedProps__", // IDX_EXPOSEDPROPS
92 : "__scriptOnly__", // IDX_SCRIPTONLY
93 : "baseURIObject", // IDX_BASEURIOBJECT
94 : "nodePrincipal", // IDX_NODEPRINCIPAL
95 : "documentURIObject" // IDX_DOCUMENTURIOBJECT
96 : };
97 :
98 : /***************************************************************************/
99 :
100 : static JSDHashOperator
101 198117 : WrappedJSDyingJSObjectFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
102 : uint32_t number, void *arg)
103 : {
104 198117 : nsTArray<nsXPCWrappedJS*>* array = static_cast<nsTArray<nsXPCWrappedJS*>*>(arg);
105 198117 : nsXPCWrappedJS* wrapper = ((JSObject2WrappedJSMap::Entry*)hdr)->value;
106 198117 : NS_ASSERTION(wrapper, "found a null JS wrapper!");
107 :
108 : // walk the wrapper chain and find any whose JSObject is to be finalized
109 613385 : while (wrapper) {
110 217151 : if (wrapper->IsSubjectToFinalization()) {
111 65038 : if (JS_IsAboutToBeFinalized(wrapper->GetJSObjectPreserveColor()))
112 5503 : array->AppendElement(wrapper);
113 : }
114 217151 : wrapper = wrapper->GetNextWrapper();
115 : }
116 198117 : return JS_DHASH_NEXT;
117 : }
118 :
119 : struct CX_AND_XPCRT_Data
120 : {
121 : JSContext* cx;
122 : XPCJSRuntime* rt;
123 : };
124 :
125 : static JSDHashOperator
126 403369 : NativeInterfaceSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
127 : uint32_t number, void *arg)
128 : {
129 403369 : XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
130 403369 : if (iface->IsMarked()) {
131 275830 : iface->Unmark();
132 275830 : return JS_DHASH_NEXT;
133 : }
134 :
135 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
136 : fputs("- Destroying XPCNativeInterface for ", stdout);
137 : JS_PutString(JSVAL_TO_STRING(iface->GetName()), stdout);
138 : putc('\n', stdout);
139 : #endif
140 :
141 127539 : XPCNativeInterface::DestroyInstance(iface);
142 127539 : return JS_DHASH_REMOVE;
143 : }
144 :
145 : // *Some* NativeSets are referenced from mClassInfo2NativeSetMap.
146 : // *All* NativeSets are referenced from mNativeSetMap.
147 : // So, in mClassInfo2NativeSetMap we just clear references to the unmarked.
148 : // In mNativeSetMap we clear the references to the unmarked *and* delete them.
149 :
150 : static JSDHashOperator
151 716870 : NativeUnMarkedSetRemover(JSDHashTable *table, JSDHashEntryHdr *hdr,
152 : uint32_t number, void *arg)
153 : {
154 716870 : XPCNativeSet* set = ((ClassInfo2NativeSetMap::Entry*)hdr)->value;
155 716870 : if (set->IsMarked())
156 680511 : return JS_DHASH_NEXT;
157 36359 : return JS_DHASH_REMOVE;
158 : }
159 :
160 : static JSDHashOperator
161 337018 : NativeSetSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
162 : uint32_t number, void *arg)
163 : {
164 337018 : XPCNativeSet* set = ((NativeSetMap::Entry*)hdr)->key_value;
165 337018 : if (set->IsMarked()) {
166 221767 : set->Unmark();
167 221767 : return JS_DHASH_NEXT;
168 : }
169 :
170 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
171 : printf("- Destroying XPCNativeSet for:\n");
172 : PRUint16 count = set->GetInterfaceCount();
173 : for (PRUint16 k = 0; k < count; k++) {
174 : XPCNativeInterface* iface = set->GetInterfaceAt(k);
175 : fputs(" ", stdout);
176 : JS_PutString(JSVAL_TO_STRING(iface->GetName()), stdout);
177 : putc('\n', stdout);
178 : }
179 : #endif
180 :
181 115251 : XPCNativeSet::DestroyInstance(set);
182 115251 : return JS_DHASH_REMOVE;
183 : }
184 :
185 : static JSDHashOperator
186 122164 : JSClassSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
187 : uint32_t number, void *arg)
188 : {
189 : XPCNativeScriptableShared* shared =
190 122164 : ((XPCNativeScriptableSharedMap::Entry*) hdr)->key;
191 122164 : if (shared->IsMarked()) {
192 : #ifdef off_XPC_REPORT_JSCLASS_FLUSHING
193 : printf("+ Marked XPCNativeScriptableShared for: %s @ %x\n",
194 : shared->GetJSClass()->name,
195 : shared->GetJSClass());
196 : #endif
197 101050 : shared->Unmark();
198 101050 : return JS_DHASH_NEXT;
199 : }
200 :
201 : #ifdef XPC_REPORT_JSCLASS_FLUSHING
202 : printf("- Destroying XPCNativeScriptableShared for: %s @ %x\n",
203 : shared->GetJSClass()->name,
204 : shared->GetJSClass());
205 : #endif
206 :
207 21114 : delete shared;
208 21114 : return JS_DHASH_REMOVE;
209 : }
210 :
211 : static JSDHashOperator
212 186781 : DyingProtoKiller(JSDHashTable *table, JSDHashEntryHdr *hdr,
213 : uint32_t number, void *arg)
214 : {
215 : XPCWrappedNativeProto* proto =
216 186781 : (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
217 186781 : delete proto;
218 186781 : return JS_DHASH_REMOVE;
219 : }
220 :
221 : static JSDHashOperator
222 0 : DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
223 : uint32_t number, void *arg)
224 : {
225 : XPCWrappedNativeProto* proto =
226 0 : (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
227 :
228 0 : proto->Mark();
229 0 : return JS_DHASH_NEXT;
230 : }
231 :
232 : // GCCallback calls are chained
233 : static JSBool
234 15428 : ContextCallback(JSContext *cx, unsigned operation)
235 : {
236 15428 : XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
237 15428 : if (self) {
238 15428 : if (operation == JSCONTEXT_NEW) {
239 7715 : if (!self->OnJSContextNew(cx))
240 0 : return false;
241 7713 : } else if (operation == JSCONTEXT_DESTROY) {
242 7713 : delete XPCContext::GetXPCContext(cx);
243 : }
244 : }
245 15428 : return true;
246 : }
247 :
248 6734 : xpc::CompartmentPrivate::~CompartmentPrivate()
249 : {
250 3367 : MOZ_COUNT_DTOR(xpc::CompartmentPrivate);
251 3367 : }
252 :
253 : static JSBool
254 3647 : CompartmentCallback(JSContext *cx, JSCompartment *compartment, unsigned op)
255 : {
256 3647 : JS_ASSERT(op == JSCOMPARTMENT_DESTROY);
257 :
258 3647 : XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
259 3647 : if (!self)
260 0 : return true;
261 :
262 : nsAutoPtr<xpc::CompartmentPrivate>
263 7294 : priv(static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment)));
264 3647 : if (!priv)
265 280 : return true;
266 :
267 3367 : JS_SetCompartmentPrivate(compartment, nsnull);
268 :
269 3367 : xpc::PtrAndPrincipalHashKey *key = priv->key;
270 3367 : XPCCompartmentMap &map = self->GetCompartmentMap();
271 : #ifdef DEBUG
272 3367 : JSCompartment *current = NULL;
273 3367 : NS_ASSERTION(map.Get(key, ¤t), "no compartment?");
274 3367 : NS_ASSERTION(current == compartment, "compartment mismatch");
275 : #endif
276 3367 : map.Remove(key);
277 :
278 3367 : return true;
279 : }
280 :
281 : struct ObjectHolder : public JSDHashEntryHdr
282 : {
283 : void *holder;
284 : nsScriptObjectTracer* tracer;
285 : };
286 :
287 : nsresult
288 7458 : XPCJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer)
289 : {
290 7458 : if (!mJSHolders.ops)
291 0 : return NS_ERROR_OUT_OF_MEMORY;
292 :
293 : ObjectHolder *entry =
294 : reinterpret_cast<ObjectHolder*>(JS_DHashTableOperate(&mJSHolders,
295 : aHolder,
296 7458 : JS_DHASH_ADD));
297 7458 : if (!entry)
298 0 : return NS_ERROR_OUT_OF_MEMORY;
299 :
300 7458 : entry->holder = aHolder;
301 7458 : entry->tracer = aTracer;
302 :
303 7458 : return NS_OK;
304 : }
305 :
306 : nsresult
307 7456 : XPCJSRuntime::RemoveJSHolder(void* aHolder)
308 : {
309 7456 : if (!mJSHolders.ops)
310 0 : return NS_ERROR_OUT_OF_MEMORY;
311 :
312 7456 : JS_DHashTableOperate(&mJSHolders, aHolder, JS_DHASH_REMOVE);
313 :
314 7456 : return NS_OK;
315 : }
316 :
317 : // static
318 14728 : void XPCJSRuntime::TraceBlackJS(JSTracer* trc, void* data)
319 : {
320 14728 : XPCJSRuntime* self = (XPCJSRuntime*)data;
321 :
322 : // Skip this part if XPConnect is shutting down. We get into
323 : // bad locking problems with the thread iteration otherwise.
324 14728 : if (!self->GetXPConnect()->IsShuttingDown()) {
325 11922 : Mutex* threadLock = XPCPerThreadData::GetLock();
326 11922 : if (threadLock)
327 : { // scoped lock
328 23844 : MutexAutoLock lock(*threadLock);
329 :
330 11922 : XPCPerThreadData* iterp = nsnull;
331 : XPCPerThreadData* thread;
332 :
333 35766 : while (nsnull != (thread =
334 : XPCPerThreadData::IterateThreads(&iterp))) {
335 : // Trace those AutoMarkingPtr lists!
336 11922 : thread->TraceJS(trc);
337 : }
338 : }
339 : }
340 :
341 : {
342 29456 : XPCAutoLock lock(self->mMapLock);
343 :
344 : // XPCJSObjectHolders don't participate in cycle collection, so always
345 : // trace them here.
346 : XPCRootSetElem *e;
347 14728 : for (e = self->mObjectHolderRoots; e; e = e->GetNextRoot())
348 0 : static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
349 : }
350 14728 : }
351 :
352 : // static
353 14728 : void XPCJSRuntime::TraceGrayJS(JSTracer* trc, void* data)
354 : {
355 14728 : XPCJSRuntime* self = (XPCJSRuntime*)data;
356 :
357 : // Mark these roots as gray so the CC can walk them later.
358 14728 : self->TraceXPConnectRoots(trc);
359 14728 : }
360 :
361 : static void
362 5847 : TraceJSObject(PRUint32 aLangID, void *aScriptThing, const char *name,
363 : void *aClosure)
364 : {
365 5847 : if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
366 5847 : JS_CALL_TRACER(static_cast<JSTracer*>(aClosure), aScriptThing,
367 : js_GetGCThingTraceKind(aScriptThing), name);
368 : }
369 5847 : }
370 :
371 : static JSDHashOperator
372 5220 : TraceJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
373 : void *arg)
374 : {
375 5220 : ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
376 :
377 5220 : entry->tracer->Trace(entry->holder, TraceJSObject, arg);
378 :
379 5220 : return JS_DHASH_NEXT;
380 : }
381 :
382 : struct ClearedGlobalObject : public JSDHashEntryHdr
383 : {
384 : JSContext* mContext;
385 : JSObject* mGlobalObject;
386 : };
387 :
388 : static PLDHashOperator
389 0 : TraceExpandos(XPCWrappedNative *wn, JSObject *&expando, void *aClosure)
390 : {
391 0 : if (wn->IsWrapperExpired())
392 0 : return PL_DHASH_REMOVE;
393 0 : JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando, "expando object");
394 0 : return PL_DHASH_NEXT;
395 : }
396 :
397 : static PLDHashOperator
398 0 : TraceDOMExpandos(nsPtrHashKey<JSObject> *expando, void *aClosure)
399 : {
400 0 : JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando->GetKey(),
401 : "DOM expando object");
402 0 : return PL_DHASH_NEXT;
403 : }
404 :
405 : static PLDHashOperator
406 27300 : TraceCompartment(xpc::PtrAndPrincipalHashKey *aKey, JSCompartment *compartment, void *aClosure)
407 : {
408 : xpc::CompartmentPrivate *priv =
409 27300 : static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
410 27300 : if (priv->expandoMap)
411 0 : priv->expandoMap->Enumerate(TraceExpandos, aClosure);
412 27300 : if (priv->domExpandoMap)
413 0 : priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, aClosure);
414 27300 : return PL_DHASH_NEXT;
415 : }
416 :
417 14728 : void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
418 : {
419 14728 : JSContext *iter = nsnull;
420 81212 : while (JSContext *acx = JS_ContextIterator(GetJSRuntime(), &iter)) {
421 33242 : JS_ASSERT(js::HasUnrootedGlobal(acx));
422 33242 : if (JSObject *global = JS_GetGlobalObject(acx))
423 26313 : JS_CALL_OBJECT_TRACER(trc, global, "XPC global object");
424 : }
425 :
426 29456 : XPCAutoLock lock(mMapLock);
427 :
428 14728 : XPCWrappedNativeScope::TraceJS(trc, this);
429 :
430 15279 : for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot())
431 551 : static_cast<XPCTraceableVariant*>(e)->TraceJS(trc);
432 :
433 166841 : for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot())
434 152113 : static_cast<nsXPCWrappedJS*>(e)->TraceJS(trc);
435 :
436 14728 : if (mJSHolders.ops)
437 14728 : JS_DHashTableEnumerate(&mJSHolders, TraceJSHolder, trc);
438 :
439 : // Trace compartments.
440 14728 : GetCompartmentMap().EnumerateRead(TraceCompartment, trc);
441 14728 : }
442 :
443 : struct Closure
444 : {
445 : bool cycleCollectionEnabled;
446 : nsCycleCollectionTraversalCallback *cb;
447 : };
448 :
449 : static void
450 648 : CheckParticipatesInCycleCollection(PRUint32 aLangID, void *aThing,
451 : const char *name, void *aClosure)
452 : {
453 648 : Closure *closure = static_cast<Closure*>(aClosure);
454 :
455 : closure->cycleCollectionEnabled =
456 : aLangID == nsIProgrammingLanguage::JAVASCRIPT &&
457 648 : AddToCCKind(js_GetGCThingTraceKind(aThing));
458 648 : }
459 :
460 : static JSDHashOperator
461 623 : NoteJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
462 : void *arg)
463 : {
464 623 : ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
465 623 : Closure *closure = static_cast<Closure*>(arg);
466 :
467 : entry->tracer->Trace(entry->holder, CheckParticipatesInCycleCollection,
468 623 : closure);
469 623 : if (!closure->cycleCollectionEnabled)
470 1 : return JS_DHASH_NEXT;
471 :
472 : closure->cb->NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, entry->holder,
473 622 : entry->tracer);
474 :
475 622 : return JS_DHASH_NEXT;
476 : }
477 :
478 : // static
479 : void
480 190 : XPCJSRuntime::SuspectWrappedNative(XPCWrappedNative *wrapper,
481 : nsCycleCollectionTraversalCallback &cb)
482 : {
483 190 : if (!wrapper->IsValid() || wrapper->IsWrapperExpired())
484 0 : return;
485 :
486 190 : NS_ASSERTION(NS_IsMainThread() || NS_IsCycleCollectorThread(),
487 : "Suspecting wrapped natives from non-CC thread");
488 :
489 : // Only record objects that might be part of a cycle as roots, unless
490 : // the callback wants all traces (a debug feature).
491 190 : JSObject* obj = wrapper->GetFlatJSObjectPreserveColor();
492 190 : if (xpc_IsGrayGCThing(obj) || cb.WantAllTraces())
493 : cb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, obj,
494 56 : nsXPConnect::GetXPConnect());
495 : }
496 :
497 : static PLDHashOperator
498 0 : SuspectExpandos(XPCWrappedNative *wrapper, JSObject *expando, void *arg)
499 : {
500 0 : Closure* closure = static_cast<Closure*>(arg);
501 0 : XPCJSRuntime::SuspectWrappedNative(wrapper, *closure->cb);
502 :
503 0 : return PL_DHASH_NEXT;
504 : }
505 :
506 : static PLDHashOperator
507 0 : SuspectDOMExpandos(nsPtrHashKey<JSObject> *expando, void *arg)
508 : {
509 0 : Closure *closure = static_cast<Closure*>(arg);
510 0 : closure->cb->NoteXPCOMRoot(static_cast<nsISupports*>(js::GetObjectPrivate(expando->GetKey())));
511 0 : return PL_DHASH_NEXT;
512 : }
513 :
514 : static PLDHashOperator
515 3828 : SuspectCompartment(xpc::PtrAndPrincipalHashKey *key, JSCompartment *compartment, void *arg)
516 : {
517 : xpc::CompartmentPrivate *priv =
518 3828 : static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
519 3828 : if (priv->expandoMap)
520 0 : priv->expandoMap->EnumerateRead(SuspectExpandos, arg);
521 3828 : if (priv->domExpandoMap)
522 0 : priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, arg);
523 3828 : return PL_DHASH_NEXT;
524 : }
525 :
526 : void
527 1910 : XPCJSRuntime::AddXPConnectRoots(nsCycleCollectionTraversalCallback &cb)
528 : {
529 : // For all JS objects that are held by native objects but aren't held
530 : // through rooting or locking, we need to add all the native objects that
531 : // hold them so that the JS objects are colored correctly in the cycle
532 : // collector. This includes JSContexts that don't have outstanding requests,
533 : // because their global object wasn't marked by the JS GC. All other JS
534 : // roots were marked by the JS GC and will be colored correctly in the cycle
535 : // collector.
536 :
537 1910 : JSContext *iter = nsnull, *acx;
538 9118 : while ((acx = JS_ContextIterator(GetJSRuntime(), &iter))) {
539 : cb.NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, acx,
540 5298 : nsXPConnect::JSContextParticipant());
541 : }
542 :
543 3820 : XPCAutoLock lock(mMapLock);
544 :
545 1910 : XPCWrappedNativeScope::SuspectAllWrappers(this, cb);
546 :
547 1910 : for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot()) {
548 0 : XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(e);
549 0 : if (nsCCUncollectableMarker::InGeneration(cb,
550 0 : v->CCGeneration())) {
551 0 : jsval val = v->GetJSValPreserveColor();
552 0 : if (val.isObject() && !xpc_IsGrayGCThing(&val.toObject()))
553 0 : continue;
554 : }
555 0 : cb.NoteXPCOMRoot(v);
556 : }
557 :
558 10294 : for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) {
559 8384 : nsXPCWrappedJS *wrappedJS = static_cast<nsXPCWrappedJS*>(e);
560 8384 : JSObject *obj = wrappedJS->GetJSObjectPreserveColor();
561 : // If traversing wrappedJS wouldn't release it, nor
562 : // cause any other objects to be added to the graph, no
563 : // need to add it to the graph at all.
564 15612 : if (nsCCUncollectableMarker::sGeneration &&
565 3782 : !cb.WantAllTraces() && (!obj || !xpc_IsGrayGCThing(obj)) &&
566 1192 : !wrappedJS->IsSubjectToFinalization() &&
567 1192 : wrappedJS->GetRootWrapper() == wrappedJS &&
568 1062 : !wrappedJS->IsAggregatedToNative()) {
569 1062 : continue;
570 : }
571 :
572 7322 : cb.NoteXPCOMRoot(static_cast<nsIXPConnectWrappedJS *>(wrappedJS));
573 : }
574 :
575 1910 : Closure closure = { true, &cb };
576 1910 : if (mJSHolders.ops) {
577 1910 : JS_DHashTableEnumerate(&mJSHolders, NoteJSHolder, &closure);
578 : }
579 :
580 : // Suspect wrapped natives with expando objects.
581 1910 : GetCompartmentMap().EnumerateRead(SuspectCompartment, &closure);
582 1910 : }
583 :
584 : static JSDHashOperator
585 0 : UnmarkJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
586 : void *arg)
587 : {
588 0 : ObjectHolder* entry = reinterpret_cast<ObjectHolder*>(hdr);
589 0 : entry->tracer->CanSkip(entry->holder, true);
590 0 : return JS_DHASH_NEXT;
591 : }
592 :
593 : void
594 0 : XPCJSRuntime::UnmarkSkippableJSHolders()
595 : {
596 0 : XPCAutoLock lock(mMapLock);
597 0 : if (mJSHolders.ops) {
598 0 : JS_DHashTableEnumerate(&mJSHolders, UnmarkJSHolder, nsnull);
599 : }
600 0 : }
601 :
602 : void
603 0 : xpc_UnmarkSkippableJSHolders()
604 : {
605 0 : if (nsXPConnect::GetXPConnect() &&
606 0 : nsXPConnect::GetXPConnect()->GetRuntime()) {
607 0 : nsXPConnect::GetXPConnect()->GetRuntime()->UnmarkSkippableJSHolders();
608 : }
609 0 : }
610 :
611 : template<class T> static void
612 2443424 : DoDeferredRelease(nsTArray<T> &array)
613 : {
614 2413968 : while (1) {
615 2443424 : PRUint32 count = array.Length();
616 2443424 : if (!count) {
617 29456 : array.Compact();
618 : break;
619 : }
620 2413968 : T wrapper = array[count-1];
621 2413968 : array.RemoveElementAt(count-1);
622 2413968 : NS_RELEASE(wrapper);
623 : }
624 29456 : }
625 :
626 : static JSDHashOperator
627 0 : SweepWaiverWrappers(JSDHashTable *table, JSDHashEntryHdr *hdr,
628 : uint32_t number, void *arg)
629 : {
630 0 : JSObject *key = ((JSObject2JSObjectMap::Entry *)hdr)->key;
631 0 : JSObject *value = ((JSObject2JSObjectMap::Entry *)hdr)->value;
632 :
633 0 : if (JS_IsAboutToBeFinalized(key) || JS_IsAboutToBeFinalized(value))
634 0 : return JS_DHASH_REMOVE;
635 0 : return JS_DHASH_NEXT;
636 : }
637 :
638 : static PLDHashOperator
639 0 : SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg)
640 : {
641 0 : return JS_IsAboutToBeFinalized(wn->GetFlatJSObjectPreserveColor())
642 : ? PL_DHASH_REMOVE
643 0 : : PL_DHASH_NEXT;
644 : }
645 :
646 : static PLDHashOperator
647 27300 : SweepCompartment(nsCStringHashKey& aKey, JSCompartment *compartment, void *aClosure)
648 : {
649 27300 : MOZ_ASSERT(!aClosure);
650 : xpc::CompartmentPrivate *priv =
651 27300 : static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
652 27300 : if (priv->waiverWrapperMap)
653 0 : priv->waiverWrapperMap->Enumerate(SweepWaiverWrappers, nsnull);
654 27300 : if (priv->expandoMap)
655 0 : priv->expandoMap->Enumerate(SweepExpandos, nsnull);
656 27300 : return PL_DHASH_NEXT;
657 : }
658 :
659 : /* static */ void
660 29456 : XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
661 : {
662 29456 : XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
663 29456 : if (!self)
664 0 : return;
665 :
666 29456 : switch (status) {
667 : case JSGC_BEGIN:
668 : {
669 : // We seem to sometime lose the unrooted global flag. Restore it
670 : // here. FIXME: bug 584495.
671 14728 : JSContext *iter = nsnull;
672 81212 : while (JSContext *acx = JS_ContextIterator(rt, &iter)) {
673 33242 : if (!js::HasUnrootedGlobal(acx))
674 0 : JS_ToggleOptions(acx, JSOPTION_UNROOTED_GLOBAL);
675 : }
676 14728 : break;
677 : }
678 : case JSGC_END:
679 : {
680 : // Do any deferred releases of native objects.
681 : #ifdef XPC_TRACK_DEFERRED_RELEASES
682 : printf("XPC - Begin deferred Release of %d nsISupports pointers\n",
683 : self->mNativesToReleaseArray.Length());
684 : #endif
685 14728 : DoDeferredRelease(self->mNativesToReleaseArray);
686 : #ifdef XPC_TRACK_DEFERRED_RELEASES
687 : printf("XPC - End deferred Releases\n");
688 : #endif
689 :
690 14728 : self->GetXPConnect()->ClearGCBeforeCC();
691 14728 : break;
692 : }
693 : }
694 :
695 58912 : nsTArray<JSGCCallback> callbacks(self->extraGCCallbacks);
696 29456 : for (PRUint32 i = 0; i < callbacks.Length(); ++i)
697 0 : callbacks[i](rt, status);
698 : }
699 :
700 : /* static */ void
701 29456 : XPCJSRuntime::FinalizeCallback(JSContext *cx, JSFinalizeStatus status)
702 : {
703 29456 : XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
704 29456 : if (!self)
705 0 : return;
706 :
707 29456 : switch (status) {
708 : case JSFINALIZE_START:
709 : {
710 14728 : NS_ASSERTION(!self->mDoingFinalization, "bad state");
711 :
712 : // mThreadRunningGC indicates that GC is running
713 : { // scoped lock
714 29456 : XPCAutoLock lock(self->GetMapLock());
715 14728 : NS_ASSERTION(!self->mThreadRunningGC, "bad state");
716 14728 : self->mThreadRunningGC = PR_GetCurrentThread();
717 : }
718 :
719 : nsTArray<nsXPCWrappedJS*>* dyingWrappedJSArray =
720 14728 : &self->mWrappedJSToReleaseArray;
721 :
722 : // Add any wrappers whose JSObjects are to be finalized to
723 : // this array. Note that we do not want to be changing the
724 : // refcount of these wrappers.
725 : // We add them to the array now and Release the array members
726 : // later to avoid the posibility of doing any JS GCThing
727 : // allocations during the gc cycle.
728 : self->mWrappedJSMap->
729 14728 : Enumerate(WrappedJSDyingJSObjectFinder, dyingWrappedJSArray);
730 :
731 : // Find dying scopes.
732 14728 : XPCWrappedNativeScope::FinishedMarkPhaseOfGC(cx, self);
733 :
734 : // Sweep compartments.
735 14728 : self->GetCompartmentMap().EnumerateRead((XPCCompartmentMap::EnumReadFunction)
736 29456 : SweepCompartment, nsnull);
737 :
738 14728 : self->mDoingFinalization = true;
739 14728 : break;
740 : }
741 : case JSFINALIZE_END:
742 : {
743 14728 : NS_ASSERTION(self->mDoingFinalization, "bad state");
744 14728 : self->mDoingFinalization = false;
745 :
746 : // Release all the members whose JSObjects are now known
747 : // to be dead.
748 14728 : DoDeferredRelease(self->mWrappedJSToReleaseArray);
749 :
750 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
751 : printf("--------------------------------------------------------------\n");
752 : int setsBefore = (int) self->mNativeSetMap->Count();
753 : int ifacesBefore = (int) self->mIID2NativeInterfaceMap->Count();
754 : #endif
755 :
756 : // We use this occasion to mark and sweep NativeInterfaces,
757 : // NativeSets, and the WrappedNativeJSClasses...
758 :
759 : // Do the marking...
760 14728 : XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos();
761 :
762 : self->mDetachedWrappedNativeProtoMap->
763 14728 : Enumerate(DetachedWrappedNativeProtoMarker, nsnull);
764 :
765 14728 : DOM_MarkInterfaces();
766 :
767 : // Mark the sets used in the call contexts. There is a small
768 : // chance that a wrapper's set will change *while* a call is
769 : // happening which uses that wrapper's old interfface set. So,
770 : // we need to do this marking to avoid collecting those sets
771 : // that might no longer be otherwise reachable from the wrappers
772 : // or the wrapperprotos.
773 :
774 : // Skip this part if XPConnect is shutting down. We get into
775 : // bad locking problems with the thread iteration otherwise.
776 14728 : if (!self->GetXPConnect()->IsShuttingDown()) {
777 11922 : Mutex* threadLock = XPCPerThreadData::GetLock();
778 11922 : if (threadLock)
779 : { // scoped lock
780 23844 : MutexAutoLock lock(*threadLock);
781 :
782 11922 : XPCPerThreadData* iterp = nsnull;
783 : XPCPerThreadData* thread;
784 :
785 35766 : while (nsnull != (thread =
786 : XPCPerThreadData::IterateThreads(&iterp))) {
787 : // Mark those AutoMarkingPtr lists!
788 11922 : thread->MarkAutoRootsAfterJSFinalize();
789 :
790 11922 : XPCCallContext* ccxp = thread->GetCallContext();
791 33630 : while (ccxp) {
792 : // Deal with the strictness of callcontext that
793 : // complains if you ask for a set when
794 : // it is in a state where the set could not
795 : // possibly be valid.
796 9786 : if (ccxp->CanGetSet()) {
797 3887 : XPCNativeSet* set = ccxp->GetSet();
798 3887 : if (set)
799 3887 : set->Mark();
800 : }
801 9786 : if (ccxp->CanGetInterface()) {
802 3887 : XPCNativeInterface* iface = ccxp->GetInterface();
803 3887 : if (iface)
804 3887 : iface->Mark();
805 : }
806 9786 : ccxp = ccxp->GetPrevCallContext();
807 : }
808 : }
809 : }
810 : }
811 :
812 : // Do the sweeping...
813 :
814 : // We don't want to sweep the JSClasses at shutdown time.
815 : // At this point there may be JSObjects using them that have
816 : // been removed from the other maps.
817 14728 : if (!self->GetXPConnect()->IsShuttingDown()) {
818 : self->mNativeScriptableSharedMap->
819 11922 : Enumerate(JSClassSweeper, nsnull);
820 : }
821 :
822 : self->mClassInfo2NativeSetMap->
823 14728 : Enumerate(NativeUnMarkedSetRemover, nsnull);
824 :
825 : self->mNativeSetMap->
826 14728 : Enumerate(NativeSetSweeper, nsnull);
827 :
828 : self->mIID2NativeInterfaceMap->
829 14728 : Enumerate(NativeInterfaceSweeper, nsnull);
830 :
831 : #ifdef DEBUG
832 14728 : XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked();
833 : #endif
834 :
835 : #ifdef XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING
836 : int setsAfter = (int) self->mNativeSetMap->Count();
837 : int ifacesAfter = (int) self->mIID2NativeInterfaceMap->Count();
838 :
839 : printf("\n");
840 : printf("XPCNativeSets: before: %d collected: %d remaining: %d\n",
841 : setsBefore, setsBefore - setsAfter, setsAfter);
842 : printf("XPCNativeInterfaces: before: %d collected: %d remaining: %d\n",
843 : ifacesBefore, ifacesBefore - ifacesAfter, ifacesAfter);
844 : printf("--------------------------------------------------------------\n");
845 : #endif
846 :
847 : // Sweep scopes needing cleanup
848 14728 : XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC(cx);
849 :
850 : // Now we are going to recycle any unused WrappedNativeTearoffs.
851 : // We do this by iterating all the live callcontexts (on all
852 : // threads!) and marking the tearoffs in use. And then we
853 : // iterate over all the WrappedNative wrappers and sweep their
854 : // tearoffs.
855 : //
856 : // This allows us to perhaps minimize the growth of the
857 : // tearoffs. And also makes us not hold references to interfaces
858 : // on our wrapped natives that we are not actually using.
859 : //
860 : // XXX We may decide to not do this on *every* gc cycle.
861 :
862 : // Skip this part if XPConnect is shutting down. We get into
863 : // bad locking problems with the thread iteration otherwise.
864 14728 : if (!self->GetXPConnect()->IsShuttingDown()) {
865 11922 : Mutex* threadLock = XPCPerThreadData::GetLock();
866 11922 : if (threadLock) {
867 : // Do the marking...
868 :
869 : { // scoped lock
870 23844 : MutexAutoLock lock(*threadLock);
871 :
872 11922 : XPCPerThreadData* iterp = nsnull;
873 : XPCPerThreadData* thread;
874 :
875 35766 : while (nsnull != (thread =
876 : XPCPerThreadData::IterateThreads(&iterp))) {
877 11922 : XPCCallContext* ccxp = thread->GetCallContext();
878 33630 : while (ccxp) {
879 : // Deal with the strictness of callcontext that
880 : // complains if you ask for a tearoff when
881 : // it is in a state where the tearoff could not
882 : // possibly be valid.
883 9786 : if (ccxp->CanGetTearOff()) {
884 : XPCWrappedNativeTearOff* to =
885 3975 : ccxp->GetTearOff();
886 3975 : if (to)
887 3877 : to->Mark();
888 : }
889 9786 : ccxp = ccxp->GetPrevCallContext();
890 : }
891 : }
892 : }
893 :
894 : // Do the sweeping...
895 11922 : XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs();
896 : }
897 : }
898 :
899 : // Now we need to kill the 'Dying' XPCWrappedNativeProtos.
900 : // We transfered these native objects to this table when their
901 : // JSObject's were finalized. We did not destroy them immediately
902 : // at that point because the ordering of JS finalization is not
903 : // deterministic and we did not yet know if any wrappers that
904 : // might still be referencing the protos where still yet to be
905 : // finalized and destroyed. We *do* know that the protos'
906 : // JSObjects would not have been finalized if there were any
907 : // wrappers that referenced the proto but where not themselves
908 : // slated for finalization in this gc cycle. So... at this point
909 : // we know that any and all wrappers that might have been
910 : // referencing the protos in the dying list are themselves dead.
911 : // So, we can safely delete all the protos in the list.
912 :
913 : self->mDyingWrappedNativeProtoMap->
914 14728 : Enumerate(DyingProtoKiller, nsnull);
915 :
916 :
917 : // mThreadRunningGC indicates that GC is running.
918 : // Clear it and notify waiters.
919 : { // scoped lock
920 29456 : XPCAutoLock lock(self->GetMapLock());
921 14728 : NS_ASSERTION(self->mThreadRunningGC == PR_GetCurrentThread(), "bad state");
922 14728 : self->mThreadRunningGC = nsnull;
923 14728 : xpc_NotifyAll(self->GetMapLock());
924 : }
925 :
926 14728 : break;
927 : }
928 : }
929 : }
930 :
931 : class AutoLockWatchdog {
932 : XPCJSRuntime* const mRuntime;
933 :
934 : public:
935 778895 : AutoLockWatchdog(XPCJSRuntime* aRuntime)
936 778895 : : mRuntime(aRuntime) {
937 778895 : PR_Lock(mRuntime->mWatchdogLock);
938 778895 : }
939 :
940 778894 : ~AutoLockWatchdog() {
941 778894 : PR_Unlock(mRuntime->mWatchdogLock);
942 778894 : }
943 : };
944 :
945 : //static
946 : void
947 1404 : XPCJSRuntime::WatchdogMain(void *arg)
948 : {
949 1404 : XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
950 :
951 : // Lock lasts until we return
952 2807 : AutoLockWatchdog lock(self);
953 :
954 : PRIntervalTime sleepInterval;
955 6147 : while (self->mWatchdogThread) {
956 : // Sleep only 1 second if recently (or currently) active; otherwise, hibernate
957 3340 : if (self->mLastActiveTime == -1 || PR_Now() - self->mLastActiveTime <= PRTime(2*PR_USEC_PER_SEC))
958 3339 : sleepInterval = PR_TicksPerSecond();
959 : else {
960 1 : sleepInterval = PR_INTERVAL_NO_TIMEOUT;
961 1 : self->mWatchdogHibernating = true;
962 : }
963 3340 : MOZ_ALWAYS_TRUE(PR_WaitCondVar(self->mWatchdogWakeup, sleepInterval) == PR_SUCCESS);
964 3339 : JS_TriggerOperationCallback(self->mJSRuntime);
965 : }
966 :
967 : /* Wake up the main thread waiting for the watchdog to terminate. */
968 1403 : PR_NotifyCondVar(self->mWatchdogWakeup);
969 1403 : }
970 :
971 : //static
972 : void
973 774684 : XPCJSRuntime::ActivityCallback(void *arg, JSBool active)
974 : {
975 774684 : XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
976 :
977 1549368 : AutoLockWatchdog lock(self);
978 :
979 774684 : if (active) {
980 387342 : self->mLastActiveTime = -1;
981 387342 : if (self->mWatchdogHibernating) {
982 1 : self->mWatchdogHibernating = false;
983 1 : PR_NotifyCondVar(self->mWatchdogWakeup);
984 : }
985 : } else {
986 387342 : self->mLastActiveTime = PR_Now();
987 : }
988 774684 : }
989 :
990 : size_t
991 3 : XPCJSRuntime::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
992 : {
993 3 : size_t n = 0;
994 3 : n += mallocSizeOf(this);
995 3 : n += mWrappedJSMap->SizeOfIncludingThis(mallocSizeOf);
996 3 : n += mIID2NativeInterfaceMap->SizeOfIncludingThis(mallocSizeOf);
997 3 : n += mClassInfo2NativeSetMap->ShallowSizeOfIncludingThis(mallocSizeOf);
998 3 : n += mNativeSetMap->SizeOfIncludingThis(mallocSizeOf);
999 :
1000 : // NULL for the second arg; we're not measuring anything hanging off the
1001 : // entries in mJSHolders.
1002 3 : n += JS_DHashTableSizeOfExcludingThis(&mJSHolders, NULL, mallocSizeOf);
1003 :
1004 : // There are other XPCJSRuntime members that could be measured; the above
1005 : // ones have been seen by DMD to be worth measuring. More stuff may be
1006 : // added later.
1007 :
1008 3 : return n;
1009 : }
1010 :
1011 : /***************************************************************************/
1012 :
1013 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
1014 : static JSDHashOperator
1015 : DEBUG_WrapperChecker(JSDHashTable *table, JSDHashEntryHdr *hdr,
1016 : uint32_t number, void *arg)
1017 : {
1018 : XPCWrappedNative* wrapper = (XPCWrappedNative*)((JSDHashEntryStub*)hdr)->key;
1019 : NS_ASSERTION(!wrapper->IsValid(), "found a 'valid' wrapper!");
1020 : ++ *((int*)arg);
1021 : return JS_DHASH_NEXT;
1022 : }
1023 : #endif
1024 :
1025 : static JSDHashOperator
1026 275 : WrappedJSShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
1027 : uint32_t number, void *arg)
1028 : {
1029 275 : JSRuntime* rt = (JSRuntime*) arg;
1030 275 : nsXPCWrappedJS* wrapper = ((JSObject2WrappedJSMap::Entry*)hdr)->value;
1031 275 : NS_ASSERTION(wrapper, "found a null JS wrapper!");
1032 275 : NS_ASSERTION(wrapper->IsValid(), "found an invalid JS wrapper!");
1033 275 : wrapper->SystemIsBeingShutDown(rt);
1034 275 : return JS_DHASH_NEXT;
1035 : }
1036 :
1037 : static JSDHashOperator
1038 0 : DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
1039 : uint32_t number, void *arg)
1040 : {
1041 : XPCWrappedNativeProto* proto =
1042 0 : (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
1043 :
1044 0 : proto->SystemIsBeingShutDown();
1045 0 : return JS_DHASH_NEXT;
1046 : }
1047 :
1048 1403 : void XPCJSRuntime::SystemIsBeingShutDown()
1049 : {
1050 1403 : DOM_ClearInterfaces();
1051 :
1052 1403 : if (mDetachedWrappedNativeProtoMap)
1053 : mDetachedWrappedNativeProtoMap->
1054 1403 : Enumerate(DetachedWrappedNativeProtoShutdownMarker, nsnull);
1055 1403 : }
1056 :
1057 : JSContext *
1058 1910 : XPCJSRuntime::GetJSCycleCollectionContext()
1059 : {
1060 1910 : if (!mJSCycleCollectionContext) {
1061 1404 : mJSCycleCollectionContext = JS_NewContext(mJSRuntime, 0);
1062 1404 : if (!mJSCycleCollectionContext)
1063 0 : return nsnull;
1064 : }
1065 1910 : return mJSCycleCollectionContext;
1066 : }
1067 :
1068 2806 : XPCJSRuntime::~XPCJSRuntime()
1069 : {
1070 1403 : if (mWatchdogWakeup) {
1071 : // If the watchdog thread is running, tell it to terminate waking it
1072 : // up if necessary and wait until it signals that it finished. As we
1073 : // must release the lock before calling PR_DestroyCondVar, we use an
1074 : // extra block here.
1075 : {
1076 2806 : AutoLockWatchdog lock(this);
1077 1403 : if (mWatchdogThread) {
1078 1403 : mWatchdogThread = nsnull;
1079 1403 : PR_NotifyCondVar(mWatchdogWakeup);
1080 1403 : PR_WaitCondVar(mWatchdogWakeup, PR_INTERVAL_NO_TIMEOUT);
1081 : }
1082 : }
1083 1403 : PR_DestroyCondVar(mWatchdogWakeup);
1084 1403 : PR_DestroyLock(mWatchdogLock);
1085 1403 : mWatchdogWakeup = nsnull;
1086 : }
1087 :
1088 1403 : if (mJSCycleCollectionContext)
1089 1403 : JS_DestroyContextNoGC(mJSCycleCollectionContext);
1090 :
1091 : #ifdef XPC_DUMP_AT_SHUTDOWN
1092 : {
1093 : // count the total JSContexts in use
1094 : JSContext* iter = nsnull;
1095 : int count = 0;
1096 : while (JS_ContextIterator(mJSRuntime, &iter))
1097 : count ++;
1098 : if (count)
1099 : printf("deleting XPCJSRuntime with %d live JSContexts\n", count);
1100 : }
1101 : #endif
1102 :
1103 : // clean up and destroy maps...
1104 1403 : if (mWrappedJSMap) {
1105 : #ifdef XPC_DUMP_AT_SHUTDOWN
1106 : uint32_t count = mWrappedJSMap->Count();
1107 : if (count)
1108 : printf("deleting XPCJSRuntime with %d live wrapped JSObject\n", (int)count);
1109 : #endif
1110 1403 : mWrappedJSMap->Enumerate(WrappedJSShutdownMarker, mJSRuntime);
1111 1403 : delete mWrappedJSMap;
1112 : }
1113 :
1114 1403 : if (mWrappedJSClassMap) {
1115 : #ifdef XPC_DUMP_AT_SHUTDOWN
1116 : uint32_t count = mWrappedJSClassMap->Count();
1117 : if (count)
1118 : printf("deleting XPCJSRuntime with %d live nsXPCWrappedJSClass\n", (int)count);
1119 : #endif
1120 1403 : delete mWrappedJSClassMap;
1121 : }
1122 :
1123 1403 : if (mIID2NativeInterfaceMap) {
1124 : #ifdef XPC_DUMP_AT_SHUTDOWN
1125 : uint32_t count = mIID2NativeInterfaceMap->Count();
1126 : if (count)
1127 : printf("deleting XPCJSRuntime with %d live XPCNativeInterfaces\n", (int)count);
1128 : #endif
1129 1403 : delete mIID2NativeInterfaceMap;
1130 : }
1131 :
1132 1403 : if (mClassInfo2NativeSetMap) {
1133 : #ifdef XPC_DUMP_AT_SHUTDOWN
1134 : uint32_t count = mClassInfo2NativeSetMap->Count();
1135 : if (count)
1136 : printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count);
1137 : #endif
1138 1403 : delete mClassInfo2NativeSetMap;
1139 : }
1140 :
1141 1403 : if (mNativeSetMap) {
1142 : #ifdef XPC_DUMP_AT_SHUTDOWN
1143 : uint32_t count = mNativeSetMap->Count();
1144 : if (count)
1145 : printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count);
1146 : #endif
1147 1403 : delete mNativeSetMap;
1148 : }
1149 :
1150 1403 : if (mMapLock)
1151 1403 : XPCAutoLock::DestroyLock(mMapLock);
1152 :
1153 1403 : if (mThisTranslatorMap) {
1154 : #ifdef XPC_DUMP_AT_SHUTDOWN
1155 : uint32_t count = mThisTranslatorMap->Count();
1156 : if (count)
1157 : printf("deleting XPCJSRuntime with %d live ThisTranslator\n", (int)count);
1158 : #endif
1159 1403 : delete mThisTranslatorMap;
1160 : }
1161 :
1162 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
1163 : if (DEBUG_WrappedNativeHashtable) {
1164 : int LiveWrapperCount = 0;
1165 : JS_DHashTableEnumerate(DEBUG_WrappedNativeHashtable,
1166 : DEBUG_WrapperChecker, &LiveWrapperCount);
1167 : if (LiveWrapperCount)
1168 : printf("deleting XPCJSRuntime with %d live XPCWrappedNative (found in wrapper check)\n", (int)LiveWrapperCount);
1169 : JS_DHashTableDestroy(DEBUG_WrappedNativeHashtable);
1170 : }
1171 : #endif
1172 :
1173 1403 : if (mNativeScriptableSharedMap) {
1174 : #ifdef XPC_DUMP_AT_SHUTDOWN
1175 : uint32_t count = mNativeScriptableSharedMap->Count();
1176 : if (count)
1177 : printf("deleting XPCJSRuntime with %d live XPCNativeScriptableShared\n", (int)count);
1178 : #endif
1179 1403 : delete mNativeScriptableSharedMap;
1180 : }
1181 :
1182 1403 : if (mDyingWrappedNativeProtoMap) {
1183 : #ifdef XPC_DUMP_AT_SHUTDOWN
1184 : uint32_t count = mDyingWrappedNativeProtoMap->Count();
1185 : if (count)
1186 : printf("deleting XPCJSRuntime with %d live but dying XPCWrappedNativeProto\n", (int)count);
1187 : #endif
1188 1403 : delete mDyingWrappedNativeProtoMap;
1189 : }
1190 :
1191 1403 : if (mDetachedWrappedNativeProtoMap) {
1192 : #ifdef XPC_DUMP_AT_SHUTDOWN
1193 : uint32_t count = mDetachedWrappedNativeProtoMap->Count();
1194 : if (count)
1195 : printf("deleting XPCJSRuntime with %d live detached XPCWrappedNativeProto\n", (int)count);
1196 : #endif
1197 1403 : delete mDetachedWrappedNativeProtoMap;
1198 : }
1199 :
1200 1403 : if (mExplicitNativeWrapperMap) {
1201 : #ifdef XPC_DUMP_AT_SHUTDOWN
1202 : uint32_t count = mExplicitNativeWrapperMap->Count();
1203 : if (count)
1204 : printf("deleting XPCJSRuntime with %d live explicit XPCNativeWrapper\n", (int)count);
1205 : #endif
1206 1403 : delete mExplicitNativeWrapperMap;
1207 : }
1208 :
1209 1403 : if (mJSHolders.ops) {
1210 1403 : JS_DHashTableFinish(&mJSHolders);
1211 1403 : mJSHolders.ops = nsnull;
1212 : }
1213 :
1214 1403 : if (mJSRuntime) {
1215 1403 : JS_DestroyRuntime(mJSRuntime);
1216 1403 : JS_ShutDown();
1217 : #ifdef DEBUG_shaver_off
1218 : fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
1219 : #endif
1220 : }
1221 :
1222 1403 : XPCPerThreadData::ShutDown();
1223 1403 : }
1224 :
1225 : static void
1226 18 : GetCompartmentName(JSCompartment *c, bool getAddress, nsCString &name)
1227 : {
1228 18 : if (js::IsAtomsCompartment(c)) {
1229 6 : name.AssignLiteral("atoms");
1230 12 : } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
1231 12 : nsJSPrincipals::get(principals)->GetScriptLocation(name);
1232 :
1233 : // For system compartments we append the location, if there is one.
1234 : // And we append the address if |getAddress| is true, so that
1235 : // multiple system compartments (and there can be many) can be
1236 : // distinguished.
1237 12 : if (js::IsSystemCompartment(c)) {
1238 : xpc::CompartmentPrivate *compartmentPrivate =
1239 6 : static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(c));
1240 6 : if (compartmentPrivate && !compartmentPrivate->location.IsEmpty()) {
1241 0 : name.AppendLiteral(", ");
1242 0 : name.Append(compartmentPrivate->location);
1243 : }
1244 :
1245 6 : if (getAddress) {
1246 : // ample; 64-bit address max is 18 chars
1247 3 : const int maxLength = 31;
1248 6 : nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
1249 3 : name.Append(address);
1250 : }
1251 : }
1252 :
1253 : // A hack: replace forward slashes with '\\' so they aren't
1254 : // treated as path separators. Users of the reporters
1255 : // (such as about:memory) have to undo this change.
1256 12 : name.ReplaceChar('/', '\\');
1257 : } else {
1258 0 : name.AssignLiteral("null-principal");
1259 : }
1260 18 : }
1261 :
1262 : // We have per-compartment GC heap totals, so we can't put the total GC heap
1263 : // size in the explicit allocations tree. But it's a useful figure, so put it
1264 : // in the "others" list.
1265 :
1266 : static PRInt64
1267 3 : GetGCChunkTotalBytes()
1268 : {
1269 3 : JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
1270 3 : return PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * js::gc::ChunkSize;
1271 : }
1272 :
1273 1422 : NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
1274 : "js-gc-heap",
1275 : KIND_OTHER,
1276 : nsIMemoryReporter::UNITS_BYTES,
1277 : GetGCChunkTotalBytes,
1278 4278 : "Memory used by the garbage-collected JavaScript heap.")
1279 :
1280 : static PRInt64
1281 3 : GetJSSystemCompartmentCount()
1282 : {
1283 3 : return JS::SystemCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
1284 : }
1285 :
1286 : static PRInt64
1287 3 : GetJSUserCompartmentCount()
1288 : {
1289 3 : return JS::UserCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
1290 : }
1291 :
1292 : // Nb: js-system-compartment-count + js-user-compartment-count could be
1293 : // different to the number of compartments reported by
1294 : // JSMemoryMultiReporter if a garbage collection occurred
1295 : // between them being consulted. We could move these reporters into
1296 : // XPConnectJSCompartmentCount to avoid that problem, but then we couldn't
1297 : // easily report them via telemetry, so we live with the small risk of
1298 : // inconsistencies.
1299 1425 : NS_MEMORY_REPORTER_IMPLEMENT(
1300 : XPConnectJSSystemCompartmentCount,
1301 : "js-compartments-system",
1302 : KIND_OTHER,
1303 : nsIMemoryReporter::UNITS_COUNT,
1304 : GetJSSystemCompartmentCount,
1305 : "The number of JavaScript compartments for system code. The sum of this "
1306 : "and 'js-compartments-user' might not match the number of compartments "
1307 : "listed under 'js' if a garbage collection occurs at an inopportune time, "
1308 4278 : "but such cases should be rare.")
1309 :
1310 1425 : NS_MEMORY_REPORTER_IMPLEMENT(
1311 : XPConnectJSUserCompartmentCount,
1312 : "js-compartments-user",
1313 : KIND_OTHER,
1314 : nsIMemoryReporter::UNITS_COUNT,
1315 : GetJSUserCompartmentCount,
1316 : "The number of JavaScript compartments for user code. The sum of this "
1317 : "and 'js-compartments-system' might not match the number of compartments "
1318 : "listed under 'js' if a garbage collection occurs at an inopportune time, "
1319 4278 : "but such cases should be rare.")
1320 :
1321 : // The REPORT* macros do an unconditional report. The REPORT*0 macros only
1322 : // report if the value is non-zero.
1323 :
1324 : #define REPORT(_path, _kind, _units, _amount, _desc) \
1325 : do { \
1326 : nsresult rv; \
1327 : rv = cb->Callback(EmptyCString(), _path, _kind, _units, _amount, \
1328 : NS_LITERAL_CSTRING(_desc), closure); \
1329 : NS_ENSURE_SUCCESS(rv, rv); \
1330 : } while (0)
1331 :
1332 : #define REPORT0(_path, _kind, _units, _amount, _desc) \
1333 : do { \
1334 : size_t amount = _amount; /* evaluate _amount only once */ \
1335 : if (amount > 0) { \
1336 : nsresult rv; \
1337 : rv = cb->Callback(EmptyCString(), _path, _kind, _units, amount, \
1338 : NS_LITERAL_CSTRING(_desc), closure); \
1339 : NS_ENSURE_SUCCESS(rv, rv); \
1340 : } \
1341 : } while (0)
1342 :
1343 : #define REPORT_BYTES(_path, _kind, _amount, _desc) \
1344 : REPORT(_path, _kind, nsIMemoryReporter::UNITS_BYTES, _amount, _desc);
1345 :
1346 : #define REPORT_BYTES0(_path, _kind, _amount, _desc) \
1347 : REPORT0(_path, _kind, nsIMemoryReporter::UNITS_BYTES, _amount, _desc);
1348 :
1349 : #define REPORT_GC_BYTES(_path, _amount, _desc) \
1350 : do { \
1351 : size_t amount = _amount; /* evaluate _amount only once */ \
1352 : nsresult rv; \
1353 : rv = cb->Callback(EmptyCString(), _path, \
1354 : nsIMemoryReporter::KIND_NONHEAP, \
1355 : nsIMemoryReporter::UNITS_BYTES, amount, \
1356 : NS_LITERAL_CSTRING(_desc), closure); \
1357 : NS_ENSURE_SUCCESS(rv, rv); \
1358 : gcTotal += amount; \
1359 : } while (0)
1360 :
1361 : #define REPORT_GC_BYTES0(_path, _amount, _desc) \
1362 : do { \
1363 : size_t amount = _amount; /* evaluate _amount only once */ \
1364 : if (amount > 0) { \
1365 : nsresult rv; \
1366 : rv = cb->Callback(EmptyCString(), _path, \
1367 : nsIMemoryReporter::KIND_NONHEAP, \
1368 : nsIMemoryReporter::UNITS_BYTES, amount, \
1369 : NS_LITERAL_CSTRING(_desc), closure); \
1370 : NS_ENSURE_SUCCESS(rv, rv); \
1371 : gcTotal += amount; \
1372 : } \
1373 : } while (0)
1374 :
1375 : template <int N>
1376 : inline const nsCString
1377 135 : MakePath(const nsACString &pathPrefix, const JS::CompartmentStats &cStats,
1378 : const char (&reporterName)[N])
1379 : {
1380 135 : const char *name = static_cast<char *>(cStats.extra);
1381 135 : if (!name)
1382 0 : name = "error while initializing compartment name";
1383 : return pathPrefix + NS_LITERAL_CSTRING("compartment(") +
1384 : nsDependentCString(name) + NS_LITERAL_CSTRING(")/") +
1385 135 : nsDependentCString(reporterName);
1386 : }
1387 :
1388 : namespace mozilla {
1389 : namespace xpconnect {
1390 : namespace memory {
1391 :
1392 : static nsresult
1393 9 : ReportCompartmentStats(const JS::CompartmentStats &cStats,
1394 : const nsACString &pathPrefix,
1395 : nsIMemoryMultiReporterCallback *cb,
1396 : nsISupports *closure, size_t *gcTotalOut)
1397 : {
1398 9 : size_t gcTotal = 0;
1399 :
1400 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/arena/headers"),
1401 : cStats.gcHeapArenaHeaders,
1402 : "Memory on the compartment's garbage-collected JavaScript "
1403 : "heap, within arenas, that is used to hold internal "
1404 : "book-keeping information.");
1405 :
1406 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/arena/padding"),
1407 : cStats.gcHeapArenaPadding,
1408 : "Memory on the compartment's garbage-collected JavaScript "
1409 : "heap, within arenas, that is unused and present only so "
1410 : "that other data is aligned. This constitutes internal "
1411 : "fragmentation.");
1412 :
1413 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/arena/unused"),
1414 : cStats.gcHeapArenaUnused,
1415 : "Memory on the compartment's garbage-collected JavaScript "
1416 : "heap, within arenas, that could be holding useful data "
1417 : "but currently isn't.");
1418 :
1419 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/objects/non-function"),
1420 : cStats.gcHeapObjectsNonFunction,
1421 : "Memory on the compartment's garbage-collected JavaScript "
1422 : "heap that holds non-function objects.");
1423 :
1424 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/objects/function"),
1425 : cStats.gcHeapObjectsFunction,
1426 : "Memory on the compartment's garbage-collected JavaScript "
1427 : "heap that holds function objects.");
1428 :
1429 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/strings"),
1430 : cStats.gcHeapStrings,
1431 : "Memory on the compartment's garbage-collected JavaScript "
1432 : "heap that holds string headers. String headers contain "
1433 : "various pieces of information about a string, but do not "
1434 : "contain (except in the case of very short strings) the "
1435 : "string characters; characters in longer strings are "
1436 : "counted " "under 'gc-heap/string-chars' instead.");
1437 :
1438 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/scripts"),
1439 : cStats.gcHeapScripts,
1440 : "Memory on the compartment's garbage-collected JavaScript "
1441 : "heap that holds JSScript instances. A JSScript is "
1442 : "created for each user-defined function in a script. One "
1443 : "is also created for the top-level code in a script.");
1444 :
1445 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/shapes/tree"),
1446 : cStats.gcHeapShapesTree,
1447 : "Memory on the compartment's garbage-collected JavaScript "
1448 : "heap that holds shapes that are in a property tree.");
1449 :
1450 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/shapes/dict"),
1451 : cStats.gcHeapShapesDict,
1452 : "Memory on the compartment's garbage-collected JavaScript "
1453 : "heap that holds shapes that are in dictionary mode.");
1454 :
1455 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/shapes/base"),
1456 : cStats.gcHeapShapesBase,
1457 : "Memory on the compartment's garbage-collected JavaScript "
1458 : "heap that collates data common to many shapes.");
1459 :
1460 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/type-objects"),
1461 : cStats.gcHeapTypeObjects,
1462 : "Memory on the compartment's garbage-collected JavaScript "
1463 : "heap that holds type inference information.");
1464 :
1465 9 : REPORT_GC_BYTES0(MakePath(pathPrefix, cStats, "gc-heap/xml"),
1466 : cStats.gcHeapXML,
1467 : "Memory on the compartment's garbage-collected JavaScript "
1468 : "heap that holds E4X XML objects.");
1469 :
1470 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "objects/slots"),
1471 : nsIMemoryReporter::KIND_HEAP, cStats.objectSlots,
1472 : "Memory allocated for the compartment's non-fixed object "
1473 : "slot arrays, which are used to represent object properties. "
1474 : "Some objects also contain a fixed number of slots which are "
1475 : "stored on the compartment's JavaScript heap; those slots "
1476 : "are not counted here, but in 'gc-heap/objects' instead.");
1477 :
1478 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "objects/elements"),
1479 : nsIMemoryReporter::KIND_HEAP, cStats.objectElements,
1480 : "Memory allocated for the compartment's object element "
1481 : "arrays, which are used to represent indexed object "
1482 : "properties.");
1483 :
1484 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "objects/misc"),
1485 : nsIMemoryReporter::KIND_HEAP, cStats.objectMisc,
1486 : "Memory allocated for various small, miscellaneous "
1487 : "structures that hang off certain kinds of objects.");
1488 :
1489 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "string-chars"),
1490 : nsIMemoryReporter::KIND_HEAP, cStats.stringChars,
1491 : "Memory allocated to hold the compartment's string "
1492 : "characters. Sometimes more memory is allocated than "
1493 : "necessary, to simplify string concatenation. Each string "
1494 : "also includes a header which is stored on the "
1495 : "compartment's JavaScript heap; that header is not counted "
1496 : "here, but in 'gc-heap/strings' instead.");
1497 :
1498 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/tree-tables"),
1499 : nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeTables,
1500 : "Memory allocated for the compartment's property tables "
1501 : "that belong to shapes that are in a property tree.");
1502 :
1503 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/dict-tables"),
1504 : nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraDictTables,
1505 : "Memory allocated for the compartment's property tables "
1506 : "that belong to shapes that are in dictionary mode.");
1507 :
1508 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/tree-shape-kids"),
1509 : nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeShapeKids,
1510 : "Memory allocated for the compartment's kid hashes that "
1511 : "belong to shapes that are in a property tree.");
1512 :
1513 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "shapes-extra/compartment-tables"),
1514 : nsIMemoryReporter::KIND_HEAP, cStats.shapesCompartmentTables,
1515 : "Memory used by compartment wide tables storing shape "
1516 : "information for use during object construction.");
1517 :
1518 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "script-data"),
1519 : nsIMemoryReporter::KIND_HEAP, cStats.scriptData,
1520 : "Memory allocated for JSScript bytecode and various "
1521 : "variable-length tables.");
1522 :
1523 : #ifdef JS_METHODJIT
1524 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "mjit/code"),
1525 : nsIMemoryReporter::KIND_NONHEAP, cStats.mjitCode,
1526 : "Memory used by the method JIT to hold the compartment's "
1527 : "generated code.");
1528 :
1529 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "mjit/data"),
1530 : nsIMemoryReporter::KIND_HEAP, cStats.mjitData,
1531 : "Memory used by the method JIT for the compartment's "
1532 : "compilation data: JITScripts, native maps, and inline "
1533 : "cache structs.");
1534 : #endif
1535 :
1536 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "type-inference/script-main"),
1537 : nsIMemoryReporter::KIND_HEAP,
1538 : cStats.typeInferenceSizes.scripts,
1539 : "Memory used during type inference to store type sets of "
1540 : "variables and dynamically observed types.");
1541 :
1542 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "type-inference/object-main"),
1543 : nsIMemoryReporter::KIND_HEAP,
1544 : cStats.typeInferenceSizes.objects,
1545 : "Memory used during type inference to store types and "
1546 : "possible property types of JS objects.");
1547 :
1548 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "type-inference/tables"),
1549 : nsIMemoryReporter::KIND_HEAP,
1550 : cStats.typeInferenceSizes.tables,
1551 : "Memory used during type inference for compartment-wide "
1552 : "tables.");
1553 :
1554 9 : REPORT_BYTES0(MakePath(pathPrefix, cStats, "analysis-temporary"),
1555 : nsIMemoryReporter::KIND_HEAP,
1556 : cStats.typeInferenceSizes.temporary,
1557 : "Memory used during type inference and compilation to hold "
1558 : "transient analysis information. Cleared on GC.");
1559 :
1560 9 : *gcTotalOut += gcTotal;
1561 :
1562 9 : return NS_OK;
1563 : }
1564 :
1565 : nsresult
1566 3 : ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
1567 : const nsACString &pathPrefix,
1568 : nsIMemoryMultiReporterCallback *cb,
1569 : nsISupports *closure)
1570 : {
1571 : nsresult rv;
1572 3 : size_t gcTotal = 0;
1573 24 : for (size_t index = 0;
1574 12 : index < rtStats.compartmentStatsVector.length();
1575 : index++) {
1576 9 : rv = ReportCompartmentStats(rtStats.compartmentStatsVector[index],
1577 9 : pathPrefix, cb, closure, &gcTotal);
1578 9 : NS_ENSURE_SUCCESS(rv, rv);
1579 : }
1580 :
1581 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
1582 : nsIMemoryReporter::KIND_HEAP, rtStats.runtimeObject,
1583 : "Memory used by the JSRuntime object.");
1584 :
1585 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"),
1586 : nsIMemoryReporter::KIND_HEAP, rtStats.runtimeAtomsTable,
1587 : "Memory used by the atoms table.");
1588 :
1589 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/contexts"),
1590 : nsIMemoryReporter::KIND_HEAP, rtStats.runtimeContexts,
1591 : "Memory used by JSContext objects and certain structures "
1592 : "hanging off them.");
1593 :
1594 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/normal"),
1595 : nsIMemoryReporter::KIND_HEAP, rtStats.runtimeNormal,
1596 : "Memory used by a JSRuntime, excluding memory that is "
1597 : "reported by other reporters under 'explicit/js/runtime/'.");
1598 :
1599 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/temporary"),
1600 : nsIMemoryReporter::KIND_HEAP, rtStats.runtimeTemporary,
1601 : "Memory held transiently in JSRuntime and used during "
1602 : "compilation. It mostly holds parse nodes.");
1603 :
1604 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/regexp-code"),
1605 : nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeRegexpCode,
1606 : "Memory used by the regexp JIT to hold generated code.");
1607 :
1608 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"),
1609 : nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeStackCommitted,
1610 : "Memory used for the JS call stack. This is the committed "
1611 : "portion of the stack; the uncommitted portion is not "
1612 : "measured because it hardly costs anything.");
1613 :
1614 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/gc-marker"),
1615 : nsIMemoryReporter::KIND_HEAP, rtStats.runtimeGCMarker,
1616 : "Memory used for the GC mark stack and gray roots.");
1617 :
1618 3 : REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
1619 : rtStats.gcHeapChunkDirtyUnused,
1620 : "Memory on the garbage-collected JavaScript heap, within "
1621 : "chunks with at least one allocated GC thing, that could "
1622 : "be holding useful data but currently isn't. Memory here "
1623 : "is mutually exclusive with memory reported under "
1624 : "'explicit/js/gc-heap-decommitted'.");
1625 :
1626 3 : REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-clean-unused"),
1627 : rtStats.gcHeapChunkCleanUnused,
1628 : "Memory on the garbage-collected JavaScript heap taken by "
1629 : "completely empty chunks, that soon will be released "
1630 : "unless claimed for new allocations. Memory here is "
1631 : "mutually exclusive with memory reported under "
1632 : "'explicit/js/gc-heap-decommitted'.");
1633 :
1634 3 : REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-decommitted"),
1635 : rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
1636 : "Memory in the address space of the garbage-collected "
1637 : "JavaScript heap that is currently returned to the OS.");
1638 :
1639 3 : REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
1640 : rtStats.gcHeapChunkAdmin,
1641 : "Memory on the garbage-collected JavaScript heap, within "
1642 : "chunks, that is used to hold internal book-keeping "
1643 : "information.");
1644 :
1645 : // gcTotal is the sum of everything we've reported for the GC heap. It
1646 : // should equal rtStats.gcHeapChunkTotal.
1647 3 : JS_ASSERT(gcTotal == rtStats.gcHeapChunkTotal);
1648 :
1649 3 : return NS_OK;
1650 : }
1651 :
1652 : } // namespace memory
1653 : } // namespace xpconnect
1654 : } // namespace mozilla
1655 :
1656 42948 : NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
1657 :
1658 : class JSCompartmentsMultiReporter : public nsIMemoryMultiReporter
1659 1404 : {
1660 : public:
1661 : NS_DECL_ISUPPORTS
1662 :
1663 0 : NS_IMETHOD GetName(nsACString &name)
1664 : {
1665 0 : name.AssignLiteral("compartments");
1666 0 : return NS_OK;
1667 : }
1668 :
1669 : typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths;
1670 :
1671 9 : static void CompartmentCallback(JSRuntime *rt, void* data, JSCompartment *c)
1672 : {
1673 : // silently ignore OOM errors
1674 9 : Paths *paths = static_cast<Paths *>(data);
1675 18 : nsCString path;
1676 9 : GetCompartmentName(c, /* getAddress = */ false, path);
1677 9 : path.Insert(js::IsSystemCompartment(c)
1678 6 : ? NS_LITERAL_CSTRING("compartments/system/")
1679 3 : : NS_LITERAL_CSTRING("compartments/user/"),
1680 18 : 0);
1681 9 : paths->append(path);
1682 9 : }
1683 :
1684 3 : NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *cb,
1685 : nsISupports *closure)
1686 : {
1687 : // First we collect the compartment paths. Then we report them. Doing
1688 : // the two steps interleaved is a bad idea, because calling |cb|
1689 : // from within CompartmentCallback() leads to all manner of assertions.
1690 :
1691 : // Collect.
1692 :
1693 6 : Paths paths;
1694 : JS_IterateCompartments(nsXPConnect::GetRuntimeInstance()->GetJSRuntime(),
1695 3 : &paths, CompartmentCallback);
1696 :
1697 : // Report.
1698 12 : for (size_t i = 0; i < paths.length(); i++)
1699 : // These ones don't need a description, hence the "".
1700 9 : REPORT(nsCString(paths[i]),
1701 : nsIMemoryReporter::KIND_OTHER,
1702 : nsIMemoryReporter::UNITS_COUNT,
1703 : 1, "");
1704 :
1705 3 : return NS_OK;
1706 : }
1707 :
1708 : NS_IMETHOD
1709 3 : GetExplicitNonHeap(PRInt64 *n)
1710 : {
1711 : // This reporter does neither "explicit" nor NONHEAP measurements.
1712 3 : *n = 0;
1713 3 : return NS_OK;
1714 : }
1715 : };
1716 :
1717 4242 : NS_IMPL_THREADSAFE_ISUPPORTS1(JSCompartmentsMultiReporter
1718 : , nsIMemoryMultiReporter
1719 : )
1720 :
1721 : struct XPCJSRuntimeStats : public JS::RuntimeStats {
1722 3 : XPCJSRuntimeStats()
1723 3 : : JS::RuntimeStats(JsMallocSizeOf) { }
1724 :
1725 6 : ~XPCJSRuntimeStats() {
1726 12 : for (size_t i = 0; i != compartmentStatsVector.length(); ++i)
1727 9 : free(compartmentStatsVector[i].extra);
1728 3 : }
1729 :
1730 9 : virtual void initExtraCompartmentStats(JSCompartment *c,
1731 : JS::CompartmentStats *cstats) MOZ_OVERRIDE {
1732 18 : nsCAutoString name;
1733 9 : GetCompartmentName(c, /* getAddress = */ true, name);
1734 9 : cstats->extra = strdup(name.get());
1735 9 : }
1736 : };
1737 :
1738 : class JSMemoryMultiReporter : public nsIMemoryMultiReporter
1739 1404 : {
1740 : public:
1741 : NS_DECL_ISUPPORTS
1742 :
1743 0 : NS_IMETHOD GetName(nsACString &name)
1744 : {
1745 0 : name.AssignLiteral("js");
1746 0 : return NS_OK;
1747 : }
1748 :
1749 3 : NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *cb,
1750 : nsISupports *closure)
1751 : {
1752 3 : XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
1753 :
1754 : // In the first step we get all the stats and stash them in a local
1755 : // data structure. In the second step we pass all the stashed stats to
1756 : // the callback. Separating these steps is important because the
1757 : // callback may be a JS function, and executing JS while getting these
1758 : // stats seems like a bad idea.
1759 6 : XPCJSRuntimeStats rtStats;
1760 3 : if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
1761 0 : return NS_ERROR_FAILURE;
1762 :
1763 : size_t xpconnect =
1764 3 : xpcrt->SizeOfIncludingThis(JsMallocSizeOf) +
1765 3 : XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
1766 :
1767 6 : NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
1768 :
1769 : // This is the second step (see above). First we report stuff in the
1770 : // "explicit" tree, then we report other stuff.
1771 :
1772 : nsresult rv =
1773 3 : ReportJSRuntimeExplicitTreeStats(rtStats, pathPrefix, cb, closure);
1774 3 : NS_ENSURE_SUCCESS(rv, rv);
1775 :
1776 3 : REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
1777 : nsIMemoryReporter::KIND_HEAP, xpconnect,
1778 : "Memory used by XPConnect.");
1779 :
1780 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-chunk-dirty-unused"),
1781 : nsIMemoryReporter::KIND_OTHER,
1782 : rtStats.gcHeapChunkDirtyUnused,
1783 : "The same as 'explicit/js/gc-heap-chunk-dirty-unused'. "
1784 : "Shown here for easy comparison with other 'js-gc' "
1785 : "reporters.");
1786 :
1787 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-chunk-clean-unused"),
1788 : nsIMemoryReporter::KIND_OTHER,
1789 : rtStats.gcHeapChunkCleanUnused,
1790 : "The same as 'explicit/js/gc-heap-chunk-clean-unused'. "
1791 : "Shown here for easy comparison with other 'js-gc' "
1792 : "reporters.");
1793 :
1794 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-decommitted"),
1795 : nsIMemoryReporter::KIND_OTHER,
1796 : rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
1797 : "The same as 'explicit/js/gc-heap-decommitted'. Shown "
1798 : "here for easy comparison with other 'js-gc' reporters.");
1799 :
1800 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-arena-unused"),
1801 : nsIMemoryReporter::KIND_OTHER,
1802 : rtStats.gcHeapArenaUnused,
1803 : "Memory on the main JSRuntime's garbage-collected "
1804 : "JavaScript heap, within arenas, that could be holding "
1805 : "useful data but currently isn't. This is the sum of all "
1806 : "compartments' 'gc-heap/arena-unused' numbers.");
1807 :
1808 3 : REPORT(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-unused-fraction"),
1809 : nsIMemoryReporter::KIND_OTHER,
1810 : nsIMemoryReporter::UNITS_PERCENTAGE,
1811 : rtStats.gcHeapUnusedPercentage,
1812 : "Fraction of the main JSRuntime's garbage-collected JavaScript "
1813 : "heap that is unused. Computed as "
1814 : "('js-gc-heap-chunk-clean-unused' + "
1815 : "'js-gc-heap-chunk-dirty-unused' + 'js-gc-heap-decommitted' + "
1816 : "'js-gc-heap-arena-unused') / 'js-gc-heap'.");
1817 :
1818 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-objects"),
1819 : nsIMemoryReporter::KIND_OTHER, rtStats.totalObjects,
1820 : "Memory used for all object-related data in the main "
1821 : "JSRuntime. This is the sum of all compartments' "
1822 : "'gc-heap/objects-non-function', "
1823 : "'gc-heap/objects-function' and 'object-slots' numbers.");
1824 :
1825 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-shapes"),
1826 : nsIMemoryReporter::KIND_OTHER, rtStats.totalShapes,
1827 : "Memory used for all shape-related data in the main "
1828 : "JSRuntime. This is the sum of all compartments' "
1829 : "'gc-heap/shapes/tree', 'gc-heap/shapes/dict', "
1830 : "'gc-heap/shapes/base', 'shapes-extra/tree-tables', "
1831 : "'shapes-extra/dict-tables', "
1832 : "'shapes-extra/tree-shape-kids' and "
1833 : "'shapes-extra/empty-shape-arrays'.");
1834 :
1835 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-scripts"),
1836 : nsIMemoryReporter::KIND_OTHER, rtStats.totalScripts,
1837 : "Memory used for all script-related data in the main "
1838 : "JSRuntime. This is the sum of all compartments' "
1839 : "'gc-heap/scripts' and 'script-data' numbers.");
1840 :
1841 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-strings"),
1842 : nsIMemoryReporter::KIND_OTHER, rtStats.totalStrings,
1843 : "Memory used for all string-related data in the main "
1844 : "JSRuntime. This is the sum of all compartments' "
1845 : "'gc-heap/strings' and 'string-chars' numbers.");
1846 :
1847 : #ifdef JS_METHODJIT
1848 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-mjit"),
1849 : nsIMemoryReporter::KIND_OTHER, rtStats.totalMjit,
1850 : "Memory used by the method JIT in the main JSRuntime. "
1851 : "This is the sum of all compartments' 'mjit/code', and "
1852 : "'mjit/data' numbers.");
1853 : #endif
1854 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-type-inference"),
1855 : nsIMemoryReporter::KIND_OTHER, rtStats.totalTypeInference,
1856 : "Non-transient memory used by type inference in the main "
1857 : "JSRuntime. This is the sum of all compartments' "
1858 : "'gc-heap/type-objects', 'type-inference/script-main', "
1859 : "'type-inference/object-main' and "
1860 : "'type-inference/tables' numbers.");
1861 :
1862 3 : REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-analysis-temporary"),
1863 : nsIMemoryReporter::KIND_OTHER, rtStats.totalAnalysisTemp,
1864 : "Memory used transiently during type inference and "
1865 : "compilation in the main JSRuntime. This is the sum of "
1866 : "all compartments' 'analysis-temporary' numbers.");
1867 :
1868 3 : return NS_OK;
1869 : }
1870 :
1871 : NS_IMETHOD
1872 3 : GetExplicitNonHeap(PRInt64 *n)
1873 : {
1874 3 : JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
1875 3 : *reinterpret_cast<int64_t*>(n) = JS::GetExplicitNonHeapForRuntime(rt, JsMallocSizeOf);
1876 3 : return NS_OK;
1877 : }
1878 : };
1879 :
1880 4242 : NS_IMPL_THREADSAFE_ISUPPORTS1(JSMemoryMultiReporter
1881 : , nsIMemoryMultiReporter
1882 : )
1883 :
1884 : #ifdef MOZ_CRASHREPORTER
1885 : static JSBool
1886 4212 : DiagnosticMemoryCallback(void *ptr, size_t size)
1887 : {
1888 4212 : return CrashReporter::RegisterAppMemory(ptr, size) == NS_OK;
1889 : }
1890 : #endif
1891 :
1892 : static void
1893 147280 : AccumulateTelemetryCallback(int id, uint32_t sample)
1894 : {
1895 147280 : switch (id) {
1896 : case JS_TELEMETRY_GC_REASON:
1897 14728 : Telemetry::Accumulate(Telemetry::GC_REASON, sample);
1898 14728 : break;
1899 : case JS_TELEMETRY_GC_IS_COMPARTMENTAL:
1900 14728 : Telemetry::Accumulate(Telemetry::GC_IS_COMPARTMENTAL, sample);
1901 14728 : break;
1902 : case JS_TELEMETRY_GC_MS:
1903 14728 : Telemetry::Accumulate(Telemetry::GC_MS, sample);
1904 14728 : break;
1905 : case JS_TELEMETRY_GC_MARK_MS:
1906 14728 : Telemetry::Accumulate(Telemetry::GC_MARK_MS, sample);
1907 14728 : break;
1908 : case JS_TELEMETRY_GC_SWEEP_MS:
1909 14728 : Telemetry::Accumulate(Telemetry::GC_SWEEP_MS, sample);
1910 14728 : break;
1911 : case JS_TELEMETRY_GC_SLICE_MS:
1912 14728 : Telemetry::Accumulate(Telemetry::GC_SLICE_MS, sample);
1913 14728 : break;
1914 : case JS_TELEMETRY_GC_MMU_50:
1915 14728 : Telemetry::Accumulate(Telemetry::GC_MMU_50, sample);
1916 14728 : break;
1917 : case JS_TELEMETRY_GC_RESET:
1918 14728 : Telemetry::Accumulate(Telemetry::GC_RESET, sample);
1919 14728 : break;
1920 : case JS_TELEMETRY_GC_INCREMENTAL_DISABLED:
1921 14728 : Telemetry::Accumulate(Telemetry::GC_INCREMENTAL_DISABLED, sample);
1922 14728 : break;
1923 : case JS_TELEMETRY_GC_NON_INCREMENTAL:
1924 14728 : Telemetry::Accumulate(Telemetry::GC_NON_INCREMENTAL, sample);
1925 14728 : break;
1926 : }
1927 147280 : }
1928 :
1929 : bool XPCJSRuntime::gNewDOMBindingsEnabled;
1930 :
1931 0 : bool PreserveWrapper(JSContext *cx, JSObject *obj)
1932 : {
1933 0 : JS_ASSERT(IS_WRAPPER_CLASS(js::GetObjectClass(obj)));
1934 0 : nsISupports *native = nsXPConnect::GetXPConnect()->GetNativeOfWrapper(cx, obj);
1935 0 : if (!native)
1936 0 : return false;
1937 : nsresult rv;
1938 0 : nsCOMPtr<nsINode> node = do_QueryInterface(native, &rv);
1939 0 : if (NS_FAILED(rv))
1940 0 : return false;
1941 0 : nsContentUtils::PreserveWrapper(native, node);
1942 0 : return true;
1943 : }
1944 :
1945 1404 : XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
1946 : : mXPConnect(aXPConnect),
1947 : mJSRuntime(nsnull),
1948 : mJSCycleCollectionContext(nsnull),
1949 1404 : mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)),
1950 1404 : mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)),
1951 1404 : mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_SIZE)),
1952 1404 : mClassInfo2NativeSetMap(ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
1953 1404 : mNativeSetMap(NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
1954 1404 : mThisTranslatorMap(IID2ThisTranslatorMap::newMap(XPC_THIS_TRANSLATOR_MAP_SIZE)),
1955 1404 : mNativeScriptableSharedMap(XPCNativeScriptableSharedMap::newMap(XPC_NATIVE_JSCLASS_MAP_SIZE)),
1956 1404 : mDyingWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_SIZE)),
1957 1404 : mDetachedWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DETACHED_NATIVE_PROTO_MAP_SIZE)),
1958 1404 : mExplicitNativeWrapperMap(XPCNativeWrapperMap::newMap(XPC_NATIVE_WRAPPER_MAP_SIZE)),
1959 1404 : mMapLock(XPCAutoLock::NewLock("XPCJSRuntime::mMapLock")),
1960 : mThreadRunningGC(nsnull),
1961 : mWrappedJSToReleaseArray(),
1962 : mNativesToReleaseArray(),
1963 : mDoingFinalization(false),
1964 : mVariantRoots(nsnull),
1965 : mWrappedJSRoots(nsnull),
1966 : mObjectHolderRoots(nsnull),
1967 : mWatchdogLock(nsnull),
1968 : mWatchdogWakeup(nsnull),
1969 : mWatchdogThread(nsnull),
1970 : mWatchdogHibernating(false),
1971 16848 : mLastActiveTime(-1)
1972 : {
1973 : #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
1974 : DEBUG_WrappedNativeHashtable =
1975 : JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
1976 : sizeof(JSDHashEntryStub), 128);
1977 : #endif
1978 : NS_TIME_FUNCTION;
1979 :
1980 1404 : DOM_InitInterfaces();
1981 : Preferences::AddBoolVarCache(&gNewDOMBindingsEnabled, "dom.new_bindings",
1982 1404 : false);
1983 :
1984 :
1985 : // these jsids filled in later when we have a JSContext to work with.
1986 1404 : mStrIDs[0] = JSID_VOID;
1987 :
1988 1404 : mJSRuntime = JS_NewRuntime(32L * 1024L * 1024L); // pref ?
1989 1404 : if (!mJSRuntime)
1990 0 : NS_RUNTIMEABORT("JS_NewRuntime failed.");
1991 :
1992 : // Unconstrain the runtime's threshold on nominal heap size, to avoid
1993 : // triggering GC too often if operating continuously near an arbitrary
1994 : // finite threshold (0xffffffff is infinity for uint32_t parameters).
1995 : // This leaves the maximum-JS_malloc-bytes threshold still in effect
1996 : // to cause period, and we hope hygienic, last-ditch GCs from within
1997 : // the GC's allocator.
1998 1404 : JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff);
1999 : #ifdef MOZ_ASAN
2000 : // ASan requires more stack space due to redzones
2001 : JS_SetNativeStackQuota(mJSRuntime, 2 * 128 * sizeof(size_t) * 1024);
2002 : #else
2003 1404 : JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024);
2004 : #endif
2005 1404 : JS_SetContextCallback(mJSRuntime, ContextCallback);
2006 1404 : JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback);
2007 1404 : JS_SetGCCallback(mJSRuntime, GCCallback);
2008 1404 : JS_SetFinalizeCallback(mJSRuntime, FinalizeCallback);
2009 1404 : JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
2010 1404 : JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
2011 : JS_SetWrapObjectCallbacks(mJSRuntime,
2012 : xpc::WrapperFactory::Rewrap,
2013 1404 : xpc::WrapperFactory::PrepareForWrapping);
2014 1404 : js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);
2015 : #ifdef MOZ_CRASHREPORTER
2016 1404 : JS_EnumerateDiagnosticMemoryRegions(DiagnosticMemoryCallback);
2017 : #endif
2018 1404 : JS_SetAccumulateTelemetryCallback(mJSRuntime, AccumulateTelemetryCallback);
2019 1404 : js::SetActivityCallback(mJSRuntime, ActivityCallback, this);
2020 :
2021 1404 : NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
2022 1404 : NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
2023 1404 : NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
2024 1404 : NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter);
2025 1404 : NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
2026 :
2027 1404 : if (!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
2028 1404 : sizeof(ObjectHolder), 512))
2029 0 : mJSHolders.ops = nsnull;
2030 :
2031 1404 : mCompartmentMap.Init();
2032 :
2033 : // Install a JavaScript 'debugger' keyword handler in debug builds only
2034 : #ifdef DEBUG
2035 1404 : if (!JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
2036 1404 : xpc_InstallJSDebuggerKeywordHandler(mJSRuntime);
2037 : #endif
2038 :
2039 1404 : mWatchdogLock = PR_NewLock();
2040 1404 : if (!mWatchdogLock)
2041 0 : NS_RUNTIMEABORT("PR_NewLock failed.");
2042 1404 : mWatchdogWakeup = PR_NewCondVar(mWatchdogLock);
2043 1404 : if (!mWatchdogWakeup)
2044 0 : NS_RUNTIMEABORT("PR_NewCondVar failed.");
2045 :
2046 : {
2047 2808 : AutoLockWatchdog lock(this);
2048 :
2049 : mWatchdogThread = PR_CreateThread(PR_USER_THREAD, WatchdogMain, this,
2050 : PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
2051 1404 : PR_UNJOINABLE_THREAD, 0);
2052 1404 : if (!mWatchdogThread)
2053 0 : NS_RUNTIMEABORT("PR_CreateThread failed!");
2054 : }
2055 1404 : }
2056 :
2057 : // static
2058 : XPCJSRuntime*
2059 1404 : XPCJSRuntime::newXPCJSRuntime(nsXPConnect* aXPConnect)
2060 : {
2061 1404 : NS_PRECONDITION(aXPConnect,"bad param");
2062 :
2063 1404 : XPCJSRuntime* self = new XPCJSRuntime(aXPConnect);
2064 :
2065 16848 : if (self &&
2066 1404 : self->GetJSRuntime() &&
2067 1404 : self->GetWrappedJSMap() &&
2068 1404 : self->GetWrappedJSClassMap() &&
2069 1404 : self->GetIID2NativeInterfaceMap() &&
2070 1404 : self->GetClassInfo2NativeSetMap() &&
2071 1404 : self->GetNativeSetMap() &&
2072 1404 : self->GetThisTranslatorMap() &&
2073 1404 : self->GetNativeScriptableSharedMap() &&
2074 1404 : self->GetDyingWrappedNativeProtoMap() &&
2075 1404 : self->GetExplicitNativeWrapperMap() &&
2076 1404 : self->GetMapLock() &&
2077 : self->mWatchdogThread) {
2078 1404 : return self;
2079 : }
2080 :
2081 0 : NS_RUNTIMEABORT("new XPCJSRuntime failed to initialize.");
2082 :
2083 0 : delete self;
2084 0 : return nsnull;
2085 : }
2086 :
2087 : // InternStaticDictionaryJSVals is automatically generated.
2088 : bool InternStaticDictionaryJSVals(JSContext* aCx);
2089 :
2090 : JSBool
2091 7715 : XPCJSRuntime::OnJSContextNew(JSContext *cx)
2092 : {
2093 : NS_TIME_FUNCTION;
2094 :
2095 : // if it is our first context then we need to generate our string ids
2096 7715 : JSBool ok = true;
2097 7715 : if (JSID_IS_VOID(mStrIDs[0])) {
2098 1404 : JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 16 * 1024 * 1024);
2099 : {
2100 : // Scope the JSAutoRequest so it goes out of scope before calling
2101 : // mozilla::dom::binding::DefineStaticJSVals.
2102 2808 : JSAutoRequest ar(cx);
2103 30888 : for (unsigned i = 0; i < IDX_TOTAL_COUNT; i++) {
2104 29484 : JSString* str = JS_InternString(cx, mStrings[i]);
2105 29484 : if (!str || !JS_ValueToId(cx, STRING_TO_JSVAL(str), &mStrIDs[i])) {
2106 0 : mStrIDs[0] = JSID_VOID;
2107 0 : ok = false;
2108 0 : break;
2109 : }
2110 29484 : mStrJSVals[i] = STRING_TO_JSVAL(str);
2111 : }
2112 : }
2113 :
2114 1404 : ok = mozilla::dom::binding::DefineStaticJSVals(cx);
2115 1404 : if (!ok)
2116 0 : return false;
2117 :
2118 1404 : ok = InternStaticDictionaryJSVals(cx);
2119 : }
2120 7715 : if (!ok)
2121 0 : return false;
2122 :
2123 7715 : XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
2124 7715 : if (!tls)
2125 0 : return false;
2126 :
2127 7715 : XPCContext* xpc = new XPCContext(this, cx);
2128 7715 : if (!xpc)
2129 0 : return false;
2130 :
2131 : // we want to mark the global object ourselves since we use a different color
2132 7715 : JS_ToggleOptions(cx, JSOPTION_UNROOTED_GLOBAL);
2133 :
2134 7715 : return true;
2135 : }
2136 :
2137 : JSBool
2138 2408465 : XPCJSRuntime::DeferredRelease(nsISupports* obj)
2139 : {
2140 2408465 : NS_ASSERTION(obj, "bad param");
2141 :
2142 2408465 : if (mNativesToReleaseArray.IsEmpty()) {
2143 : // This array sometimes has 1000's
2144 : // of entries, and usually has 50-200 entries. Avoid lots
2145 : // of incremental grows. We compact it down when we're done.
2146 8772 : mNativesToReleaseArray.SetCapacity(256);
2147 : }
2148 2408465 : return mNativesToReleaseArray.AppendElement(obj) != nsnull;
2149 : }
2150 :
2151 : /***************************************************************************/
2152 :
2153 : #ifdef DEBUG
2154 : static JSDHashOperator
2155 0 : WrappedJSClassMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
2156 : uint32_t number, void *arg)
2157 : {
2158 0 : ((IID2WrappedJSClassMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
2159 0 : return JS_DHASH_NEXT;
2160 : }
2161 : static JSDHashOperator
2162 0 : WrappedJSMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
2163 : uint32_t number, void *arg)
2164 : {
2165 0 : ((JSObject2WrappedJSMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
2166 0 : return JS_DHASH_NEXT;
2167 : }
2168 : static JSDHashOperator
2169 0 : NativeSetDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
2170 : uint32_t number, void *arg)
2171 : {
2172 0 : ((NativeSetMap::Entry*)hdr)->key_value->DebugDump(*(PRInt16*)arg);
2173 0 : return JS_DHASH_NEXT;
2174 : }
2175 : #endif
2176 :
2177 : void
2178 0 : XPCJSRuntime::DebugDump(PRInt16 depth)
2179 : {
2180 : #ifdef DEBUG
2181 0 : depth--;
2182 0 : XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
2183 0 : XPC_LOG_INDENT();
2184 0 : XPC_LOG_ALWAYS(("mXPConnect @ %x", mXPConnect));
2185 0 : XPC_LOG_ALWAYS(("mJSRuntime @ %x", mJSRuntime));
2186 0 : XPC_LOG_ALWAYS(("mMapLock @ %x", mMapLock));
2187 :
2188 0 : XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)", \
2189 : &mWrappedJSToReleaseArray,
2190 : mWrappedJSToReleaseArray.Length()));
2191 :
2192 0 : int cxCount = 0;
2193 0 : JSContext* iter = nsnull;
2194 0 : while (JS_ContextIterator(mJSRuntime, &iter))
2195 0 : ++cxCount;
2196 0 : XPC_LOG_ALWAYS(("%d JS context(s)", cxCount));
2197 :
2198 0 : iter = nsnull;
2199 0 : while (JS_ContextIterator(mJSRuntime, &iter)) {
2200 0 : XPCContext *xpc = XPCContext::GetXPCContext(iter);
2201 0 : XPC_LOG_INDENT();
2202 0 : xpc->DebugDump(depth);
2203 0 : XPC_LOG_OUTDENT();
2204 : }
2205 :
2206 0 : XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)", \
2207 : mWrappedJSClassMap, mWrappedJSClassMap ? \
2208 : mWrappedJSClassMap->Count() : 0));
2209 : // iterate wrappersclasses...
2210 0 : if (depth && mWrappedJSClassMap && mWrappedJSClassMap->Count()) {
2211 0 : XPC_LOG_INDENT();
2212 0 : mWrappedJSClassMap->Enumerate(WrappedJSClassMapDumpEnumerator, &depth);
2213 0 : XPC_LOG_OUTDENT();
2214 : }
2215 0 : XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)", \
2216 : mWrappedJSMap, mWrappedJSMap ? \
2217 : mWrappedJSMap->Count() : 0));
2218 : // iterate wrappers...
2219 0 : if (depth && mWrappedJSMap && mWrappedJSMap->Count()) {
2220 0 : XPC_LOG_INDENT();
2221 0 : mWrappedJSMap->Enumerate(WrappedJSMapDumpEnumerator, &depth);
2222 0 : XPC_LOG_OUTDENT();
2223 : }
2224 :
2225 0 : XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %x with %d interface(s)", \
2226 : mIID2NativeInterfaceMap, mIID2NativeInterfaceMap ? \
2227 : mIID2NativeInterfaceMap->Count() : 0));
2228 :
2229 0 : XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %x with %d sets(s)", \
2230 : mClassInfo2NativeSetMap, mClassInfo2NativeSetMap ? \
2231 : mClassInfo2NativeSetMap->Count() : 0));
2232 :
2233 0 : XPC_LOG_ALWAYS(("mThisTranslatorMap @ %x with %d translator(s)", \
2234 : mThisTranslatorMap, mThisTranslatorMap ? \
2235 : mThisTranslatorMap->Count() : 0));
2236 :
2237 0 : XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)", \
2238 : mNativeSetMap, mNativeSetMap ? \
2239 : mNativeSetMap->Count() : 0));
2240 :
2241 : // iterate sets...
2242 0 : if (depth && mNativeSetMap && mNativeSetMap->Count()) {
2243 0 : XPC_LOG_INDENT();
2244 0 : mNativeSetMap->Enumerate(NativeSetDumpEnumerator, &depth);
2245 0 : XPC_LOG_OUTDENT();
2246 : }
2247 :
2248 0 : XPC_LOG_OUTDENT();
2249 : #endif
2250 0 : }
2251 :
2252 : /***************************************************************************/
2253 :
2254 : void
2255 117513 : XPCRootSetElem::AddToRootSet(XPCLock *lock, XPCRootSetElem **listHead)
2256 : {
2257 117513 : NS_ASSERTION(!mSelfp, "Must be not linked");
2258 :
2259 235026 : XPCAutoLock autoLock(lock);
2260 :
2261 117513 : mSelfp = listHead;
2262 117513 : mNext = *listHead;
2263 117513 : if (mNext) {
2264 114086 : NS_ASSERTION(mNext->mSelfp == listHead, "Must be list start");
2265 114086 : mNext->mSelfp = &mNext;
2266 : }
2267 117513 : *listHead = this;
2268 117513 : }
2269 :
2270 : void
2271 117232 : XPCRootSetElem::RemoveFromRootSet(XPCLock *lock)
2272 : {
2273 117232 : NS_ASSERTION(mSelfp, "Must be linked");
2274 :
2275 234464 : XPCAutoLock autoLock(lock);
2276 :
2277 117232 : NS_ASSERTION(*mSelfp == this, "Link invariant");
2278 117232 : *mSelfp = mNext;
2279 117232 : if (mNext)
2280 110746 : mNext->mSelfp = mSelfp;
2281 : #ifdef DEBUG
2282 117232 : mSelfp = nsnull;
2283 117232 : mNext = nsnull;
2284 : #endif
2285 117232 : }
2286 :
2287 : void
2288 0 : XPCJSRuntime::AddGCCallback(JSGCCallback cb)
2289 : {
2290 0 : NS_ASSERTION(cb, "null callback");
2291 0 : extraGCCallbacks.AppendElement(cb);
2292 0 : }
2293 :
2294 : void
2295 0 : XPCJSRuntime::RemoveGCCallback(JSGCCallback cb)
2296 : {
2297 0 : NS_ASSERTION(cb, "null callback");
2298 0 : bool found = extraGCCallbacks.RemoveElement(cb);
2299 0 : if (!found) {
2300 0 : NS_ERROR("Removing a callback which was never added.");
2301 : }
2302 0 : }
|