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 : * Pierre Phaneuf <pp@ludusdesign.com>
27 : * Nate Nielsen <nielsen@memberwebs.com>
28 : *
29 : * Alternatively, the contents of this file may be used under the terms of
30 : * either of the GNU General Public License Version 2 or later (the "GPL"),
31 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 : * in which case the provisions of the GPL or the LGPL are applicable instead
33 : * of those above. If you wish to allow use of your version of this file only
34 : * under the terms of either the GPL or the LGPL, and not to allow others to
35 : * use your version of this file under the terms of the MPL, indicate your
36 : * decision by deleting the provisions above and replace them with the notice
37 : * and other provisions required by the GPL or the LGPL. If you do not delete
38 : * the provisions above, a recipient may use your version of this file under
39 : * the terms of any one of the MPL, the GPL or the LGPL.
40 : *
41 : * ***** END LICENSE BLOCK ***** */
42 :
43 : /* High level class and public functions implementation. */
44 :
45 : #include "mozilla/Assertions.h"
46 : #include "mozilla/Base64.h"
47 : #include "mozilla/Util.h"
48 :
49 : #include "xpcprivate.h"
50 : #include "XPCWrapper.h"
51 : #include "nsBaseHashtable.h"
52 : #include "nsHashKeys.h"
53 : #include "jsatom.h"
54 : #include "jsfriendapi.h"
55 : #include "jsgc.h"
56 : #include "dom_quickstubs.h"
57 : #include "nsNullPrincipal.h"
58 : #include "nsIURI.h"
59 : #include "nsJSEnvironment.h"
60 : #include "nsThreadUtils.h"
61 :
62 : #include "XrayWrapper.h"
63 : #include "WrapperFactory.h"
64 : #include "AccessCheck.h"
65 :
66 : #include "jsdIDebuggerService.h"
67 :
68 : #include "XPCQuickStubs.h"
69 : #include "dombindings.h"
70 :
71 : #include "nsWrapperCacheInlines.h"
72 :
73 10425367 : NS_IMPL_THREADSAFE_ISUPPORTS7(nsXPConnect,
74 : nsIXPConnect,
75 : nsISupportsWeakReference,
76 : nsIThreadObserver,
77 : nsIJSRuntimeService,
78 : nsIJSContextStack,
79 : nsIThreadJSContextStack,
80 : nsIJSEngineTelemetryStats)
81 :
82 : nsXPConnect* nsXPConnect::gSelf = nsnull;
83 : JSBool nsXPConnect::gOnceAliveNowDead = false;
84 : PRUint32 nsXPConnect::gReportAllJSExceptions = 0;
85 : JSBool nsXPConnect::gDebugMode = false;
86 : JSBool nsXPConnect::gDesiredDebugMode = false;
87 :
88 : // Global cache of the default script security manager (QI'd to
89 : // nsIScriptSecurityManager)
90 : nsIScriptSecurityManager *nsXPConnect::gScriptSecurityManager = nsnull;
91 :
92 : const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
93 : const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1";
94 : const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1";
95 : const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1";
96 : const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1";
97 : const char XPC_ID_CONTRACTID[] = "@mozilla.org/js/xpc/ID;1";
98 : const char XPC_XPCONNECT_CONTRACTID[] = "@mozilla.org/js/xpc/XPConnect;1";
99 :
100 : /***************************************************************************/
101 :
102 1404 : nsXPConnect::nsXPConnect()
103 : : mRuntime(nsnull),
104 : mInterfaceInfoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)),
105 : mDefaultSecurityManager(nsnull),
106 : mDefaultSecurityManagerFlags(0),
107 : mShuttingDown(false),
108 : mNeedGCBeforeCC(true),
109 : mEventDepth(0),
110 1404 : mCycleCollectionContext(nsnull)
111 : {
112 1404 : mRuntime = XPCJSRuntime::newXPCJSRuntime(this);
113 :
114 1404 : nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this);
115 : #ifdef DEBUG_CC
116 : mJSRoots.ops = nsnull;
117 : #endif
118 :
119 1404 : char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS");
120 1404 : if (reportableEnv && *reportableEnv)
121 0 : gReportAllJSExceptions = 1;
122 1404 : }
123 :
124 4209 : nsXPConnect::~nsXPConnect()
125 : {
126 1403 : nsCycleCollector_forgetRuntime(nsIProgrammingLanguage::JAVASCRIPT);
127 :
128 1403 : JSContext *cx = nsnull;
129 1403 : if (mRuntime) {
130 : // Create our own JSContext rather than an XPCCallContext, since
131 : // otherwise we will create a new safe JS context and attach a
132 : // components object that won't get GCed.
133 : // And do this before calling CleanupAllThreads, so that we
134 : // don't create an extra xpcPerThreadData.
135 1403 : cx = JS_NewContext(mRuntime->GetJSRuntime(), 8192);
136 : }
137 :
138 1403 : XPCPerThreadData::CleanupAllThreads();
139 1403 : mShuttingDown = true;
140 1403 : if (cx) {
141 : // XXX Call even if |mRuntime| null?
142 1403 : XPCWrappedNativeScope::SystemIsBeingShutDown();
143 :
144 1403 : mRuntime->SystemIsBeingShutDown();
145 1403 : JS_DestroyContext(cx);
146 : }
147 :
148 1403 : NS_IF_RELEASE(mDefaultSecurityManager);
149 :
150 1403 : gScriptSecurityManager = nsnull;
151 :
152 : // shutdown the logging system
153 1403 : XPC_LOG_FINISH();
154 :
155 1403 : delete mRuntime;
156 :
157 1403 : gSelf = nsnull;
158 1403 : gOnceAliveNowDead = true;
159 5612 : }
160 :
161 : // static
162 : nsXPConnect*
163 18723706 : nsXPConnect::GetXPConnect()
164 : {
165 : // Do a release-mode assert that we're not doing anything significant in
166 : // XPConnect off the main thread. If you're an extension developer hitting
167 : // this, you need to change your code. See bug 716167.
168 18723706 : if (!NS_LIKELY(NS_IsMainThread() || NS_IsCycleCollectorThread()))
169 0 : MOZ_Assert("NS_IsMainThread()", __FILE__, __LINE__);
170 :
171 18723706 : if (!gSelf) {
172 1404 : if (gOnceAliveNowDead)
173 0 : return nsnull;
174 1404 : gSelf = new nsXPConnect();
175 1404 : if (!gSelf)
176 0 : return nsnull;
177 :
178 1404 : if (!gSelf->mRuntime) {
179 0 : NS_RUNTIMEABORT("Couldn't create XPCJSRuntime.");
180 : }
181 1404 : if (!gSelf->mInterfaceInfoManager) {
182 0 : NS_RUNTIMEABORT("Couldn't get global interface info manager.");
183 : }
184 :
185 : // Initial extra ref to keep the singleton alive
186 : // balanced by explicit call to ReleaseXPConnectSingleton()
187 1404 : NS_ADDREF(gSelf);
188 :
189 : // Add XPConnect as an thread observer.
190 : //
191 : // The cycle collector sometimes calls GetXPConnect, but it should never
192 : // be the one that initializes gSelf.
193 1404 : MOZ_ASSERT(NS_IsMainThread());
194 2808 : nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
195 1404 : if (NS_FAILED(thread->AddObserver(gSelf))) {
196 0 : NS_RELEASE(gSelf);
197 : // Fall through to returning null
198 : }
199 : }
200 18723706 : return gSelf;
201 : }
202 :
203 : // static
204 : nsXPConnect*
205 1403 : nsXPConnect::GetSingleton()
206 : {
207 1403 : nsXPConnect* xpc = nsXPConnect::GetXPConnect();
208 1403 : NS_IF_ADDREF(xpc);
209 1403 : return xpc;
210 : }
211 :
212 : // static
213 : void
214 1404 : nsXPConnect::ReleaseXPConnectSingleton()
215 : {
216 1404 : nsXPConnect* xpc = gSelf;
217 1404 : if (xpc) {
218 :
219 : // The thread subsystem may have been shut down already, so make sure
220 : // to check for null here.
221 2808 : nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
222 1404 : if (thread) {
223 0 : MOZ_ASSERT(NS_IsMainThread());
224 0 : thread->RemoveObserver(xpc);
225 : }
226 :
227 : #ifdef DEBUG
228 : // force a dump of the JavaScript gc heap if JS is still alive
229 : // if requested through XPC_SHUTDOWN_HEAP_DUMP environment variable
230 : {
231 1404 : const char* dumpName = getenv("XPC_SHUTDOWN_HEAP_DUMP");
232 1404 : if (dumpName) {
233 : FILE* dumpFile = (*dumpName == '\0' ||
234 0 : strcmp(dumpName, "stdout") == 0)
235 : ? stdout
236 0 : : fopen(dumpName, "w");
237 0 : if (dumpFile) {
238 : JS_DumpHeap(xpc->GetRuntime()->GetJSRuntime(), dumpFile, nsnull,
239 0 : JSTRACE_OBJECT, nsnull, static_cast<size_t>(-1), nsnull);
240 0 : if (dumpFile != stdout)
241 0 : fclose(dumpFile);
242 : }
243 : }
244 : }
245 : #endif
246 : #ifdef XPC_DUMP_AT_SHUTDOWN
247 : // NOTE: to see really interesting stuff turn on the prlog stuff.
248 : // See the comment at the top of XPCLog.h to see how to do that.
249 : xpc->DebugDump(7);
250 : #endif
251 : nsrefcnt cnt;
252 1404 : NS_RELEASE2(xpc, cnt);
253 : #ifdef XPC_DUMP_AT_SHUTDOWN
254 : if (0 != cnt)
255 : printf("*** dangling reference to nsXPConnect: refcnt=%d\n", cnt);
256 : else
257 : printf("+++ XPConnect had no dangling references.\n");
258 : #endif
259 : }
260 1404 : }
261 :
262 : // static
263 : nsresult
264 0 : nsXPConnect::GetInterfaceInfoManager(nsIInterfaceInfoSuperManager** iim,
265 : nsXPConnect* xpc /*= nsnull*/)
266 : {
267 0 : if (!xpc && !(xpc = GetXPConnect()))
268 0 : return NS_ERROR_FAILURE;
269 :
270 0 : *iim = xpc->mInterfaceInfoManager;
271 0 : NS_IF_ADDREF(*iim);
272 0 : return NS_OK;
273 : }
274 :
275 : // static
276 : XPCJSRuntime*
277 2041731 : nsXPConnect::GetRuntimeInstance()
278 : {
279 2041731 : nsXPConnect* xpc = GetXPConnect();
280 2041731 : NS_ASSERTION(xpc, "Must not be called if XPC failed to initialize");
281 2041731 : return xpc->GetRuntime();
282 : }
283 :
284 : // static
285 : JSBool
286 160071 : nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info)
287 : {
288 160071 : bool found = false;
289 160071 : if (info)
290 160071 : info->HasAncestor(&NS_GET_IID(nsISupports), &found);
291 160071 : return found;
292 : }
293 :
294 : /***************************************************************************/
295 :
296 : typedef bool (*InfoTester)(nsIInterfaceInfoManager* manager, const void* data,
297 : nsIInterfaceInfo** info);
298 :
299 308493 : static bool IIDTester(nsIInterfaceInfoManager* manager, const void* data,
300 : nsIInterfaceInfo** info)
301 : {
302 308493 : return NS_SUCCEEDED(manager->GetInfoForIID((const nsIID *) data, info)) &&
303 308493 : *info;
304 : }
305 :
306 5400 : static bool NameTester(nsIInterfaceInfoManager* manager, const void* data,
307 : nsIInterfaceInfo** info)
308 : {
309 5400 : return NS_SUCCEEDED(manager->GetInfoForName((const char *) data, info)) &&
310 5400 : *info;
311 : }
312 :
313 313893 : static nsresult FindInfo(InfoTester tester, const void* data,
314 : nsIInterfaceInfoSuperManager* iism,
315 : nsIInterfaceInfo** info)
316 : {
317 313893 : if (tester(iism, data, info))
318 306454 : return NS_OK;
319 :
320 : // If not found, then let's ask additional managers.
321 :
322 : bool yes;
323 14878 : nsCOMPtr<nsISimpleEnumerator> list;
324 :
325 14878 : if (NS_SUCCEEDED(iism->HasAdditionalManagers(&yes)) && yes &&
326 7439 : NS_SUCCEEDED(iism->EnumerateAdditionalManagers(getter_AddRefs(list))) &&
327 0 : list) {
328 : bool more;
329 0 : nsCOMPtr<nsIInterfaceInfoManager> current;
330 :
331 0 : while (NS_SUCCEEDED(list->HasMoreElements(&more)) && more &&
332 0 : NS_SUCCEEDED(list->GetNext(getter_AddRefs(current))) && current) {
333 0 : if (tester(current, data, info))
334 0 : return NS_OK;
335 : }
336 : }
337 :
338 7439 : return NS_ERROR_NO_INTERFACE;
339 : }
340 :
341 : nsresult
342 308493 : nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info)
343 : {
344 308493 : return FindInfo(IIDTester, aIID, mInterfaceInfoManager, info);
345 : }
346 :
347 : nsresult
348 5400 : nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
349 : {
350 5400 : return FindInfo(NameTester, name, mInterfaceInfoManager, info);
351 : }
352 :
353 : bool
354 48 : nsXPConnect::NeedCollect()
355 : {
356 48 : return !!mNeedGCBeforeCC;
357 : }
358 :
359 : void
360 1868 : nsXPConnect::Collect(PRUint32 reason, PRUint32 kind)
361 : {
362 : // We're dividing JS objects into 2 categories:
363 : //
364 : // 1. "real" roots, held by the JS engine itself or rooted through the root
365 : // and lock JS APIs. Roots from this category are considered black in the
366 : // cycle collector, any cycle they participate in is uncollectable.
367 : //
368 : // 2. roots held by C++ objects that participate in cycle collection,
369 : // held by XPConnect (see XPCJSRuntime::TraceXPConnectRoots). Roots from
370 : // this category are considered grey in the cycle collector, their final
371 : // color depends on the objects that hold them.
372 : //
373 : // Note that if a root is in both categories it is the fact that it is in
374 : // category 1 that takes precedence, so it will be considered black.
375 : //
376 : // During garbage collection we switch to an additional mark color (gray)
377 : // when tracing inside TraceXPConnectRoots. This allows us to walk those
378 : // roots later on and add all objects reachable only from them to the
379 : // cycle collector.
380 : //
381 : // Phases:
382 : //
383 : // 1. marking of the roots in category 1 by having the JS GC do its marking
384 : // 2. marking of the roots in category 2 by XPCJSRuntime::TraceXPConnectRoots
385 : // using an additional color (gray).
386 : // 3. end of GC, GC can sweep its heap
387 : //
388 : // At some later point, when the cycle collector runs:
389 : //
390 : // 4. walk gray objects and add them to the cycle collector, cycle collect
391 : //
392 : // JS objects that are part of cycles the cycle collector breaks will be
393 : // collected by the next JS.
394 : //
395 : // If DEBUG_CC is not defined the cycle collector will not traverse roots
396 : // from category 1 or any JS objects held by them. Any JS objects they hold
397 : // will already be marked by the JS GC and will thus be colored black
398 : // themselves. Any C++ objects they hold will have a missing (untraversed)
399 : // edge from the JS object to the C++ object and so it will be marked black
400 : // too. This decreases the number of objects that the cycle collector has to
401 : // deal with.
402 : // To improve debugging, if DEBUG_CC is defined all JS objects are
403 : // traversed.
404 :
405 3736 : XPCCallContext ccx(NATIVE_CALLER);
406 1868 : if (!ccx.IsValid())
407 : return;
408 :
409 1868 : JSContext *cx = ccx.GetJSContext();
410 :
411 : // We want to scan the current thread for GC roots only if it was in a
412 : // request prior to the Collect call to avoid false positives during the
413 : // cycle collection. So to compensate for JS_BeginRequest in
414 : // XPCCallContext::Init we disable the conservative scanner if that call
415 : // has started the request on this thread.
416 3736 : js::AutoSkipConservativeScan ascs(cx);
417 1868 : MOZ_ASSERT(reason < js::gcreason::NUM_REASONS);
418 1868 : js::gcreason::Reason gcreason = (js::gcreason::Reason)reason;
419 1868 : if (kind == nsGCShrinking) {
420 0 : js::ShrinkingGC(cx, gcreason);
421 1868 : } else if (kind == nsGCIncremental) {
422 4 : js::IncrementalGC(cx, gcreason);
423 : } else {
424 1864 : MOZ_ASSERT(kind == nsGCNormal);
425 1864 : js::GCForReason(cx, gcreason);
426 : }
427 : }
428 :
429 : NS_IMETHODIMP
430 4 : nsXPConnect::GarbageCollect(PRUint32 reason, PRUint32 kind)
431 : {
432 4 : Collect(reason, kind);
433 4 : return NS_OK;
434 : }
435 :
436 : #ifdef DEBUG_CC
437 : struct NoteJSRootTracer : public JSTracer
438 : {
439 : NoteJSRootTracer(PLDHashTable *aObjects,
440 : nsCycleCollectionTraversalCallback& cb)
441 : : mObjects(aObjects),
442 : mCb(cb)
443 : {
444 : }
445 : PLDHashTable* mObjects;
446 : nsCycleCollectionTraversalCallback& mCb;
447 : };
448 :
449 : static void
450 : NoteJSRoot(JSTracer *trc, void *thing, JSGCTraceKind kind)
451 : {
452 : if (AddToCCKind(kind)) {
453 : NoteJSRootTracer *tracer = static_cast<NoteJSRootTracer*>(trc);
454 : PLDHashEntryHdr *entry = PL_DHashTableOperate(tracer->mObjects, thing,
455 : PL_DHASH_ADD);
456 : if (entry && !reinterpret_cast<PLDHashEntryStub*>(entry)->key) {
457 : reinterpret_cast<PLDHashEntryStub*>(entry)->key = thing;
458 : tracer->mCb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, thing,
459 : nsXPConnect::GetXPConnect());
460 : }
461 : } else if (kind != JSTRACE_STRING) {
462 : JS_TraceChildren(trc, thing, kind);
463 : }
464 : }
465 : #endif
466 :
467 : struct NoteWeakMapChildrenTracer : public JSTracer
468 : {
469 1910 : NoteWeakMapChildrenTracer(nsCycleCollectionTraversalCallback &cb)
470 1910 : : mCb(cb)
471 : {
472 1910 : }
473 : nsCycleCollectionTraversalCallback &mCb;
474 : JSObject *mMap;
475 : void *mKey;
476 : };
477 :
478 : static void
479 0 : TraceWeakMappingChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
480 : {
481 0 : MOZ_ASSERT(trc->callback == TraceWeakMappingChild);
482 0 : void *thing = *thingp;
483 : NoteWeakMapChildrenTracer *tracer =
484 0 : static_cast<NoteWeakMapChildrenTracer *>(trc);
485 0 : if (kind == JSTRACE_STRING)
486 0 : return;
487 0 : if (!xpc_IsGrayGCThing(thing) && !tracer->mCb.WantAllTraces())
488 0 : return;
489 0 : if (AddToCCKind(kind)) {
490 0 : tracer->mCb.NoteWeakMapping(tracer->mMap, tracer->mKey, thing);
491 : } else {
492 0 : JS_TraceChildren(trc, thing, kind);
493 : }
494 : }
495 :
496 : struct NoteWeakMapsTracer : public js::WeakMapTracer
497 : {
498 1910 : NoteWeakMapsTracer(JSRuntime *rt, js::WeakMapTraceCallback cb,
499 : nsCycleCollectionTraversalCallback &cccb)
500 1910 : : js::WeakMapTracer(rt, cb), mCb(cccb), mChildTracer(cccb)
501 : {
502 1910 : JS_TracerInit(&mChildTracer, rt, TraceWeakMappingChild);
503 1910 : }
504 : nsCycleCollectionTraversalCallback &mCb;
505 : NoteWeakMapChildrenTracer mChildTracer;
506 : };
507 :
508 : static void
509 0 : TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m,
510 : void *k, JSGCTraceKind kkind,
511 : void *v, JSGCTraceKind vkind)
512 : {
513 0 : MOZ_ASSERT(trc->callback == TraceWeakMapping);
514 0 : NoteWeakMapsTracer *tracer = static_cast<NoteWeakMapsTracer *>(trc);
515 0 : if (vkind == JSTRACE_STRING)
516 0 : return;
517 0 : if (!xpc_IsGrayGCThing(v) && !tracer->mCb.WantAllTraces())
518 0 : return;
519 :
520 : // The cycle collector can only properly reason about weak maps if it can
521 : // reason about the liveness of their keys, which in turn requires that
522 : // the key can be represented in the cycle collector graph. All existing
523 : // uses of weak maps use either objects or scripts as keys, which are okay.
524 0 : MOZ_ASSERT(AddToCCKind(kkind));
525 :
526 : // As an emergency fallback for non-debug builds, if the key is not
527 : // representable in the cycle collector graph, we treat it as marked. This
528 : // can cause leaks, but is preferable to ignoring the binding, which could
529 : // cause the cycle collector to free live objects.
530 0 : if (!AddToCCKind(kkind))
531 0 : k = nsnull;
532 :
533 0 : if (AddToCCKind(vkind)) {
534 0 : tracer->mCb.NoteWeakMapping(m, k, v);
535 : } else {
536 0 : tracer->mChildTracer.mMap = m;
537 0 : tracer->mChildTracer.mKey = k;
538 0 : JS_TraceChildren(&tracer->mChildTracer, v, vkind);
539 : }
540 : }
541 :
542 : nsresult
543 1910 : nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb,
544 : bool explainLiveExpectedGarbage)
545 : {
546 : // It is important not to call GetSafeJSContext while on the
547 : // cycle-collector thread since this context will be destroyed
548 : // asynchronously and race with the main thread. In particular, we must
549 : // ensure that a context is passed to the XPCCallContext constructor.
550 1910 : JSContext *cx = mRuntime->GetJSCycleCollectionContext();
551 1910 : if (!cx)
552 0 : return NS_ERROR_OUT_OF_MEMORY;
553 :
554 1910 : NS_ASSERTION(!mCycleCollectionContext, "Didn't call FinishTraverse?");
555 3820 : mCycleCollectionContext = new XPCCallContext(NATIVE_CALLER, cx);
556 1910 : if (!mCycleCollectionContext->IsValid()) {
557 0 : mCycleCollectionContext = nsnull;
558 0 : return NS_ERROR_FAILURE;
559 : }
560 :
561 : static bool gcHasRun = false;
562 1910 : if (!gcHasRun) {
563 1404 : JSRuntime* rt = GetRuntime()->GetJSRuntime();
564 1404 : uint32_t gcNumber = JS_GetGCParameter(rt, JSGC_NUMBER);
565 1404 : if (!gcNumber)
566 0 : NS_RUNTIMEABORT("Cannot cycle collect if GC has not run first!");
567 1404 : gcHasRun = true;
568 : }
569 :
570 : #ifdef DEBUG_CC
571 : NS_ASSERTION(!mJSRoots.ops, "Didn't call FinishCycleCollection?");
572 :
573 : if (explainLiveExpectedGarbage) {
574 : // Being called from nsCycleCollector::ExplainLiveExpectedGarbage.
575 :
576 : // Record all objects held by the JS runtime. This avoids doing a
577 : // complete GC if we're just tracing to explain (from
578 : // ExplainLiveExpectedGarbage), which makes the results of cycle
579 : // collection identical for DEBUG_CC and non-DEBUG_CC builds.
580 : if (!PL_DHashTableInit(&mJSRoots, PL_DHashGetStubOps(), nsnull,
581 : sizeof(PLDHashEntryStub), PL_DHASH_MIN_SIZE)) {
582 : mJSRoots.ops = nsnull;
583 :
584 : return NS_ERROR_OUT_OF_MEMORY;
585 : }
586 :
587 : NoteJSRootTracer trc(&mJSRoots, cb);
588 : JS_TracerInit(&trc, mCycleCollectionContext->GetJSContext(), NoteJSRoot);
589 : JS_TraceRuntime(&trc);
590 : }
591 : #else
592 1910 : NS_ASSERTION(!explainLiveExpectedGarbage, "Didn't call nsXPConnect::Collect()?");
593 : #endif
594 :
595 1910 : GetRuntime()->AddXPConnectRoots(cb);
596 :
597 1910 : NoteWeakMapsTracer trc(GetRuntime()->GetJSRuntime(), TraceWeakMapping, cb);
598 1910 : js::TraceWeakMaps(&trc);
599 :
600 1910 : return NS_OK;
601 : }
602 :
603 : bool
604 48 : nsXPConnect::NotifyLeaveMainThread()
605 : {
606 48 : NS_ABORT_IF_FALSE(NS_IsMainThread(), "Off main thread");
607 48 : JSRuntime *rt = mRuntime->GetJSRuntime();
608 48 : if (JS_IsInRequest(rt) || JS_IsInSuspendedRequest(rt))
609 45 : return false;
610 3 : JS_ClearRuntimeThread(rt);
611 3 : return true;
612 : }
613 :
614 : void
615 3 : nsXPConnect::NotifyEnterCycleCollectionThread()
616 : {
617 3 : NS_ABORT_IF_FALSE(!NS_IsMainThread(), "On main thread");
618 3 : JS_SetRuntimeThread(mRuntime->GetJSRuntime());
619 3 : }
620 :
621 : void
622 3 : nsXPConnect::NotifyLeaveCycleCollectionThread()
623 : {
624 3 : NS_ABORT_IF_FALSE(!NS_IsMainThread(), "On main thread");
625 3 : JS_ClearRuntimeThread(mRuntime->GetJSRuntime());
626 3 : }
627 :
628 : void
629 3 : nsXPConnect::NotifyEnterMainThread()
630 : {
631 3 : NS_ABORT_IF_FALSE(NS_IsMainThread(), "Off main thread");
632 3 : JS_SetRuntimeThread(mRuntime->GetJSRuntime());
633 3 : }
634 :
635 : nsresult
636 1910 : nsXPConnect::FinishTraverse()
637 : {
638 1910 : if (mCycleCollectionContext)
639 1910 : mCycleCollectionContext = nsnull;
640 1910 : return NS_OK;
641 : }
642 :
643 : nsresult
644 1910 : nsXPConnect::FinishCycleCollection()
645 : {
646 : #ifdef DEBUG_CC
647 : if (mJSRoots.ops) {
648 : PL_DHashTableFinish(&mJSRoots);
649 : mJSRoots.ops = nsnull;
650 : }
651 : #endif
652 :
653 1910 : return NS_OK;
654 : }
655 :
656 : nsCycleCollectionParticipant *
657 1352183 : nsXPConnect::ToParticipant(void *p)
658 : {
659 1352183 : if (!AddToCCKind(js_GetGCThingTraceKind(p)))
660 0 : return NULL;
661 1352183 : return this;
662 : }
663 :
664 : NS_IMETHODIMP
665 25671 : nsXPConnect::Root(void *p)
666 : {
667 25671 : return NS_OK;
668 : }
669 :
670 : #ifdef DEBUG_CC
671 : void
672 : nsXPConnect::PrintAllReferencesTo(void *p)
673 : {
674 : #ifdef DEBUG
675 : XPCCallContext ccx(NATIVE_CALLER);
676 : if (ccx.IsValid())
677 : JS_DumpHeap(ccx.GetJSContext(), stdout, nsnull, 0, p,
678 : 0x7fffffff, nsnull);
679 : #endif
680 : }
681 : #endif
682 :
683 : NS_IMETHODIMP
684 25671 : nsXPConnect::Unlink(void *p)
685 : {
686 25671 : return NS_OK;
687 : }
688 :
689 : NS_IMETHODIMP
690 25671 : nsXPConnect::Unroot(void *p)
691 : {
692 25671 : return NS_OK;
693 : }
694 :
695 : JSBool
696 1357230 : xpc_GCThingIsGrayCCThing(void *thing)
697 : {
698 1357230 : return AddToCCKind(js_GetGCThingTraceKind(thing)) &&
699 1357230 : xpc_IsGrayGCThing(thing);
700 : }
701 :
702 : struct UnmarkGrayTracer : public JSTracer
703 : {
704 5600 : UnmarkGrayTracer() : mTracingShape(false), mPreviousShape(nsnull) {}
705 207798 : UnmarkGrayTracer(JSTracer *trc, bool aTracingShape)
706 207798 : : mTracingShape(aTracingShape), mPreviousShape(nsnull)
707 : {
708 207798 : JS_TracerInit(this, trc->runtime, trc->callback);
709 207798 : }
710 : bool mTracingShape; // true iff we are tracing the immediate children of a shape
711 : void *mPreviousShape; // If mTracingShape, shape child or NULL. Otherwise, NULL.
712 : };
713 :
714 : /*
715 : * The GC and CC are run independently. Consequently, the following sequence of
716 : * events can occur:
717 : * 1. GC runs and marks an object gray.
718 : * 2. Some JS code runs that creates a pointer from a JS root to the gray
719 : * object. If we re-ran a GC at this point, the object would now be black.
720 : * 3. Now we run the CC. It may think it can collect the gray object, even
721 : * though it's reachable from the JS heap.
722 : *
723 : * To prevent this badness, we unmark the gray bit of an object when it is
724 : * accessed by callers outside XPConnect. This would cause the object to go
725 : * black in step 2 above. This must be done on everything reachable from the
726 : * object being returned. The following code takes care of the recursive
727 : * re-coloring.
728 : */
729 : static void
730 689878 : UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind)
731 : {
732 689878 : void *thing = *thingp;
733 : int stackDummy;
734 689878 : if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(trc->runtime), &stackDummy)) {
735 : /*
736 : * If we run out of stack, we take a more drastic measure: require that
737 : * we GC again before the next CC.
738 : */
739 0 : nsXPConnect* xpc = nsXPConnect::GetXPConnect();
740 0 : xpc->EnsureGCBeforeCC();
741 0 : return;
742 : }
743 :
744 689878 : if (!xpc_IsGrayGCThing(thing))
745 482080 : return;
746 :
747 207798 : static_cast<js::gc::Cell *>(thing)->unmark(js::gc::GRAY);
748 :
749 : /*
750 : * Trace children of |thing|. If |thing| and its parent are both shapes, |thing| will
751 : * get saved to mPreviousShape without being traced. The parent will later
752 : * trace |thing|. This is done to avoid increasing the stack depth during shape
753 : * tracing. It is safe to do because a shape can only have one child that is a shape.
754 : */
755 207798 : UnmarkGrayTracer *tracer = static_cast<UnmarkGrayTracer*>(trc);
756 207798 : UnmarkGrayTracer childTracer(tracer, kind == JSTRACE_SHAPE);
757 :
758 207798 : if (kind != JSTRACE_SHAPE) {
759 122627 : JS_TraceChildren(&childTracer, thing, kind);
760 122627 : MOZ_ASSERT(!childTracer.mPreviousShape);
761 122627 : return;
762 : }
763 :
764 85171 : if (tracer->mTracingShape) {
765 64963 : MOZ_ASSERT(!tracer->mPreviousShape);
766 64963 : tracer->mPreviousShape = thing;
767 64963 : return;
768 : }
769 :
770 85171 : do {
771 85171 : MOZ_ASSERT(!xpc_IsGrayGCThing(thing));
772 85171 : JS_TraceChildren(&childTracer, thing, JSTRACE_SHAPE);
773 85171 : thing = childTracer.mPreviousShape;
774 85171 : childTracer.mPreviousShape = nsnull;
775 : } while (thing);
776 : }
777 :
778 : void
779 5600 : xpc_UnmarkGrayObjectRecursive(JSObject *obj)
780 : {
781 5600 : NS_ASSERTION(obj, "Don't pass me null!");
782 :
783 : // Unmark.
784 5600 : js::gc::AsCell(obj)->unmark(js::gc::GRAY);
785 :
786 : // Trace children.
787 5600 : UnmarkGrayTracer trc;
788 5600 : JS_TracerInit(&trc, JS_GetObjectRuntime(obj), UnmarkGrayChildren);
789 5600 : JS_TraceChildren(&trc, obj, JSTRACE_OBJECT);
790 5600 : }
791 :
792 : struct TraversalTracer : public JSTracer
793 : {
794 452318 : TraversalTracer(nsCycleCollectionTraversalCallback &aCb) : cb(aCb)
795 : {
796 452318 : }
797 : nsCycleCollectionTraversalCallback &cb;
798 : };
799 :
800 : static void
801 3659381 : NoteJSChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
802 : {
803 3659381 : TraversalTracer *tracer = static_cast<TraversalTracer*>(trc);
804 3659381 : void *thing = *thingp;
805 :
806 : // Don't traverse non-gray objects, unless we want all traces.
807 3659381 : if (!xpc_IsGrayGCThing(thing) && !tracer->cb.WantAllTraces())
808 1630616 : return;
809 :
810 : /*
811 : * This function needs to be careful to avoid stack overflow. Normally, when
812 : * AddToCCKind is true, the recursion terminates immediately as we just add
813 : * |thing| to the CC graph. So overflow is only possible when there are long
814 : * chains of non-AddToCCKind GC things. Currently, this only can happen via
815 : * shape parent pointers. The special JSTRACE_SHAPE case below handles
816 : * parent pointers iteratively, rather than recursively, to avoid overflow.
817 : */
818 2028765 : if (AddToCCKind(kind)) {
819 : #if defined(DEBUG)
820 1345770 : if (NS_UNLIKELY(tracer->cb.WantDebugInfo())) {
821 : // based on DumpNotify in jsapi.c
822 0 : if (tracer->debugPrinter) {
823 : char buffer[200];
824 0 : tracer->debugPrinter(trc, buffer, sizeof(buffer));
825 0 : tracer->cb.NoteNextEdgeName(buffer);
826 0 : } else if (tracer->debugPrintIndex != (size_t)-1) {
827 : char buffer[200];
828 : JS_snprintf(buffer, sizeof(buffer), "%s[%lu]",
829 : static_cast<const char *>(tracer->debugPrintArg),
830 0 : tracer->debugPrintIndex);
831 0 : tracer->cb.NoteNextEdgeName(buffer);
832 : } else {
833 0 : tracer->cb.NoteNextEdgeName(static_cast<const char*>(tracer->debugPrintArg));
834 : }
835 : }
836 : #endif
837 1345770 : tracer->cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, thing);
838 682995 : } else if (kind == JSTRACE_SHAPE) {
839 375083 : JS_TraceShapeCycleCollectorChildren(trc, thing);
840 307912 : } else if (kind != JSTRACE_STRING) {
841 307912 : JS_TraceChildren(trc, thing, kind);
842 : }
843 : }
844 :
845 : void
846 0 : xpc_MarkInCCGeneration(nsISupports* aVariant, PRUint32 aGeneration)
847 : {
848 0 : nsCOMPtr<XPCVariant> variant = do_QueryInterface(aVariant);
849 0 : if (variant) {
850 0 : variant->SetCCGeneration(aGeneration);
851 0 : variant->GetJSVal(); // Unmarks gray JSObject.
852 0 : XPCVariant* weak = variant.get();
853 0 : variant = nsnull;
854 0 : if (weak->IsPurple()) {
855 0 : weak->RemovePurple();
856 : }
857 : }
858 0 : }
859 :
860 : void
861 374 : xpc_UnmarkGrayObject(nsIXPConnectWrappedJS* aWrappedJS)
862 : {
863 374 : if (aWrappedJS) {
864 : // Unmarks gray JSObject.
865 374 : static_cast<nsXPCWrappedJS*>(aWrappedJS)->GetJSObject();
866 : }
867 374 : }
868 :
869 : static JSBool
870 46164 : WrapperIsNotMainThreadOnly(XPCWrappedNative *wrapper)
871 : {
872 46164 : XPCWrappedNativeProto *proto = wrapper->GetProto();
873 46164 : if (proto && proto->ClassIsMainThreadOnly())
874 259 : return false;
875 :
876 : // If the native participates in cycle collection then we know it can only
877 : // be used on the main thread, in that case we assume the wrapped native
878 : // can only be used on the main thread too.
879 : nsXPCOMCycleCollectionParticipant* participant;
880 45905 : return NS_FAILED(CallQueryInterface(wrapper->Native(), &participant));
881 : }
882 :
883 : NS_IMETHODIMP
884 452374 : nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
885 : {
886 452374 : JSGCTraceKind traceKind = js_GetGCThingTraceKind(p);
887 452374 : JSObject *obj = nsnull;
888 452374 : js::Class *clazz = nsnull;
889 :
890 : // We do not want to add wrappers to the cycle collector if they're not
891 : // explicitly marked as main thread only, because the cycle collector isn't
892 : // able to deal with objects that might be used off of the main thread. We
893 : // do want to explicitly mark them for cycle collection if the wrapper has
894 : // an external reference, because the wrapper would mark the JS object if
895 : // we did add the wrapper to the cycle collector.
896 452374 : JSBool dontTraverse = false;
897 452374 : JSBool markJSObject = false;
898 452374 : if (traceKind == JSTRACE_OBJECT) {
899 404343 : obj = static_cast<JSObject*>(p);
900 404343 : clazz = js::GetObjectClass(obj);
901 :
902 404343 : if (clazz == &XPC_WN_Tearoff_JSClass) {
903 : XPCWrappedNative *wrapper =
904 0 : (XPCWrappedNative*)xpc_GetJSPrivate(js::GetObjectParent(obj));
905 0 : dontTraverse = WrapperIsNotMainThreadOnly(wrapper);
906 404343 : } else if (IS_WRAPPER_CLASS(clazz) && IS_WN_WRAPPER_OBJECT(obj)) {
907 46164 : XPCWrappedNative *wrapper = (XPCWrappedNative*)xpc_GetJSPrivate(obj);
908 46164 : dontTraverse = WrapperIsNotMainThreadOnly(wrapper);
909 46164 : markJSObject = dontTraverse && wrapper->HasExternalReference();
910 : }
911 : }
912 :
913 : bool isMarked;
914 :
915 : #ifdef DEBUG_CC
916 : // Note that the conditions under which we specify GCMarked vs.
917 : // GCUnmarked are different between ExplainLiveExpectedGarbage and
918 : // the normal case. In the normal case, we're saying that anything
919 : // reachable from a JS runtime root is itself such a root. This
920 : // doesn't actually break anything; it really just does some of the
921 : // cycle collector's work for it. However, when debugging, we
922 : // (1) actually need to know what the root is and (2) don't want to
923 : // do an extra GC, so we use mJSRoots, built from JS_TraceRuntime,
924 : // which produces a different result because we didn't call
925 : // JS_TraceChildren to trace everything that was reachable.
926 : if (mJSRoots.ops) {
927 : // ExplainLiveExpectedGarbage codepath
928 : PLDHashEntryHdr* entry =
929 : PL_DHashTableOperate(&mJSRoots, p, PL_DHASH_LOOKUP);
930 : isMarked = markJSObject || PL_DHASH_ENTRY_IS_BUSY(entry);
931 : } else
932 : #endif
933 : {
934 : // Normal codepath (matches non-DEBUG_CC codepath).
935 452374 : isMarked = markJSObject || !xpc_IsGrayGCThing(p);
936 : }
937 :
938 452374 : if (cb.WantDebugInfo()) {
939 : char name[72];
940 0 : if (traceKind == JSTRACE_OBJECT) {
941 0 : XPCNativeScriptableInfo* si = nsnull;
942 0 : if (IS_PROTO_CLASS(clazz)) {
943 : XPCWrappedNativeProto* p =
944 0 : (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
945 0 : si = p->GetScriptableInfo();
946 : }
947 0 : if (si) {
948 : JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
949 0 : clazz->name, si->GetJSClass()->name);
950 0 : } else if (clazz == &js::FunctionClass) {
951 0 : JSFunction* fun = JS_GetObjectFunction(obj);
952 0 : JSString* str = JS_GetFunctionId(fun);
953 0 : if (str) {
954 0 : NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
955 : JS_snprintf(name, sizeof(name),
956 0 : "JS Object (Function - %s)", fname.get());
957 : } else {
958 0 : JS_snprintf(name, sizeof(name), "JS Object (Function)");
959 : }
960 : } else {
961 : JS_snprintf(name, sizeof(name), "JS Object (%s)",
962 0 : clazz->name);
963 : }
964 : } else {
965 : static const char trace_types[][11] = {
966 : "Object",
967 : "String",
968 : "Script",
969 : "Xml",
970 : "Shape",
971 : "BaseShape",
972 : "TypeObject",
973 : };
974 : JS_STATIC_ASSERT(NS_ARRAY_LENGTH(trace_types) == JSTRACE_LAST + 1);
975 0 : JS_snprintf(name, sizeof(name), "JS %s", trace_types[traceKind]);
976 : }
977 :
978 : // Disable printing global for objects while we figure out ObjShrink fallout.
979 0 : cb.DescribeGCedNode(isMarked, sizeof(js::shadow::Object), name);
980 : } else {
981 452374 : cb.DescribeGCedNode(isMarked, sizeof(js::shadow::Object), "JS Object");
982 : }
983 :
984 : // There's no need to trace objects that have already been marked by the JS
985 : // GC. Any JS objects hanging from them will already be marked. Only do this
986 : // if DEBUG_CC is not defined, else we do want to know about all JS objects
987 : // to get better graphs and explanations.
988 452374 : if (!cb.WantAllTraces() && isMarked)
989 56 : return NS_OK;
990 :
991 452318 : TraversalTracer trc(cb);
992 :
993 452318 : JS_TracerInit(&trc, GetRuntime()->GetJSRuntime(), NoteJSChild);
994 452318 : trc.eagerlyTraceWeakMaps = false;
995 452318 : JS_TraceChildren(&trc, p, traceKind);
996 :
997 452318 : if (traceKind != JSTRACE_OBJECT || dontTraverse)
998 93776 : return NS_OK;
999 :
1000 358542 : if (clazz == &XPC_WN_Tearoff_JSClass) {
1001 : // A tearoff holds a strong reference to its native object
1002 : // (see XPCWrappedNative::FlatJSObjectFinalized). Its XPCWrappedNative
1003 : // will be held alive through the parent of the JSObject of the tearoff.
1004 : XPCWrappedNativeTearOff *to =
1005 0 : (XPCWrappedNativeTearOff*) xpc_GetJSPrivate(obj);
1006 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)->mNative");
1007 0 : cb.NoteXPCOMChild(to->GetNative());
1008 : }
1009 : // XXX This test does seem fragile, we should probably whitelist classes
1010 : // that do hold a strong reference, but that might not be possible.
1011 358542 : else if (clazz->flags & JSCLASS_HAS_PRIVATE &&
1012 : clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
1013 2285 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)");
1014 2285 : cb.NoteXPCOMChild(static_cast<nsISupports*>(xpc_GetJSPrivate(obj)));
1015 356257 : } else if (mozilla::dom::binding::instanceIsProxy(obj)) {
1016 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "js::GetProxyPrivate(obj)");
1017 : nsISupports *identity =
1018 0 : static_cast<nsISupports*>(js::GetProxyPrivate(obj).toPrivate());
1019 0 : cb.NoteXPCOMChild(identity);
1020 : }
1021 :
1022 358542 : return NS_OK;
1023 : }
1024 :
1025 : unsigned
1026 5298 : nsXPConnect::GetOutstandingRequests(JSContext* cx)
1027 : {
1028 5298 : unsigned n = js::GetContextOutstandingRequests(cx);
1029 5298 : XPCCallContext* context = mCycleCollectionContext;
1030 : // Ignore the contribution from the XPCCallContext we created for cycle
1031 : // collection.
1032 5298 : if (context && cx == context->GetJSContext()) {
1033 1910 : MOZ_ASSERT(n);
1034 1910 : --n;
1035 : }
1036 5298 : return n;
1037 : }
1038 :
1039 : class JSContextParticipant : public nsCycleCollectionParticipant
1040 1464 : {
1041 : public:
1042 0 : NS_IMETHOD Root(void *n)
1043 : {
1044 0 : return NS_OK;
1045 : }
1046 0 : NS_IMETHOD Unlink(void *n)
1047 : {
1048 0 : JSContext *cx = static_cast<JSContext*>(n);
1049 0 : JSAutoRequest ar(cx);
1050 0 : NS_ASSERTION(JS_GetGlobalObject(cx), "global object NULL before unlinking");
1051 0 : JS_SetGlobalObject(cx, NULL);
1052 0 : return NS_OK;
1053 : }
1054 0 : NS_IMETHOD Unroot(void *n)
1055 : {
1056 0 : return NS_OK;
1057 : }
1058 5298 : NS_IMETHODIMP Traverse(void *n, nsCycleCollectionTraversalCallback &cb)
1059 : {
1060 5298 : JSContext *cx = static_cast<JSContext*>(n);
1061 :
1062 : // Add outstandingRequests to the count, if there are outstanding
1063 : // requests the context needs to be kept alive and adding unknown
1064 : // edges will ensure that any cycles this context is in won't be
1065 : // collected.
1066 5298 : unsigned refCount = nsXPConnect::GetXPConnect()->GetOutstandingRequests(cx) + 1;
1067 5298 : cb.DescribeRefCountedNode(refCount, js::SizeOfJSContext(), "JSContext");
1068 5298 : if (JSObject *global = JS_GetGlobalObject(cx)) {
1069 3387 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[global object]");
1070 3387 : cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, global);
1071 : }
1072 :
1073 5298 : return NS_OK;
1074 : }
1075 : };
1076 :
1077 1464 : static JSContextParticipant JSContext_cycleCollectorGlobal;
1078 :
1079 : // static
1080 : nsCycleCollectionParticipant*
1081 5298 : nsXPConnect::JSContextParticipant()
1082 : {
1083 5298 : return &JSContext_cycleCollectorGlobal;
1084 : }
1085 :
1086 : NS_IMETHODIMP_(void)
1087 0 : nsXPConnect::NoteJSContext(JSContext *aJSContext,
1088 : nsCycleCollectionTraversalCallback &aCb)
1089 : {
1090 0 : aCb.NoteNativeChild(aJSContext, &JSContext_cycleCollectorGlobal);
1091 0 : }
1092 :
1093 :
1094 : /***************************************************************************/
1095 : /***************************************************************************/
1096 : // nsIXPConnect interface methods...
1097 :
1098 0 : inline nsresult UnexpectedFailure(nsresult rv)
1099 : {
1100 0 : NS_ERROR("This is not supposed to fail!");
1101 0 : return rv;
1102 : }
1103 :
1104 : /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
1105 : NS_IMETHODIMP
1106 2258 : nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
1107 : {
1108 2258 : NS_ASSERTION(aJSContext, "bad param");
1109 2258 : NS_ASSERTION(aGlobalJSObj, "bad param");
1110 :
1111 : // Nest frame chain save/restore in request created by XPCCallContext.
1112 4516 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1113 2258 : if (!ccx.IsValid())
1114 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1115 :
1116 4516 : JSAutoEnterCompartment ac;
1117 2258 : if (!ac.enter(ccx, aGlobalJSObj))
1118 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1119 :
1120 : XPCWrappedNativeScope* scope =
1121 2258 : XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
1122 :
1123 2258 : if (!scope)
1124 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1125 :
1126 2258 : scope->RemoveWrappedNativeProtos();
1127 :
1128 2258 : if (!nsXPCComponents::AttachNewComponentsObject(ccx, scope, aGlobalJSObj))
1129 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1130 :
1131 2258 : if (XPCPerThreadData::IsMainThread(ccx)) {
1132 2258 : if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, aGlobalJSObj))
1133 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1134 : }
1135 :
1136 2258 : return NS_OK;
1137 : }
1138 :
1139 : static bool
1140 3369 : CreateNewCompartment(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
1141 : xpc::CompartmentPrivate *priv, JSObject **global,
1142 : JSCompartment **compartment)
1143 : {
1144 : // We take ownership of |priv|. Ensure that either we free it in the case
1145 : // of failure or give ownership to the compartment in case of success (in
1146 : // that case it will be free'd in CompartmentCallback during GC).
1147 6738 : nsAutoPtr<xpc::CompartmentPrivate> priv_holder(priv);
1148 : JSObject *tempGlobal =
1149 3369 : JS_NewCompartmentAndGlobalObject(cx, clasp, nsJSPrincipals::get(principal));
1150 :
1151 3369 : if (!tempGlobal)
1152 0 : return false;
1153 :
1154 3369 : *global = tempGlobal;
1155 3369 : *compartment = js::GetObjectCompartment(tempGlobal);
1156 :
1157 3369 : JS_SetCompartmentPrivate(*compartment, priv_holder.forget());
1158 3369 : return true;
1159 : }
1160 :
1161 : #ifdef DEBUG
1162 : struct VerifyTraceXPCGlobalCalledTracer
1163 : {
1164 : JSTracer base;
1165 : bool ok;
1166 : };
1167 :
1168 : static void
1169 5934 : VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind)
1170 : {
1171 : // We don't do anything here, we only want to verify that TraceXPCGlobal
1172 : // was called.
1173 5934 : }
1174 : #endif
1175 :
1176 : void
1177 149042 : TraceXPCGlobal(JSTracer *trc, JSObject *obj)
1178 : {
1179 : #ifdef DEBUG
1180 149042 : if (trc->callback == VerifyTraceXPCGlobalCalled) {
1181 : // We don't do anything here, we only want to verify that TraceXPCGlobal
1182 : // was called.
1183 1978 : reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = true;
1184 1978 : return;
1185 : }
1186 : #endif
1187 :
1188 147064 : if (XPCWrappedNativeScope *scope = XPCWrappedNativeScope::GetNativeScope(obj))
1189 147064 : scope->TraceDOMPrototypes(trc);
1190 : }
1191 :
1192 : nsresult
1193 15195 : xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
1194 : nsIPrincipal *principal, nsISupports *ptr,
1195 : bool wantXrays, JSObject **global,
1196 : JSCompartment **compartment)
1197 : {
1198 15195 : NS_ABORT_IF_FALSE(NS_IsMainThread(), "using a principal off the main thread?");
1199 15195 : NS_ABORT_IF_FALSE(principal, "bad key");
1200 :
1201 15195 : XPCCompartmentMap& map = nsXPConnect::GetRuntimeInstance()->GetCompartmentMap();
1202 30390 : xpc::PtrAndPrincipalHashKey key(ptr, principal);
1203 15195 : if (!map.Get(&key, compartment)) {
1204 : xpc::PtrAndPrincipalHashKey *priv_key =
1205 3369 : new xpc::PtrAndPrincipalHashKey(ptr, principal);
1206 3369 : xpc::CompartmentPrivate *priv = new xpc::CompartmentPrivate(priv_key, wantXrays);
1207 3369 : if (!CreateNewCompartment(cx, clasp, principal, priv,
1208 3369 : global, compartment)) {
1209 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1210 : }
1211 :
1212 3369 : map.Put(&key, *compartment);
1213 : } else {
1214 23652 : js::AutoSwitchCompartment sc(cx, *compartment);
1215 :
1216 11826 : JSObject *tempGlobal = JS_NewGlobalObject(cx, clasp);
1217 11826 : if (!tempGlobal)
1218 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1219 23652 : *global = tempGlobal;
1220 : }
1221 :
1222 : #ifdef DEBUG
1223 : // Verify that the right trace hook is called. Note that this doesn't
1224 : // work right for wrapped globals, since the tracing situation there is
1225 : // more complicated. Manual inspection shows that they do the right thing.
1226 30390 : if (clasp->flags & JSCLASS_XPCONNECT_GLOBAL &&
1227 15195 : !((js::Class*)clasp)->ext.isWrappedNative)
1228 : {
1229 : VerifyTraceXPCGlobalCalledTracer trc;
1230 1978 : JS_TracerInit(&trc.base, JS_GetRuntime(cx), VerifyTraceXPCGlobalCalled);
1231 1978 : trc.ok = false;
1232 1978 : JS_TraceChildren(&trc.base, *global, JSTRACE_OBJECT);
1233 1978 : NS_ABORT_IF_FALSE(trc.ok, "Trace hook needs to call TraceXPCGlobal if JSCLASS_XPCONNECT_GLOBAL is set.");
1234 : }
1235 : #endif
1236 :
1237 15195 : return NS_OK;
1238 : }
1239 :
1240 : NS_IMETHODIMP
1241 13217 : nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
1242 : nsISupports *aCOMObj,
1243 : nsIPrincipal * aPrincipal,
1244 : PRUint32 aFlags,
1245 : nsIXPConnectJSObjectHolder **_retval)
1246 : {
1247 13217 : NS_ASSERTION(aJSContext, "bad param");
1248 13217 : NS_ASSERTION(aCOMObj, "bad param");
1249 13217 : NS_ASSERTION(_retval, "bad param");
1250 :
1251 : // We pass null for the 'extra' pointer during global object creation, so
1252 : // we need to have a principal.
1253 13217 : MOZ_ASSERT(aPrincipal);
1254 :
1255 26434 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1256 :
1257 : // Call into XPCWrappedNative to make a new global object, scope, and global
1258 : // prototype.
1259 26434 : xpcObjectHelper helper(aCOMObj);
1260 13217 : MOZ_ASSERT(helper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
1261 26434 : nsRefPtr<XPCWrappedNative> wrappedGlobal;
1262 : nsresult rv =
1263 : XPCWrappedNative::WrapNewGlobal(ccx, helper, aPrincipal,
1264 : aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
1265 13217 : getter_AddRefs(wrappedGlobal));
1266 13217 : NS_ENSURE_SUCCESS(rv, rv);
1267 :
1268 : // Grab a copy of the global and enter its compartment.
1269 13217 : JSObject *global = wrappedGlobal->GetFlatJSObject();
1270 13217 : MOZ_ASSERT(!js::GetObjectParent(global));
1271 26434 : JSAutoEnterCompartment ac;
1272 13217 : if (!ac.enter(ccx, global))
1273 0 : return NS_ERROR_UNEXPECTED;
1274 :
1275 : // Apply the system flag, if requested.
1276 13217 : bool system = (aFlags & nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT) != 0;
1277 13217 : if (system && !JS_MakeSystemObject(aJSContext, global))
1278 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1279 :
1280 13217 : if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
1281 : // XPCCallContext gives us an active request needed to save/restore.
1282 13217 : if (!nsXPCComponents::AttachNewComponentsObject(ccx, wrappedGlobal->GetScope(), global))
1283 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1284 :
1285 13217 : if (XPCPerThreadData::IsMainThread(ccx)) {
1286 13217 : if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, global))
1287 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1288 : }
1289 : }
1290 :
1291 13217 : *_retval = wrappedGlobal.forget().get();
1292 13217 : return NS_OK;
1293 : }
1294 :
1295 : nsresult
1296 0 : xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph)
1297 : {
1298 : nsWrapperCache *cache;
1299 0 : CallQueryInterface(tomorph, &cache);
1300 0 : if (!cache)
1301 0 : return NS_OK;
1302 :
1303 0 : JSObject *obj = cache->GetWrapper();
1304 0 : if (!obj || !IS_SLIM_WRAPPER(obj))
1305 0 : return NS_OK;
1306 0 : return MorphSlimWrapper(cx, obj);
1307 : }
1308 :
1309 : static nsresult
1310 648602 : NativeInterface2JSObject(XPCLazyCallContext & lccx,
1311 : JSObject * aScope,
1312 : nsISupports *aCOMObj,
1313 : nsWrapperCache *aCache,
1314 : const nsIID * aIID,
1315 : bool aAllowWrapping,
1316 : jsval *aVal,
1317 : nsIXPConnectJSObjectHolder **aHolder)
1318 : {
1319 1297204 : JSAutoEnterCompartment ac;
1320 648602 : if (!ac.enter(lccx.GetJSContext(), aScope))
1321 0 : return NS_ERROR_OUT_OF_MEMORY;
1322 :
1323 648602 : lccx.SetScopeForNewJSObjects(aScope);
1324 :
1325 : nsresult rv;
1326 1297204 : xpcObjectHelper helper(aCOMObj, aCache);
1327 648602 : if (!XPCConvert::NativeInterface2JSObject(lccx, aVal, aHolder, helper, aIID,
1328 648602 : nsnull, aAllowWrapping, &rv))
1329 0 : return rv;
1330 :
1331 : #ifdef DEBUG
1332 648602 : NS_ASSERTION(aAllowWrapping ||
1333 : !xpc::WrapperFactory::IsXrayWrapper(JSVAL_TO_OBJECT(*aVal)),
1334 : "Shouldn't be returning a xray wrapper here");
1335 : #endif
1336 :
1337 648602 : return NS_OK;
1338 : }
1339 :
1340 : /* nsIXPConnectJSObjectHolder wrapNative (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */
1341 : NS_IMETHODIMP
1342 545593 : nsXPConnect::WrapNative(JSContext * aJSContext,
1343 : JSObject * aScope,
1344 : nsISupports *aCOMObj,
1345 : const nsIID & aIID,
1346 : nsIXPConnectJSObjectHolder **aHolder)
1347 : {
1348 545593 : NS_ASSERTION(aHolder, "bad param");
1349 545593 : NS_ASSERTION(aJSContext, "bad param");
1350 545593 : NS_ASSERTION(aScope, "bad param");
1351 545593 : NS_ASSERTION(aCOMObj, "bad param");
1352 :
1353 1091186 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1354 545593 : if (!ccx.IsValid())
1355 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1356 1091186 : XPCLazyCallContext lccx(ccx);
1357 :
1358 : jsval v;
1359 : return NativeInterface2JSObject(lccx, aScope, aCOMObj, nsnull, &aIID,
1360 545593 : false, &v, aHolder);
1361 : }
1362 :
1363 : /* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDPtr aIID, out jsval aVal, out nsIXPConnectJSObjectHolder aHolder); */
1364 : NS_IMETHODIMP
1365 103009 : nsXPConnect::WrapNativeToJSVal(JSContext * aJSContext,
1366 : JSObject * aScope,
1367 : nsISupports *aCOMObj,
1368 : nsWrapperCache *aCache,
1369 : const nsIID * aIID,
1370 : bool aAllowWrapping,
1371 : jsval *aVal,
1372 : nsIXPConnectJSObjectHolder **aHolder)
1373 : {
1374 103009 : NS_ASSERTION(aJSContext, "bad param");
1375 103009 : NS_ASSERTION(aScope, "bad param");
1376 103009 : NS_ASSERTION(aCOMObj, "bad param");
1377 :
1378 103009 : if (aHolder)
1379 324 : *aHolder = nsnull;
1380 :
1381 206018 : XPCLazyCallContext lccx(NATIVE_CALLER, aJSContext);
1382 :
1383 : return NativeInterface2JSObject(lccx, aScope, aCOMObj, aCache, aIID,
1384 103009 : aAllowWrapping, aVal, aHolder);
1385 : }
1386 :
1387 : /* void wrapJS (in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
1388 : NS_IMETHODIMP
1389 2452 : nsXPConnect::WrapJS(JSContext * aJSContext,
1390 : JSObject * aJSObj,
1391 : const nsIID & aIID,
1392 : void * *result)
1393 : {
1394 2452 : NS_ASSERTION(aJSContext, "bad param");
1395 2452 : NS_ASSERTION(aJSObj, "bad param");
1396 2452 : NS_ASSERTION(result, "bad param");
1397 :
1398 2452 : *result = nsnull;
1399 :
1400 4904 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1401 2452 : if (!ccx.IsValid())
1402 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1403 :
1404 4904 : JSAutoEnterCompartment aec;
1405 :
1406 2452 : nsresult rv = NS_ERROR_UNEXPECTED;
1407 4904 : if (!aec.enter(ccx, aJSObj) ||
1408 : !XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
1409 2452 : &aIID, nsnull, &rv))
1410 0 : return rv;
1411 2452 : return NS_OK;
1412 : }
1413 :
1414 : NS_IMETHODIMP
1415 0 : nsXPConnect::JSValToVariant(JSContext *cx,
1416 : jsval *aJSVal,
1417 : nsIVariant ** aResult)
1418 : {
1419 0 : NS_PRECONDITION(aJSVal, "bad param");
1420 0 : NS_PRECONDITION(aResult, "bad param");
1421 0 : *aResult = nsnull;
1422 :
1423 0 : XPCCallContext ccx(NATIVE_CALLER, cx);
1424 0 : if (!ccx.IsValid())
1425 0 : return NS_ERROR_FAILURE;
1426 :
1427 0 : *aResult = XPCVariant::newVariant(ccx, *aJSVal);
1428 0 : NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
1429 :
1430 0 : return NS_OK;
1431 : }
1432 :
1433 : /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
1434 : NS_IMETHODIMP
1435 0 : nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,
1436 : JSContext * aJSContext,
1437 : JSObject * aJSObj,
1438 : const nsIID & aIID,
1439 : void * *result)
1440 : {
1441 0 : NS_ASSERTION(aOuter, "bad param");
1442 0 : NS_ASSERTION(aJSContext, "bad param");
1443 0 : NS_ASSERTION(aJSObj, "bad param");
1444 0 : NS_ASSERTION(result, "bad param");
1445 :
1446 0 : *result = nsnull;
1447 :
1448 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1449 0 : if (!ccx.IsValid())
1450 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1451 :
1452 : nsresult rv;
1453 0 : if (!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
1454 0 : &aIID, aOuter, &rv))
1455 0 : return rv;
1456 0 : return NS_OK;
1457 : }
1458 :
1459 : /* nsIXPConnectWrappedNative getWrappedNativeOfJSObject (in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */
1460 : NS_IMETHODIMP
1461 13405 : nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext,
1462 : JSObject * aJSObj,
1463 : nsIXPConnectWrappedNative **_retval)
1464 : {
1465 13405 : NS_ASSERTION(aJSContext, "bad param");
1466 13405 : NS_ASSERTION(aJSObj, "bad param");
1467 13405 : NS_ASSERTION(_retval, "bad param");
1468 :
1469 26810 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1470 13405 : if (!ccx.IsValid())
1471 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1472 :
1473 : SLIM_LOG_WILL_MORPH(aJSContext, aJSObj);
1474 : nsIXPConnectWrappedNative* wrapper =
1475 13405 : XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(aJSContext, aJSObj);
1476 13405 : if (wrapper) {
1477 13037 : NS_ADDREF(wrapper);
1478 13037 : *_retval = wrapper;
1479 13037 : return NS_OK;
1480 : }
1481 :
1482 : // else...
1483 368 : *_retval = nsnull;
1484 368 : return NS_ERROR_FAILURE;
1485 : }
1486 :
1487 : /* nsISupports getNativeOfWrapper(in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */
1488 : NS_IMETHODIMP_(nsISupports*)
1489 9864 : nsXPConnect::GetNativeOfWrapper(JSContext * aJSContext,
1490 : JSObject * aJSObj)
1491 : {
1492 9864 : NS_ASSERTION(aJSContext, "bad param");
1493 9864 : NS_ASSERTION(aJSObj, "bad param");
1494 :
1495 19728 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1496 9864 : if (!ccx.IsValid()) {
1497 0 : UnexpectedFailure(NS_ERROR_FAILURE);
1498 0 : return nsnull;
1499 : }
1500 :
1501 9864 : JSObject* obj2 = nsnull;
1502 : nsIXPConnectWrappedNative* wrapper =
1503 : XPCWrappedNative::GetWrappedNativeOfJSObject(aJSContext, aJSObj, nsnull,
1504 9864 : &obj2);
1505 9864 : if (wrapper)
1506 9848 : return wrapper->Native();
1507 :
1508 16 : if (obj2)
1509 0 : return (nsISupports*)xpc_GetJSPrivate(obj2);
1510 :
1511 16 : if (mozilla::dom::binding::instanceIsProxy(aJSObj)) {
1512 : // FIXME: Provide a fast non-refcounting way to get the canonical
1513 : // nsISupports from the proxy.
1514 : nsISupports *supports =
1515 0 : static_cast<nsISupports*>(js::GetProxyPrivate(aJSObj).toPrivate());
1516 0 : nsCOMPtr<nsISupports> canonical = do_QueryInterface(supports);
1517 0 : return canonical.get();
1518 : }
1519 :
1520 16 : return nsnull;
1521 : }
1522 :
1523 : /* JSObjectPtr getJSObjectOfWrapper (in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */
1524 : NS_IMETHODIMP
1525 0 : nsXPConnect::GetJSObjectOfWrapper(JSContext * aJSContext,
1526 : JSObject * aJSObj,
1527 : JSObject **_retval)
1528 : {
1529 0 : NS_ASSERTION(aJSContext, "bad param");
1530 0 : NS_ASSERTION(aJSObj, "bad param");
1531 0 : NS_ASSERTION(_retval, "bad param");
1532 :
1533 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1534 0 : if (!ccx.IsValid())
1535 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1536 :
1537 0 : JSObject* obj2 = nsnull;
1538 : nsIXPConnectWrappedNative* wrapper =
1539 : XPCWrappedNative::GetWrappedNativeOfJSObject(aJSContext, aJSObj, nsnull,
1540 0 : &obj2);
1541 0 : if (wrapper) {
1542 0 : wrapper->GetJSObject(_retval);
1543 0 : return NS_OK;
1544 : }
1545 0 : if (obj2) {
1546 0 : *_retval = obj2;
1547 0 : return NS_OK;
1548 : }
1549 0 : if (mozilla::dom::binding::instanceIsProxy(aJSObj)) {
1550 0 : *_retval = aJSObj;
1551 0 : return NS_OK;
1552 : }
1553 : // else...
1554 0 : *_retval = nsnull;
1555 0 : return NS_ERROR_FAILURE;
1556 : }
1557 :
1558 : /* nsIXPConnectWrappedNative getWrappedNativeOfNativeObject (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */
1559 : NS_IMETHODIMP
1560 0 : nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext,
1561 : JSObject * aScope,
1562 : nsISupports *aCOMObj,
1563 : const nsIID & aIID,
1564 : nsIXPConnectWrappedNative **_retval)
1565 : {
1566 0 : NS_ASSERTION(aJSContext, "bad param");
1567 0 : NS_ASSERTION(aScope, "bad param");
1568 0 : NS_ASSERTION(aCOMObj, "bad param");
1569 0 : NS_ASSERTION(_retval, "bad param");
1570 :
1571 0 : *_retval = nsnull;
1572 :
1573 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1574 0 : if (!ccx.IsValid())
1575 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1576 :
1577 : XPCWrappedNativeScope* scope =
1578 0 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
1579 0 : if (!scope)
1580 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1581 :
1582 0 : AutoMarkingNativeInterfacePtr iface(ccx);
1583 0 : iface = XPCNativeInterface::GetNewOrUsed(ccx, &aIID);
1584 0 : if (!iface)
1585 0 : return NS_ERROR_FAILURE;
1586 :
1587 : XPCWrappedNative* wrapper;
1588 :
1589 : nsresult rv = XPCWrappedNative::GetUsedOnly(ccx, aCOMObj, scope, iface,
1590 0 : &wrapper);
1591 0 : if (NS_FAILED(rv))
1592 0 : return NS_ERROR_FAILURE;
1593 0 : *_retval = static_cast<nsIXPConnectWrappedNative*>(wrapper);
1594 0 : return NS_OK;
1595 : }
1596 :
1597 : /* nsIXPConnectJSObjectHolder reparentWrappedNativeIfFound (in JSContextPtr aJSContext, in JSObjectPtr aScope, in JSObjectPtr aNewParent, in nsISupports aCOMObj); */
1598 : NS_IMETHODIMP
1599 0 : nsXPConnect::ReparentWrappedNativeIfFound(JSContext * aJSContext,
1600 : JSObject * aScope,
1601 : JSObject * aNewParent,
1602 : nsISupports *aCOMObj,
1603 : nsIXPConnectJSObjectHolder **_retval)
1604 : {
1605 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1606 0 : if (!ccx.IsValid())
1607 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1608 :
1609 : XPCWrappedNativeScope* scope =
1610 0 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
1611 0 : if (!scope)
1612 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1613 :
1614 : XPCWrappedNativeScope* scope2 =
1615 0 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, aNewParent);
1616 0 : if (!scope2)
1617 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1618 :
1619 : return XPCWrappedNative::
1620 : ReparentWrapperIfFound(ccx, scope, scope2, aNewParent, aCOMObj,
1621 0 : (XPCWrappedNative**) _retval);
1622 : }
1623 :
1624 : static JSDHashOperator
1625 0 : MoveableWrapperFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
1626 : uint32_t number, void *arg)
1627 : {
1628 : nsTArray<nsRefPtr<XPCWrappedNative> > *array =
1629 0 : static_cast<nsTArray<nsRefPtr<XPCWrappedNative> > *>(arg);
1630 0 : XPCWrappedNative *wn = ((Native2WrappedNativeMap::Entry*)hdr)->value;
1631 :
1632 : // If a wrapper is expired, then there are no references to it from JS, so
1633 : // we don't have to move it.
1634 0 : if (!wn->IsWrapperExpired())
1635 0 : array->AppendElement(wn);
1636 0 : return JS_DHASH_NEXT;
1637 : }
1638 :
1639 : static nsresult
1640 0 : MoveWrapper(XPCCallContext& ccx, XPCWrappedNative *wrapper,
1641 : XPCWrappedNativeScope *newScope, XPCWrappedNativeScope *oldScope)
1642 : {
1643 : // First, check to see if this wrapper really needs to be
1644 : // reparented.
1645 :
1646 0 : if (wrapper->GetScope() == newScope) {
1647 : // The wrapper already got moved, nothing to do here.
1648 0 : return NS_OK;
1649 : }
1650 :
1651 0 : nsISupports *identity = wrapper->GetIdentityObject();
1652 0 : nsCOMPtr<nsIClassInfo> info(do_QueryInterface(identity));
1653 :
1654 : // ClassInfo is implemented as singleton objects. If the identity
1655 : // object here is the same object as returned by the QI, then it
1656 : // is the singleton classinfo, so we don't need to reparent it.
1657 0 : if (SameCOMIdentity(identity, info))
1658 0 : info = nsnull;
1659 :
1660 0 : if (!info)
1661 0 : return NS_OK;
1662 :
1663 0 : XPCNativeScriptableCreateInfo sciProto;
1664 0 : XPCNativeScriptableCreateInfo sci;
1665 : const XPCNativeScriptableCreateInfo& sciWrapper =
1666 : XPCWrappedNative::GatherScriptableCreateInfo(identity, info,
1667 0 : sciProto, sci);
1668 :
1669 : // If the wrapper doesn't want precreate, then we don't need to
1670 : // worry about reparenting it.
1671 0 : if (!sciWrapper.GetFlags().WantPreCreate())
1672 0 : return NS_OK;
1673 :
1674 0 : JSObject *newParent = oldScope->GetGlobalJSObject();
1675 0 : nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
1676 : newParent,
1677 0 : &newParent);
1678 0 : if (NS_FAILED(rv))
1679 0 : return rv;
1680 :
1681 0 : if (newParent == oldScope->GetGlobalJSObject()) {
1682 : // The old scope still works for this wrapper. We have to
1683 : // assume that the wrapper will continue to return the old
1684 : // scope from PreCreate, so don't move it.
1685 0 : return NS_OK;
1686 : }
1687 :
1688 : // The wrapper returned a new parent. If the new parent is in a
1689 : // different scope, then we need to reparent it, otherwise, the
1690 : // old scope is fine.
1691 :
1692 : XPCWrappedNativeScope *betterScope =
1693 0 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, newParent);
1694 0 : if (betterScope == oldScope) {
1695 : // The wrapper asked for a different object, but that object
1696 : // was in the same scope. This means that the new parent
1697 : // simply hasn't been reparented yet, so reparent it first,
1698 : // and then continue reparenting the wrapper itself.
1699 :
1700 0 : if (!IS_WN_WRAPPER_OBJECT(newParent)) {
1701 : // The parent of wrapper is a slim wrapper, in this case
1702 : // we need to morph the parent so that we can reparent it.
1703 :
1704 0 : rv = MorphSlimWrapper(ccx, newParent);
1705 0 : NS_ENSURE_SUCCESS(rv, rv);
1706 : }
1707 :
1708 : XPCWrappedNative *parentWrapper =
1709 0 : XPCWrappedNative::GetWrappedNativeOfJSObject(ccx, newParent);
1710 :
1711 0 : rv = MoveWrapper(ccx, parentWrapper, newScope, oldScope);
1712 0 : NS_ENSURE_SUCCESS(rv, rv);
1713 :
1714 : // If the parent wanted to stay in the old scope, we have to stay with
1715 : // it. This can happen when doing document.write when the old detached
1716 : // about:blank document is still floating around in the scope. Leave it
1717 : // behind to die.
1718 0 : if (parentWrapper->GetScope() == oldScope)
1719 0 : return NS_OK;
1720 0 : NS_ASSERTION(parentWrapper->GetScope() == newScope,
1721 : "A _third_ scope? Oh dear...");
1722 :
1723 0 : newParent = parentWrapper->GetFlatJSObject();
1724 : } else
1725 0 : NS_ASSERTION(betterScope == newScope, "Weird scope returned");
1726 :
1727 : // Now, reparent the wrapper, since we know that it wants to be
1728 : // reparented.
1729 :
1730 0 : nsRefPtr<XPCWrappedNative> junk;
1731 : rv = XPCWrappedNative::ReparentWrapperIfFound(ccx, oldScope,
1732 : newScope, newParent,
1733 : wrapper->GetIdentityObject(),
1734 0 : getter_AddRefs(junk));
1735 0 : return rv;
1736 : }
1737 :
1738 : /* void moveWrappers(in JSContextPtr aJSContext, in JSObjectPtr aOldScope, in JSObjectPtr aNewScope); */
1739 : NS_IMETHODIMP
1740 0 : nsXPConnect::MoveWrappers(JSContext *aJSContext,
1741 : JSObject *aOldScope,
1742 : JSObject *aNewScope)
1743 : {
1744 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1745 0 : if (!ccx.IsValid())
1746 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1747 :
1748 : XPCWrappedNativeScope *oldScope =
1749 0 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, aOldScope);
1750 0 : if (!oldScope)
1751 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1752 :
1753 : XPCWrappedNativeScope *newScope =
1754 0 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, aNewScope);
1755 0 : if (!newScope)
1756 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1757 :
1758 : // First, look through the old scope and find all of the wrappers that
1759 : // we're going to move.
1760 0 : nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
1761 :
1762 : { // scoped lock
1763 0 : XPCAutoLock lock(GetRuntime()->GetMapLock());
1764 0 : Native2WrappedNativeMap *map = oldScope->GetWrappedNativeMap();
1765 0 : wrappersToMove.SetCapacity(map->Count());
1766 0 : map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
1767 : }
1768 :
1769 : // Now that we have the wrappers, reparent them to the new scope.
1770 0 : for (PRUint32 i = 0, stop = wrappersToMove.Length(); i < stop; ++i) {
1771 0 : nsresult rv = MoveWrapper(ccx, wrappersToMove[i], newScope, oldScope);
1772 0 : NS_ENSURE_SUCCESS(rv, rv);
1773 : }
1774 :
1775 0 : return NS_OK;
1776 : }
1777 :
1778 : /* void setSecurityManagerForJSContext (in JSContextPtr aJSContext, in nsIXPCSecurityManager aManager, in PRUint16 flags); */
1779 : NS_IMETHODIMP
1780 1387 : nsXPConnect::SetSecurityManagerForJSContext(JSContext * aJSContext,
1781 : nsIXPCSecurityManager *aManager,
1782 : PRUint16 flags)
1783 : {
1784 1387 : NS_ASSERTION(aJSContext, "bad param");
1785 :
1786 2774 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1787 1387 : if (!ccx.IsValid())
1788 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1789 :
1790 1387 : XPCContext* xpcc = ccx.GetXPCContext();
1791 :
1792 1387 : NS_IF_ADDREF(aManager);
1793 1387 : nsIXPCSecurityManager* oldManager = xpcc->GetSecurityManager();
1794 1387 : NS_IF_RELEASE(oldManager);
1795 :
1796 1387 : xpcc->SetSecurityManager(aManager);
1797 1387 : xpcc->SetSecurityManagerFlags(flags);
1798 1387 : return NS_OK;
1799 : }
1800 :
1801 : /* void getSecurityManagerForJSContext (in JSContextPtr aJSContext, out nsIXPCSecurityManager aManager, out PRUint16 flags); */
1802 : NS_IMETHODIMP
1803 0 : nsXPConnect::GetSecurityManagerForJSContext(JSContext * aJSContext,
1804 : nsIXPCSecurityManager **aManager,
1805 : PRUint16 *flags)
1806 : {
1807 0 : NS_ASSERTION(aJSContext, "bad param");
1808 0 : NS_ASSERTION(aManager, "bad param");
1809 0 : NS_ASSERTION(flags, "bad param");
1810 :
1811 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
1812 0 : if (!ccx.IsValid())
1813 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1814 :
1815 0 : XPCContext* xpcc = ccx.GetXPCContext();
1816 :
1817 0 : nsIXPCSecurityManager* manager = xpcc->GetSecurityManager();
1818 0 : NS_IF_ADDREF(manager);
1819 0 : *aManager = manager;
1820 0 : *flags = xpcc->GetSecurityManagerFlags();
1821 0 : return NS_OK;
1822 : }
1823 :
1824 : /* void setDefaultSecurityManager (in nsIXPCSecurityManager aManager, in PRUint16 flags); */
1825 : NS_IMETHODIMP
1826 1404 : nsXPConnect::SetDefaultSecurityManager(nsIXPCSecurityManager *aManager,
1827 : PRUint16 flags)
1828 : {
1829 1404 : NS_IF_ADDREF(aManager);
1830 1404 : NS_IF_RELEASE(mDefaultSecurityManager);
1831 1404 : mDefaultSecurityManager = aManager;
1832 1404 : mDefaultSecurityManagerFlags = flags;
1833 :
1834 : nsCOMPtr<nsIScriptSecurityManager> ssm =
1835 2808 : do_QueryInterface(mDefaultSecurityManager);
1836 :
1837 : // Remember the result of the above QI for fast access to the
1838 : // script securityt manager.
1839 1404 : gScriptSecurityManager = ssm;
1840 :
1841 1404 : return NS_OK;
1842 : }
1843 :
1844 : /* void getDefaultSecurityManager (out nsIXPCSecurityManager aManager, out PRUint16 flags); */
1845 : NS_IMETHODIMP
1846 0 : nsXPConnect::GetDefaultSecurityManager(nsIXPCSecurityManager **aManager,
1847 : PRUint16 *flags)
1848 : {
1849 0 : NS_ASSERTION(aManager, "bad param");
1850 0 : NS_ASSERTION(flags, "bad param");
1851 :
1852 0 : NS_IF_ADDREF(mDefaultSecurityManager);
1853 0 : *aManager = mDefaultSecurityManager;
1854 0 : *flags = mDefaultSecurityManagerFlags;
1855 0 : return NS_OK;
1856 : }
1857 :
1858 : /* nsIStackFrame createStackFrameLocation (in PRUint32 aLanguage, in string aFilename, in string aFunctionName, in PRInt32 aLineNumber, in nsIStackFrame aCaller); */
1859 : NS_IMETHODIMP
1860 0 : nsXPConnect::CreateStackFrameLocation(PRUint32 aLanguage,
1861 : const char *aFilename,
1862 : const char *aFunctionName,
1863 : PRInt32 aLineNumber,
1864 : nsIStackFrame *aCaller,
1865 : nsIStackFrame **_retval)
1866 : {
1867 0 : NS_ASSERTION(_retval, "bad param");
1868 :
1869 : return XPCJSStack::CreateStackFrameLocation(aLanguage,
1870 : aFilename,
1871 : aFunctionName,
1872 : aLineNumber,
1873 : aCaller,
1874 0 : _retval);
1875 : }
1876 :
1877 : /* readonly attribute nsIStackFrame CurrentJSStack; */
1878 : NS_IMETHODIMP
1879 206181 : nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack)
1880 : {
1881 206181 : NS_ASSERTION(aCurrentJSStack, "bad param");
1882 206181 : *aCurrentJSStack = nsnull;
1883 :
1884 : JSContext* cx;
1885 : // is there a current context available?
1886 206181 : if (NS_SUCCEEDED(Peek(&cx)) && cx) {
1887 412362 : nsCOMPtr<nsIStackFrame> stack;
1888 206181 : XPCJSStack::CreateStack(cx, getter_AddRefs(stack));
1889 206181 : if (stack) {
1890 : // peel off native frames...
1891 : PRUint32 language;
1892 394430 : nsCOMPtr<nsIStackFrame> caller;
1893 986126 : while (stack &&
1894 394430 : NS_SUCCEEDED(stack->GetLanguage(&language)) &&
1895 : language != nsIProgrammingLanguage::JAVASCRIPT &&
1896 197249 : NS_SUCCEEDED(stack->GetCaller(getter_AddRefs(caller))) &&
1897 17 : caller) {
1898 0 : stack = caller;
1899 : }
1900 197215 : NS_IF_ADDREF(*aCurrentJSStack = stack);
1901 : }
1902 : }
1903 206181 : return NS_OK;
1904 : }
1905 :
1906 : /* readonly attribute nsIXPCNativeCallContext CurrentNativeCallContext; */
1907 : NS_IMETHODIMP
1908 211895 : nsXPConnect::GetCurrentNativeCallContext(nsAXPCNativeCallContext * *aCurrentNativeCallContext)
1909 : {
1910 211895 : NS_ASSERTION(aCurrentNativeCallContext, "bad param");
1911 :
1912 211895 : XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
1913 211895 : if (data) {
1914 211895 : *aCurrentNativeCallContext = data->GetCallContext();
1915 211895 : return NS_OK;
1916 : }
1917 : //else...
1918 0 : *aCurrentNativeCallContext = nsnull;
1919 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1920 : }
1921 :
1922 : /* attribute nsIException PendingException; */
1923 : NS_IMETHODIMP
1924 38278 : nsXPConnect::GetPendingException(nsIException * *aPendingException)
1925 : {
1926 38278 : NS_ASSERTION(aPendingException, "bad param");
1927 :
1928 38278 : XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
1929 38278 : if (!data) {
1930 0 : *aPendingException = nsnull;
1931 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1932 : }
1933 :
1934 38278 : return data->GetException(aPendingException);
1935 : }
1936 :
1937 : NS_IMETHODIMP
1938 261 : nsXPConnect::SetPendingException(nsIException * aPendingException)
1939 : {
1940 261 : XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
1941 261 : if (!data)
1942 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
1943 :
1944 261 : data->SetException(aPendingException);
1945 261 : return NS_OK;
1946 : }
1947 :
1948 : NS_IMETHODIMP
1949 0 : nsXPConnect::SyncJSContexts(void)
1950 : {
1951 : // Do-nothing compatibility function
1952 0 : return NS_OK;
1953 : }
1954 :
1955 : /* nsIXPCFunctionThisTranslator setFunctionThisTranslator (in nsIIDRef aIID, in nsIXPCFunctionThisTranslator aTranslator); */
1956 : NS_IMETHODIMP
1957 306 : nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
1958 : nsIXPCFunctionThisTranslator *aTranslator,
1959 : nsIXPCFunctionThisTranslator **_retval)
1960 : {
1961 306 : XPCJSRuntime* rt = GetRuntime();
1962 : nsIXPCFunctionThisTranslator* old;
1963 306 : IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
1964 :
1965 : {
1966 612 : XPCAutoLock lock(rt->GetMapLock()); // scoped lock
1967 306 : if (_retval) {
1968 306 : old = map->Find(aIID);
1969 306 : NS_IF_ADDREF(old);
1970 306 : *_retval = old;
1971 : }
1972 306 : map->Add(aIID, aTranslator);
1973 : }
1974 306 : return NS_OK;
1975 : }
1976 :
1977 : /* nsIXPCFunctionThisTranslator getFunctionThisTranslator (in nsIIDRef aIID); */
1978 : NS_IMETHODIMP
1979 0 : nsXPConnect::GetFunctionThisTranslator(const nsIID & aIID,
1980 : nsIXPCFunctionThisTranslator **_retval)
1981 : {
1982 0 : XPCJSRuntime* rt = GetRuntime();
1983 : nsIXPCFunctionThisTranslator* old;
1984 0 : IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
1985 :
1986 : {
1987 0 : XPCAutoLock lock(rt->GetMapLock()); // scoped lock
1988 0 : old = map->Find(aIID);
1989 0 : NS_IF_ADDREF(old);
1990 0 : *_retval = old;
1991 : }
1992 0 : return NS_OK;
1993 : }
1994 :
1995 : /* void clearAllWrappedNativeSecurityPolicies (); */
1996 : NS_IMETHODIMP
1997 1 : nsXPConnect::ClearAllWrappedNativeSecurityPolicies()
1998 : {
1999 2 : XPCCallContext ccx(NATIVE_CALLER);
2000 1 : if (!ccx.IsValid())
2001 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2002 :
2003 1 : return XPCWrappedNativeScope::ClearAllWrappedNativeSecurityPolicies(ccx);
2004 : }
2005 :
2006 : NS_IMETHODIMP
2007 0 : nsXPConnect::CreateSandbox(JSContext *cx, nsIPrincipal *principal,
2008 : nsIXPConnectJSObjectHolder **_retval)
2009 : {
2010 0 : XPCCallContext ccx(NATIVE_CALLER, cx);
2011 0 : if (!ccx.IsValid())
2012 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2013 :
2014 0 : *_retval = nsnull;
2015 :
2016 0 : jsval rval = JSVAL_VOID;
2017 0 : AUTO_MARK_JSVAL(ccx, &rval);
2018 :
2019 : nsresult rv = xpc_CreateSandboxObject(cx, &rval, principal, NULL, false,
2020 0 : EmptyCString());
2021 0 : NS_ASSERTION(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval),
2022 : "Bad return value from xpc_CreateSandboxObject()!");
2023 :
2024 0 : if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(rval)) {
2025 0 : *_retval = XPCJSObjectHolder::newHolder(ccx, JSVAL_TO_OBJECT(rval));
2026 0 : NS_ENSURE_TRUE(*_retval, NS_ERROR_OUT_OF_MEMORY);
2027 :
2028 0 : NS_ADDREF(*_retval);
2029 : }
2030 :
2031 0 : return rv;
2032 : }
2033 :
2034 : NS_IMETHODIMP
2035 0 : nsXPConnect::EvalInSandboxObject(const nsAString& source, JSContext *cx,
2036 : nsIXPConnectJSObjectHolder *sandbox,
2037 : bool returnStringOnly, jsval *rval)
2038 : {
2039 0 : if (!sandbox)
2040 0 : return NS_ERROR_INVALID_ARG;
2041 :
2042 : JSObject *obj;
2043 0 : nsresult rv = sandbox->GetJSObject(&obj);
2044 0 : NS_ENSURE_SUCCESS(rv, rv);
2045 :
2046 : return xpc_EvalInSandbox(cx, obj, source,
2047 0 : NS_ConvertUTF16toUTF8(source).get(), 1,
2048 0 : JSVERSION_DEFAULT, returnStringOnly, rval);
2049 : }
2050 :
2051 : /* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */
2052 : NS_IMETHODIMP
2053 0 : nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,
2054 : JSObject * aScope,
2055 : nsIClassInfo *aClassInfo,
2056 : nsIXPConnectJSObjectHolder **_retval)
2057 : {
2058 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
2059 0 : if (!ccx.IsValid())
2060 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2061 :
2062 0 : JSAutoEnterCompartment ac;
2063 0 : if (!ac.enter(aJSContext, aScope))
2064 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2065 :
2066 : XPCWrappedNativeScope* scope =
2067 0 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
2068 0 : if (!scope)
2069 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2070 :
2071 0 : XPCNativeScriptableCreateInfo sciProto;
2072 0 : XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
2073 :
2074 0 : AutoMarkingWrappedNativeProtoPtr proto(ccx);
2075 0 : proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo, &sciProto);
2076 0 : if (!proto)
2077 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2078 :
2079 : nsIXPConnectJSObjectHolder* holder;
2080 : *_retval = holder = XPCJSObjectHolder::newHolder(ccx,
2081 0 : proto->GetJSProtoObject());
2082 0 : if (!holder)
2083 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2084 :
2085 0 : NS_ADDREF(holder);
2086 0 : return NS_OK;
2087 : }
2088 :
2089 : /* void releaseJSContext (in JSContextPtr aJSContext, in bool noGC); */
2090 : NS_IMETHODIMP
2091 0 : nsXPConnect::ReleaseJSContext(JSContext * aJSContext, bool noGC)
2092 : {
2093 0 : NS_ASSERTION(aJSContext, "bad param");
2094 0 : XPCPerThreadData* tls = XPCPerThreadData::GetData(aJSContext);
2095 0 : if (tls) {
2096 0 : XPCCallContext* ccx = nsnull;
2097 0 : for (XPCCallContext* cur = tls->GetCallContext();
2098 : cur;
2099 : cur = cur->GetPrevCallContext()) {
2100 0 : if (cur->GetJSContext() == aJSContext) {
2101 0 : ccx = cur;
2102 : // Keep looping to find the deepest matching call context.
2103 : }
2104 : }
2105 :
2106 0 : if (ccx) {
2107 : #ifdef DEBUG_xpc_hacker
2108 : printf("!xpc - deferring destruction of JSContext @ %p\n",
2109 : (void *)aJSContext);
2110 : #endif
2111 0 : ccx->SetDestroyJSContextInDestructor(true);
2112 0 : return NS_OK;
2113 : }
2114 : // else continue on and synchronously destroy the JSContext ...
2115 :
2116 0 : NS_ASSERTION(!tls->GetJSContextStack() ||
2117 : !tls->GetJSContextStack()->
2118 : DEBUG_StackHasJSContext(aJSContext),
2119 : "JSContext still in threadjscontextstack!");
2120 : }
2121 :
2122 0 : if (noGC)
2123 0 : JS_DestroyContextNoGC(aJSContext);
2124 : else
2125 0 : JS_DestroyContext(aJSContext);
2126 0 : return NS_OK;
2127 : }
2128 :
2129 : /* void debugDump (in short depth); */
2130 : NS_IMETHODIMP
2131 0 : nsXPConnect::DebugDump(PRInt16 depth)
2132 : {
2133 : #ifdef DEBUG
2134 0 : depth-- ;
2135 0 : XPC_LOG_ALWAYS(("nsXPConnect @ %x with mRefCnt = %d", this, mRefCnt.get()));
2136 0 : XPC_LOG_INDENT();
2137 0 : XPC_LOG_ALWAYS(("gSelf @ %x", gSelf));
2138 0 : XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead));
2139 0 : XPC_LOG_ALWAYS(("mDefaultSecurityManager @ %x", mDefaultSecurityManager));
2140 0 : XPC_LOG_ALWAYS(("mDefaultSecurityManagerFlags of %x", mDefaultSecurityManagerFlags));
2141 0 : XPC_LOG_ALWAYS(("mInterfaceInfoManager @ %x", mInterfaceInfoManager.get()));
2142 0 : if (mRuntime) {
2143 0 : if (depth)
2144 0 : mRuntime->DebugDump(depth);
2145 : else
2146 0 : XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", mRuntime));
2147 : } else
2148 0 : XPC_LOG_ALWAYS(("mRuntime is null"));
2149 0 : XPCWrappedNativeScope::DebugDumpAllScopes(depth);
2150 0 : XPC_LOG_OUTDENT();
2151 : #endif
2152 0 : return NS_OK;
2153 : }
2154 :
2155 : /* void debugDumpObject (in nsISupports aCOMObj, in short depth); */
2156 : NS_IMETHODIMP
2157 0 : nsXPConnect::DebugDumpObject(nsISupports *p, PRInt16 depth)
2158 : {
2159 : #ifdef DEBUG
2160 0 : if (!depth)
2161 0 : return NS_OK;
2162 0 : if (!p) {
2163 0 : XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address"));
2164 0 : return NS_OK;
2165 : }
2166 :
2167 : nsIXPConnect* xpc;
2168 : nsIXPCWrappedJSClass* wjsc;
2169 : nsIXPConnectWrappedNative* wn;
2170 : nsIXPConnectWrappedJS* wjs;
2171 :
2172 0 : if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnect),
2173 : (void**)&xpc))) {
2174 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPConnect..."));
2175 0 : xpc->DebugDump(depth);
2176 0 : NS_RELEASE(xpc);
2177 0 : } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPCWrappedJSClass),
2178 : (void**)&wjsc))) {
2179 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPCWrappedJSClass..."));
2180 0 : wjsc->DebugDump(depth);
2181 0 : NS_RELEASE(wjsc);
2182 0 : } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedNative),
2183 : (void**)&wn))) {
2184 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative..."));
2185 0 : wn->DebugDump(depth);
2186 0 : NS_RELEASE(wn);
2187 0 : } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedJS),
2188 : (void**)&wjs))) {
2189 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS..."));
2190 0 : wjs->DebugDump(depth);
2191 0 : NS_RELEASE(wjs);
2192 : } else
2193 0 : XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %x", p));
2194 : #endif
2195 0 : return NS_OK;
2196 : }
2197 :
2198 : /* void debugDumpJSStack (in bool showArgs, in bool showLocals, in bool showThisProps); */
2199 : NS_IMETHODIMP
2200 0 : nsXPConnect::DebugDumpJSStack(bool showArgs,
2201 : bool showLocals,
2202 : bool showThisProps)
2203 : {
2204 : JSContext* cx;
2205 0 : if (NS_FAILED(Peek(&cx)))
2206 0 : printf("failed to peek into nsIThreadJSContextStack service!\n");
2207 0 : else if (!cx)
2208 0 : printf("there is no JSContext on the nsIThreadJSContextStack!\n");
2209 : else
2210 0 : xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps);
2211 :
2212 0 : return NS_OK;
2213 : }
2214 :
2215 : char*
2216 0 : nsXPConnect::DebugPrintJSStack(bool showArgs,
2217 : bool showLocals,
2218 : bool showThisProps)
2219 : {
2220 : JSContext* cx;
2221 0 : if (NS_FAILED(Peek(&cx)))
2222 0 : printf("failed to peek into nsIThreadJSContextStack service!\n");
2223 0 : else if (!cx)
2224 0 : printf("there is no JSContext on the nsIThreadJSContextStack!\n");
2225 : else
2226 0 : return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps);
2227 :
2228 0 : return nsnull;
2229 : }
2230 :
2231 : /* void debugDumpEvalInJSStackFrame (in PRUint32 aFrameNumber, in string aSourceText); */
2232 : NS_IMETHODIMP
2233 0 : nsXPConnect::DebugDumpEvalInJSStackFrame(PRUint32 aFrameNumber, const char *aSourceText)
2234 : {
2235 : JSContext* cx;
2236 0 : if (NS_FAILED(Peek(&cx)))
2237 0 : printf("failed to peek into nsIThreadJSContextStack service!\n");
2238 0 : else if (!cx)
2239 0 : printf("there is no JSContext on the nsIThreadJSContextStack!\n");
2240 : else
2241 0 : xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText);
2242 :
2243 0 : return NS_OK;
2244 : }
2245 :
2246 : /* jsval variantToJS (in JSContextPtr ctx, in JSObjectPtr scope, in nsIVariant value); */
2247 : NS_IMETHODIMP
2248 0 : nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scope, nsIVariant* value, jsval* _retval)
2249 : {
2250 0 : NS_PRECONDITION(ctx, "bad param");
2251 0 : NS_PRECONDITION(scope, "bad param");
2252 0 : NS_PRECONDITION(value, "bad param");
2253 0 : NS_PRECONDITION(_retval, "bad param");
2254 :
2255 0 : XPCCallContext ccx(NATIVE_CALLER, ctx);
2256 0 : if (!ccx.IsValid())
2257 0 : return NS_ERROR_FAILURE;
2258 0 : XPCLazyCallContext lccx(ccx);
2259 :
2260 0 : ccx.SetScopeForNewJSObjects(scope);
2261 :
2262 0 : nsresult rv = NS_OK;
2263 0 : if (!XPCVariant::VariantDataToJS(lccx, value, &rv, _retval)) {
2264 0 : if (NS_FAILED(rv))
2265 0 : return rv;
2266 :
2267 0 : return NS_ERROR_FAILURE;
2268 : }
2269 :
2270 0 : return NS_OK;
2271 : }
2272 :
2273 : /* nsIVariant JSToVariant (in JSContextPtr ctx, in jsval value); */
2274 : NS_IMETHODIMP
2275 0 : nsXPConnect::JSToVariant(JSContext* ctx, const jsval &value, nsIVariant** _retval)
2276 : {
2277 0 : NS_PRECONDITION(ctx, "bad param");
2278 0 : NS_PRECONDITION(value != JSVAL_NULL, "bad param");
2279 0 : NS_PRECONDITION(_retval, "bad param");
2280 :
2281 0 : XPCCallContext ccx(NATIVE_CALLER, ctx);
2282 0 : if (!ccx.IsValid())
2283 0 : return NS_ERROR_FAILURE;
2284 :
2285 0 : *_retval = XPCVariant::newVariant(ccx, value);
2286 0 : if (!(*_retval))
2287 0 : return NS_ERROR_FAILURE;
2288 :
2289 0 : return NS_OK;
2290 : }
2291 :
2292 : NS_IMETHODIMP
2293 174528 : nsXPConnect::OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait,
2294 : PRUint32 aRecursionDepth)
2295 : {
2296 : // Record this event.
2297 174528 : mEventDepth++;
2298 :
2299 : // Push a null JSContext so that we don't see any script during
2300 : // event processing.
2301 174528 : MOZ_ASSERT(NS_IsMainThread());
2302 174528 : return Push(nsnull);
2303 : }
2304 :
2305 : NS_IMETHODIMP
2306 174530 : nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread,
2307 : PRUint32 aRecursionDepth)
2308 : {
2309 : // Watch out for unpaired events during observer registration.
2310 174530 : if (NS_UNLIKELY(mEventDepth == 0))
2311 2 : return NS_OK;
2312 174528 : mEventDepth--;
2313 :
2314 : // Call cycle collector occasionally.
2315 174528 : MOZ_ASSERT(NS_IsMainThread());
2316 174528 : nsJSContext::MaybePokeCC();
2317 :
2318 174528 : return Pop(nsnull);
2319 : }
2320 :
2321 : NS_IMETHODIMP
2322 0 : nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
2323 : {
2324 0 : NS_NOTREACHED("Why tell us?");
2325 0 : return NS_ERROR_UNEXPECTED;
2326 : }
2327 :
2328 : NS_IMETHODIMP
2329 7458 : nsXPConnect::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer)
2330 : {
2331 7458 : return mRuntime->AddJSHolder(aHolder, aTracer);
2332 : }
2333 :
2334 : NS_IMETHODIMP
2335 7456 : nsXPConnect::RemoveJSHolder(void* aHolder)
2336 : {
2337 7456 : return mRuntime->RemoveJSHolder(aHolder);
2338 : }
2339 :
2340 : NS_IMETHODIMP
2341 50 : nsXPConnect::SetReportAllJSExceptions(bool newval)
2342 : {
2343 : // Ignore if the environment variable was set.
2344 50 : if (gReportAllJSExceptions != 1)
2345 50 : gReportAllJSExceptions = newval ? 2 : 0;
2346 :
2347 50 : return NS_OK;
2348 : }
2349 :
2350 : /* [noscript, notxpcom] bool defineDOMQuickStubs (in JSContextPtr cx, in JSObjectPtr proto, in PRUint32 flags, in PRUint32 interfaceCount, [array, size_is (interfaceCount)] in nsIIDPtr interfaceArray); */
2351 : NS_IMETHODIMP_(bool)
2352 2781 : nsXPConnect::DefineDOMQuickStubs(JSContext * cx,
2353 : JSObject * proto,
2354 : PRUint32 flags,
2355 : PRUint32 interfaceCount,
2356 : const nsIID * *interfaceArray)
2357 : {
2358 : return DOM_DefineQuickStubs(cx, proto, flags,
2359 2781 : interfaceCount, interfaceArray);
2360 : }
2361 :
2362 : /* attribute JSRuntime runtime; */
2363 : NS_IMETHODIMP
2364 3806 : nsXPConnect::GetRuntime(JSRuntime **runtime)
2365 : {
2366 3806 : if (!runtime)
2367 0 : return NS_ERROR_NULL_POINTER;
2368 :
2369 3806 : JSRuntime *rt = GetRuntime()->GetJSRuntime();
2370 3806 : JS_AbortIfWrongThread(rt);
2371 3806 : *runtime = rt;
2372 3806 : return NS_OK;
2373 : }
2374 :
2375 : /* attribute nsIXPCScriptable backstagePass; */
2376 : NS_IMETHODIMP
2377 13217 : nsXPConnect::GetBackstagePass(nsIXPCScriptable **bsp)
2378 : {
2379 13217 : if (!mBackstagePass) {
2380 2782 : nsCOMPtr<nsIPrincipal> sysprin;
2381 : nsCOMPtr<nsIScriptSecurityManager> secman =
2382 2782 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
2383 1391 : if (!secman)
2384 0 : return NS_ERROR_NOT_AVAILABLE;
2385 1391 : if (NS_FAILED(secman->GetSystemPrincipal(getter_AddRefs(sysprin))))
2386 0 : return NS_ERROR_NOT_AVAILABLE;
2387 :
2388 2782 : mBackstagePass = new BackstagePass(sysprin);
2389 1391 : if (!mBackstagePass)
2390 0 : return NS_ERROR_OUT_OF_MEMORY;
2391 : }
2392 13217 : NS_ADDREF(*bsp = mBackstagePass);
2393 13217 : return NS_OK;
2394 : }
2395 :
2396 : /* [noscript, notxpcom] void registerGCCallback(in JSGCCallback func); */
2397 : NS_IMETHODIMP_(void)
2398 0 : nsXPConnect::RegisterGCCallback(JSGCCallback func)
2399 : {
2400 0 : mRuntime->AddGCCallback(func);
2401 0 : }
2402 :
2403 : /* [noscript, notxpcom] void unregisterGCCallback(in JSGCCallback func); */
2404 : NS_IMETHODIMP_(void)
2405 0 : nsXPConnect::UnregisterGCCallback(JSGCCallback func)
2406 : {
2407 0 : mRuntime->RemoveGCCallback(func);
2408 0 : }
2409 :
2410 : // nsIJSContextStack and nsIThreadJSContextStack implementations
2411 :
2412 : /* readonly attribute PRInt32 Count; */
2413 : NS_IMETHODIMP
2414 0 : nsXPConnect::GetCount(PRInt32 *aCount)
2415 : {
2416 0 : MOZ_ASSERT(aCount);
2417 :
2418 0 : XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
2419 :
2420 0 : if (!data) {
2421 0 : *aCount = 0;
2422 0 : return NS_ERROR_FAILURE;
2423 : }
2424 :
2425 0 : *aCount = data->GetJSContextStack()->Count();
2426 0 : return NS_OK;
2427 : }
2428 :
2429 : /* JSContext Peek (); */
2430 : NS_IMETHODIMP
2431 721373 : nsXPConnect::Peek(JSContext * *_retval)
2432 : {
2433 721373 : MOZ_ASSERT(_retval);
2434 :
2435 721373 : XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
2436 :
2437 721373 : if (!data) {
2438 0 : *_retval = nsnull;
2439 0 : return NS_ERROR_FAILURE;
2440 : }
2441 :
2442 721373 : *_retval = data->GetJSContextStack()->Peek();
2443 721373 : return NS_OK;
2444 : }
2445 :
2446 : void
2447 280 : nsXPConnect::CheckForDebugMode(JSRuntime *rt) {
2448 280 : JSContext *cx = NULL;
2449 :
2450 280 : if (gDebugMode == gDesiredDebugMode) {
2451 0 : return;
2452 : }
2453 :
2454 : // This can happen if a Worker is running, but we don't have the ability to
2455 : // debug workers right now, so just return.
2456 280 : if (!NS_IsMainThread()) {
2457 0 : return;
2458 : }
2459 :
2460 280 : JS_SetRuntimeDebugMode(rt, gDesiredDebugMode);
2461 :
2462 : nsresult rv;
2463 280 : const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
2464 560 : nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
2465 280 : if (NS_FAILED(rv)) {
2466 0 : goto fail;
2467 : }
2468 :
2469 280 : if (!(cx = JS_NewContext(rt, 256))) {
2470 0 : goto fail;
2471 : }
2472 :
2473 : {
2474 : struct AutoDestroyContext {
2475 : JSContext *cx;
2476 280 : AutoDestroyContext(JSContext *cx) : cx(cx) {}
2477 280 : ~AutoDestroyContext() { JS_DestroyContext(cx); }
2478 560 : } adc(cx);
2479 560 : JSAutoRequest ar(cx);
2480 :
2481 280 : const js::CompartmentVector &vector = js::GetRuntimeCompartments(rt);
2482 1120 : for (JSCompartment * const *p = vector.begin(); p != vector.end(); ++p) {
2483 840 : JSCompartment *comp = *p;
2484 840 : if (!JS_GetCompartmentPrincipals(comp)) {
2485 : /* Ignore special compartments (atoms, JSD compartments) */
2486 280 : continue;
2487 : }
2488 :
2489 560 : if (!JS_SetDebugModeForCompartment(cx, comp, gDesiredDebugMode))
2490 : goto fail;
2491 : }
2492 : }
2493 :
2494 280 : if (gDesiredDebugMode) {
2495 280 : rv = jsds->ActivateDebugger(rt);
2496 : }
2497 :
2498 280 : gDebugMode = gDesiredDebugMode;
2499 : return;
2500 :
2501 : fail:
2502 0 : if (jsds)
2503 0 : jsds->DeactivateDebugger();
2504 :
2505 : /*
2506 : * If an attempt to turn debug mode on fails, cancel the request. It's
2507 : * always safe to turn debug mode off, since DeactivateDebugger prevents
2508 : * debugger callbacks from having any effect.
2509 : */
2510 0 : if (gDesiredDebugMode)
2511 0 : JS_SetRuntimeDebugMode(rt, false);
2512 0 : gDesiredDebugMode = gDebugMode = false;
2513 : }
2514 :
2515 : NS_EXPORT_(void)
2516 280 : xpc_ActivateDebugMode()
2517 : {
2518 280 : XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
2519 280 : nsXPConnect::GetXPConnect()->SetDebugModeWhenPossible(true, true);
2520 280 : nsXPConnect::CheckForDebugMode(rt->GetJSRuntime());
2521 280 : }
2522 :
2523 : /* JSContext Pop (); */
2524 : NS_IMETHODIMP
2525 239307 : nsXPConnect::Pop(JSContext * *_retval)
2526 : {
2527 239307 : XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
2528 :
2529 239307 : if (!data) {
2530 0 : if (_retval)
2531 0 : *_retval = NULL;
2532 0 : return NS_ERROR_FAILURE;
2533 : }
2534 :
2535 239307 : JSContext *cx = data->GetJSContextStack()->Pop();
2536 239307 : if (_retval)
2537 3119 : *_retval = cx;
2538 239307 : return NS_OK;
2539 : }
2540 :
2541 : /* void Push (in JSContext cx); */
2542 : NS_IMETHODIMP
2543 239307 : nsXPConnect::Push(JSContext * cx)
2544 : {
2545 239307 : XPCPerThreadData* data = XPCPerThreadData::GetData(cx);
2546 :
2547 239307 : if (!data)
2548 0 : return NS_ERROR_FAILURE;
2549 :
2550 239307 : if (gDebugMode != gDesiredDebugMode && NS_IsMainThread()) {
2551 0 : const InfallibleTArray<XPCJSContextInfo>* stack = data->GetJSContextStack()->GetStack();
2552 0 : if (!gDesiredDebugMode) {
2553 : /* Turn off debug mode immediately, even if JS code is currently running */
2554 0 : CheckForDebugMode(mRuntime->GetJSRuntime());
2555 : } else {
2556 0 : bool runningJS = false;
2557 0 : for (PRUint32 i = 0; i < stack->Length(); ++i) {
2558 0 : JSContext *cx = (*stack)[i].cx;
2559 0 : if (cx && js::IsContextRunningJS(cx)) {
2560 0 : runningJS = true;
2561 0 : break;
2562 : }
2563 : }
2564 0 : if (!runningJS)
2565 0 : CheckForDebugMode(mRuntime->GetJSRuntime());
2566 : }
2567 : }
2568 :
2569 239307 : return data->GetJSContextStack()->Push(cx) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
2570 : }
2571 :
2572 : /* attribute JSContext SafeJSContext; */
2573 : NS_IMETHODIMP
2574 5922 : nsXPConnect::GetSafeJSContext(JSContext * *aSafeJSContext)
2575 : {
2576 5922 : NS_ASSERTION(aSafeJSContext, "loser!");
2577 :
2578 5922 : XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
2579 :
2580 5922 : if (!data) {
2581 0 : *aSafeJSContext = nsnull;
2582 0 : return NS_ERROR_FAILURE;
2583 : }
2584 :
2585 5922 : *aSafeJSContext = data->GetJSContextStack()->GetSafeJSContext();
2586 5922 : return *aSafeJSContext ? NS_OK : NS_ERROR_FAILURE;
2587 : }
2588 :
2589 : nsIPrincipal*
2590 3735290 : nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const
2591 : {
2592 3735290 : NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)),
2593 : "What kind of wrapper is this?");
2594 :
2595 3735290 : if (IS_WN_WRAPPER_OBJECT(obj)) {
2596 : XPCWrappedNative *xpcWrapper =
2597 3735290 : (XPCWrappedNative *)xpc_GetJSPrivate(obj);
2598 3735290 : if (xpcWrapper) {
2599 3735290 : if (allowShortCircuit) {
2600 1867645 : nsIPrincipal *result = xpcWrapper->GetObjectPrincipal();
2601 1867645 : if (result) {
2602 1867645 : return result;
2603 : }
2604 : }
2605 :
2606 : // If not, check if it points to an nsIScriptObjectPrincipal
2607 : nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2608 3735290 : do_QueryInterface(xpcWrapper->Native());
2609 1867645 : if (objPrin) {
2610 1867645 : nsIPrincipal *result = objPrin->GetPrincipal();
2611 1867645 : if (result) {
2612 1867645 : return result;
2613 : }
2614 : }
2615 : }
2616 : } else {
2617 0 : if (allowShortCircuit) {
2618 : nsIPrincipal *result =
2619 0 : GetSlimWrapperProto(obj)->GetScope()->GetPrincipal();
2620 0 : if (result) {
2621 0 : return result;
2622 : }
2623 : }
2624 :
2625 : nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2626 0 : do_QueryInterface((nsISupports*)xpc_GetJSPrivate(obj));
2627 0 : if (objPrin) {
2628 0 : nsIPrincipal *result = objPrin->GetPrincipal();
2629 0 : if (result) {
2630 0 : return result;
2631 : }
2632 : }
2633 : }
2634 :
2635 0 : return nsnull;
2636 : }
2637 :
2638 : NS_IMETHODIMP
2639 0 : nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObject,
2640 : nsIXPConnectJSObjectHolder **aHolder)
2641 : {
2642 0 : XPCCallContext ccx(NATIVE_CALLER, aJSContext);
2643 0 : XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, aObject);
2644 0 : if (!objHolder)
2645 0 : return NS_ERROR_OUT_OF_MEMORY;
2646 :
2647 0 : NS_ADDREF(*aHolder = objHolder);
2648 0 : return NS_OK;
2649 : }
2650 :
2651 : NS_IMETHODIMP_(void)
2652 0 : nsXPConnect::GetCaller(JSContext **aJSContext, JSObject **aObj)
2653 : {
2654 0 : XPCCallContext *ccx = XPCPerThreadData::GetData(nsnull)->GetCallContext();
2655 0 : *aJSContext = ccx->GetJSContext();
2656 :
2657 : // Set to the caller in XPC_WN_Helper_{Call,Construct}
2658 0 : *aObj = ccx->GetFlattenedJSObject();
2659 0 : }
2660 :
2661 : namespace xpc {
2662 :
2663 : bool
2664 6763 : Base64Encode(JSContext *cx, JS::Value val, JS::Value *out)
2665 : {
2666 6763 : MOZ_ASSERT(cx);
2667 6763 : MOZ_ASSERT(out);
2668 :
2669 6763 : JS::Value root = val;
2670 : xpc_qsACString encodedString(cx, root, &root, xpc_qsACString::eNull,
2671 13526 : xpc_qsACString::eStringify);
2672 6763 : if (!encodedString.IsValid())
2673 0 : return false;
2674 :
2675 13526 : nsCAutoString result;
2676 6763 : if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
2677 0 : JS_ReportError(cx, "Failed to encode base64 data!");
2678 0 : return false;
2679 : }
2680 :
2681 6763 : JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
2682 6763 : if (!str)
2683 0 : return false;
2684 :
2685 6763 : *out = STRING_TO_JSVAL(str);
2686 6763 : return true;
2687 : }
2688 :
2689 : bool
2690 1070 : Base64Decode(JSContext *cx, JS::Value val, JS::Value *out)
2691 : {
2692 1070 : MOZ_ASSERT(cx);
2693 1070 : MOZ_ASSERT(out);
2694 :
2695 1070 : JS::Value root = val;
2696 : xpc_qsACString encodedString(cx, root, &root, xpc_qsACString::eNull,
2697 2140 : xpc_qsACString::eNull);
2698 1070 : if (!encodedString.IsValid())
2699 0 : return false;
2700 :
2701 2140 : nsCAutoString result;
2702 1070 : if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
2703 0 : JS_ReportError(cx, "Failed to decode base64 string!");
2704 0 : return false;
2705 : }
2706 :
2707 1070 : JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
2708 1070 : if (!str)
2709 0 : return false;
2710 :
2711 1070 : *out = STRING_TO_JSVAL(str);
2712 1070 : return true;
2713 : }
2714 :
2715 : #ifdef DEBUG
2716 : void
2717 0 : DumpJSHeap(FILE* file)
2718 : {
2719 0 : NS_ABORT_IF_FALSE(NS_IsMainThread(), "Must dump GC heap on main thread.");
2720 0 : nsXPConnect* xpc = nsXPConnect::GetXPConnect();
2721 0 : if (!xpc) {
2722 0 : NS_ERROR("Failed to get nsXPConnect instance!");
2723 0 : return;
2724 : }
2725 0 : js::DumpHeapComplete(xpc->GetRuntime()->GetJSRuntime(), file);
2726 : }
2727 : #endif
2728 :
2729 : } // namespace xpc
2730 :
2731 : NS_IMETHODIMP
2732 280 : nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable)
2733 : {
2734 280 : gDesiredDebugMode = mode;
2735 280 : if (!mode && allowSyncDisable)
2736 0 : CheckForDebugMode(mRuntime->GetJSRuntime());
2737 280 : return NS_OK;
2738 : }
2739 :
2740 : NS_IMETHODIMP
2741 3 : nsXPConnect::GetTelemetryValue(JSContext *cx, jsval *rval)
2742 : {
2743 3 : JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
2744 3 : if (!obj)
2745 0 : return NS_ERROR_OUT_OF_MEMORY;
2746 :
2747 3 : unsigned attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
2748 :
2749 3 : size_t i = JS_GetE4XObjectsCreated(cx);
2750 3 : jsval v = DOUBLE_TO_JSVAL(i);
2751 3 : if (!JS_DefineProperty(cx, obj, "e4x", v, NULL, NULL, attrs))
2752 0 : return NS_ERROR_OUT_OF_MEMORY;
2753 :
2754 3 : i = JS_SetProtoCalled(cx);
2755 3 : v = DOUBLE_TO_JSVAL(i);
2756 3 : if (!JS_DefineProperty(cx, obj, "setProto", v, NULL, NULL, attrs))
2757 0 : return NS_ERROR_OUT_OF_MEMORY;
2758 :
2759 3 : i = JS_GetCustomIteratorCount(cx);
2760 3 : v = DOUBLE_TO_JSVAL(i);
2761 3 : if (!JS_DefineProperty(cx, obj, "customIter", v, NULL, NULL, attrs))
2762 0 : return NS_ERROR_OUT_OF_MEMORY;
2763 :
2764 3 : *rval = OBJECT_TO_JSVAL(obj);
2765 3 : return NS_OK;
2766 : }
2767 :
2768 : NS_IMETHODIMP
2769 0 : nsXPConnect::NotifyDidPaint()
2770 : {
2771 0 : JSRuntime *rt = mRuntime->GetJSRuntime();
2772 0 : if (!js::WantGCSlice(rt))
2773 0 : return NS_OK;
2774 :
2775 0 : XPCCallContext ccx(NATIVE_CALLER);
2776 0 : if (!ccx.IsValid())
2777 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
2778 :
2779 0 : JSContext *cx = ccx.GetJSContext();
2780 :
2781 0 : js::NotifyDidPaint(cx);
2782 0 : return NS_OK;
2783 : }
2784 :
2785 : /* These are here to be callable from a debugger */
2786 : JS_BEGIN_EXTERN_C
2787 0 : JS_EXPORT_API(void) DumpJSStack()
2788 : {
2789 : nsresult rv;
2790 0 : nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
2791 0 : if (NS_SUCCEEDED(rv) && xpc)
2792 0 : xpc->DebugDumpJSStack(true, true, false);
2793 : else
2794 0 : printf("failed to get XPConnect service!\n");
2795 0 : }
2796 :
2797 0 : JS_EXPORT_API(char*) PrintJSStack()
2798 : {
2799 : nsresult rv;
2800 0 : nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
2801 0 : return (NS_SUCCEEDED(rv) && xpc) ?
2802 0 : xpc->DebugPrintJSStack(true, true, false) :
2803 0 : nsnull;
2804 : }
2805 :
2806 0 : JS_EXPORT_API(void) DumpJSEval(PRUint32 frameno, const char* text)
2807 : {
2808 : nsresult rv;
2809 0 : nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
2810 0 : if (NS_SUCCEEDED(rv) && xpc)
2811 0 : xpc->DebugDumpEvalInJSStackFrame(frameno, text);
2812 : else
2813 0 : printf("failed to get XPConnect service!\n");
2814 0 : }
2815 :
2816 0 : JS_EXPORT_API(void) DumpJSObject(JSObject* obj)
2817 : {
2818 0 : xpc_DumpJSObject(obj);
2819 0 : }
2820 :
2821 0 : JS_EXPORT_API(void) DumpJSValue(jsval val)
2822 : {
2823 0 : printf("Dumping 0x%llu.\n", (long long) JSVAL_TO_IMPL(val).asBits);
2824 0 : if (JSVAL_IS_NULL(val)) {
2825 0 : printf("Value is null\n");
2826 0 : } else if (JSVAL_IS_OBJECT(val) || JSVAL_IS_NULL(val)) {
2827 0 : printf("Value is an object\n");
2828 0 : JSObject* obj = JSVAL_TO_OBJECT(val);
2829 0 : DumpJSObject(obj);
2830 0 : } else if (JSVAL_IS_NUMBER(val)) {
2831 0 : printf("Value is a number: ");
2832 0 : if (JSVAL_IS_INT(val))
2833 0 : printf("Integer %i\n", JSVAL_TO_INT(val));
2834 0 : else if (JSVAL_IS_DOUBLE(val))
2835 0 : printf("Floating-point value %f\n", JSVAL_TO_DOUBLE(val));
2836 0 : } else if (JSVAL_IS_STRING(val)) {
2837 0 : printf("Value is a string: ");
2838 0 : putc('<', stdout);
2839 0 : JS_FileEscapedString(stdout, JSVAL_TO_STRING(val), 0);
2840 0 : fputs(">\n", stdout);
2841 0 : } else if (JSVAL_IS_BOOLEAN(val)) {
2842 0 : printf("Value is boolean: ");
2843 0 : printf(JSVAL_TO_BOOLEAN(val) ? "true" : "false");
2844 0 : } else if (JSVAL_IS_VOID(val)) {
2845 0 : printf("Value is undefined\n");
2846 : } else {
2847 0 : printf("No idea what this value is.\n");
2848 : }
2849 0 : }
2850 4392 : JS_END_EXTERN_C
2851 :
|