Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* High level class and public functions implementation. */
9 #include "mozilla/Assertions.h"
10 #include "mozilla/Base64.h"
11 #include "mozilla/Likely.h"
13 #include "xpcprivate.h"
14 #include "XPCWrapper.h"
15 #include "jsfriendapi.h"
16 #include "js/OldDebugAPI.h"
17 #include "nsJSEnvironment.h"
18 #include "nsThreadUtils.h"
19 #include "nsDOMJSUtils.h"
21 #include "WrapperFactory.h"
22 #include "AccessCheck.h"
24 #ifdef MOZ_JSDEBUGGER
25 #include "jsdIDebuggerService.h"
26 #endif
28 #include "XPCQuickStubs.h"
30 #include "mozilla/dom/BindingUtils.h"
31 #include "mozilla/dom/Exceptions.h"
32 #include "mozilla/dom/PromiseBinding.h"
33 #include "mozilla/dom/TextDecoderBinding.h"
34 #include "mozilla/dom/TextEncoderBinding.h"
35 #include "mozilla/dom/DOMErrorBinding.h"
37 #include "nsDOMMutationObserver.h"
38 #include "nsICycleCollectorListener.h"
39 #include "nsThread.h"
40 #include "mozilla/XPTInterfaceInfoManager.h"
41 #include "nsIObjectInputStream.h"
42 #include "nsIObjectOutputStream.h"
44 using namespace mozilla;
45 using namespace mozilla::dom;
46 using namespace xpc;
47 using namespace JS;
49 NS_IMPL_ISUPPORTS(nsXPConnect,
50 nsIXPConnect,
51 nsISupportsWeakReference,
52 nsIThreadObserver,
53 nsIJSRuntimeService)
55 nsXPConnect* nsXPConnect::gSelf = nullptr;
56 bool nsXPConnect::gOnceAliveNowDead = false;
57 uint32_t nsXPConnect::gReportAllJSExceptions = 0;
59 bool xpc::gDebugMode = false;
60 bool xpc::gDesiredDebugMode = false;
62 // Global cache of the default script security manager (QI'd to
63 // nsIScriptSecurityManager)
64 nsIScriptSecurityManager *nsXPConnect::gScriptSecurityManager = nullptr;
66 const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
67 const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1";
68 const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1";
69 const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1";
70 const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1";
71 const char XPC_ID_CONTRACTID[] = "@mozilla.org/js/xpc/ID;1";
72 const char XPC_XPCONNECT_CONTRACTID[] = "@mozilla.org/js/xpc/XPConnect;1";
74 /***************************************************************************/
76 nsXPConnect::nsXPConnect()
77 : mRuntime(nullptr),
78 mShuttingDown(false),
79 mEventDepth(0)
80 {
81 mRuntime = XPCJSRuntime::newXPCJSRuntime(this);
83 char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS");
84 if (reportableEnv && *reportableEnv)
85 gReportAllJSExceptions = 1;
86 }
88 nsXPConnect::~nsXPConnect()
89 {
90 mRuntime->DeleteSingletonScopes();
91 mRuntime->DestroyJSContextStack();
93 // In order to clean up everything properly, we need to GC twice: once now,
94 // to clean anything that can go away on its own (like the Junk Scope, which
95 // we unrooted above), and once after forcing a bunch of shutdown in
96 // XPConnect, to clean the stuff we forcibly disconnected. The forced
97 // shutdown code defaults to leaking in a number of situations, so we can't
98 // get by with only the second GC. :-(
99 JS_GC(mRuntime->Runtime());
101 mShuttingDown = true;
102 XPCWrappedNativeScope::SystemIsBeingShutDown();
103 mRuntime->SystemIsBeingShutDown();
105 // The above causes us to clean up a bunch of XPConnect data structures,
106 // after which point we need to GC to clean everything up. We need to do
107 // this before deleting the XPCJSRuntime, because doing so destroys the
108 // maps that our finalize callback depends on.
109 JS_GC(mRuntime->Runtime());
111 mDefaultSecurityManager = nullptr;
112 gScriptSecurityManager = nullptr;
114 // shutdown the logging system
115 XPC_LOG_FINISH();
117 delete mRuntime;
119 gSelf = nullptr;
120 gOnceAliveNowDead = true;
121 }
123 // static
124 void
125 nsXPConnect::InitStatics()
126 {
127 gSelf = new nsXPConnect();
128 gOnceAliveNowDead = false;
129 if (!gSelf->mRuntime) {
130 NS_RUNTIMEABORT("Couldn't create XPCJSRuntime.");
131 }
133 // Initial extra ref to keep the singleton alive
134 // balanced by explicit call to ReleaseXPConnectSingleton()
135 NS_ADDREF(gSelf);
137 // Set XPConnect as the main thread observer.
138 if (NS_FAILED(nsThread::SetMainThreadObserver(gSelf))) {
139 MOZ_CRASH();
140 }
141 }
143 nsXPConnect*
144 nsXPConnect::GetSingleton()
145 {
146 nsXPConnect* xpc = nsXPConnect::XPConnect();
147 NS_IF_ADDREF(xpc);
148 return xpc;
149 }
151 // static
152 void
153 nsXPConnect::ReleaseXPConnectSingleton()
154 {
155 nsXPConnect* xpc = gSelf;
156 if (xpc) {
157 nsThread::SetMainThreadObserver(nullptr);
159 nsrefcnt cnt;
160 NS_RELEASE2(xpc, cnt);
161 }
162 }
164 // static
165 XPCJSRuntime*
166 nsXPConnect::GetRuntimeInstance()
167 {
168 nsXPConnect* xpc = XPConnect();
169 return xpc->GetRuntime();
170 }
172 // static
173 bool
174 nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info)
175 {
176 bool found = false;
177 if (info)
178 info->HasAncestor(&NS_GET_IID(nsISupports), &found);
179 return found;
180 }
182 void
183 xpc::SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep)
184 {
185 // It would be nice to assert !DescribeScriptedCaller here, to be sure
186 // that there isn't any script running that could catch the exception. But
187 // the JS engine invokes the error reporter directly if someone reports an
188 // ErrorReport that it doesn't know how to turn into an exception. Arguably
189 // it should just learn how to throw everything. But either way, if the
190 // exception is ending here, it's not going to get propagated to a caller,
191 // so it's up to us to make it known.
193 nsresult rv;
195 /* Use the console service to register the error. */
196 nsCOMPtr<nsIConsoleService> consoleService =
197 do_GetService(NS_CONSOLESERVICE_CONTRACTID);
199 /*
200 * Make an nsIScriptError, populate it with information from this
201 * error, then log it with the console service.
202 */
203 nsCOMPtr<nsIScriptError> errorObject =
204 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
206 if (consoleService && errorObject) {
207 uint32_t column = rep->uctokenptr - rep->uclinebuf;
209 const char16_t* ucmessage =
210 static_cast<const char16_t*>(rep->ucmessage);
211 const char16_t* uclinebuf =
212 static_cast<const char16_t*>(rep->uclinebuf);
214 rv = errorObject->Init(
215 ucmessage ? nsDependentString(ucmessage) : EmptyString(),
216 NS_ConvertASCIItoUTF16(rep->filename),
217 uclinebuf ? nsDependentString(uclinebuf) : EmptyString(),
218 rep->lineno, column, rep->flags,
219 "system javascript");
220 if (NS_SUCCEEDED(rv))
221 consoleService->LogMessage(errorObject);
222 }
224 if (nsContentUtils::DOMWindowDumpEnabled()) {
225 fprintf(stderr, "System JS : %s %s:%d - %s\n",
226 JSREPORT_IS_WARNING(rep->flags) ? "WARNING" : "ERROR",
227 rep->filename, rep->lineno,
228 message ? message : "<no message>");
229 }
231 }
234 /***************************************************************************/
237 nsresult
238 nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info)
239 {
240 return XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(aIID, info);
241 }
243 nsresult
244 nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
245 {
246 nsresult rv = XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, info);
247 return NS_FAILED(rv) ? NS_OK : NS_ERROR_NO_INTERFACE;
248 }
250 NS_IMETHODIMP
251 nsXPConnect::GarbageCollect(uint32_t reason)
252 {
253 GetRuntime()->Collect(reason);
254 return NS_OK;
255 }
257 bool
258 xpc_GCThingIsGrayCCThing(void *thing)
259 {
260 return AddToCCKind(js::GCThingTraceKind(thing)) &&
261 xpc_IsGrayGCThing(thing);
262 }
264 void
265 xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration)
266 {
267 nsCOMPtr<XPCVariant> variant = do_QueryInterface(aVariant);
268 if (variant) {
269 variant->SetCCGeneration(aGeneration);
270 variant->GetJSVal(); // Unmarks gray JSObject.
271 XPCVariant* weak = variant.get();
272 variant = nullptr;
273 if (weak->IsPurple()) {
274 weak->RemovePurple();
275 }
276 }
277 }
279 void
280 xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS)
281 {
282 nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aWrappedJS);
283 if (wjs) {
284 // Unmarks gray JSObject.
285 static_cast<nsXPCWrappedJS*>(wjs.get())->GetJSObject();
286 }
287 }
289 /***************************************************************************/
290 /***************************************************************************/
291 // nsIXPConnect interface methods...
293 template<typename T>
294 static inline T UnexpectedFailure(T rv)
295 {
296 NS_ERROR("This is not supposed to fail!");
297 return rv;
298 }
300 /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
301 NS_IMETHODIMP
302 nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
303 {
304 MOZ_ASSERT(aJSContext, "bad param");
305 MOZ_ASSERT(aGlobalJSObj, "bad param");
306 RootedObject globalJSObj(aJSContext, aGlobalJSObj);
308 JSAutoCompartment ac(aJSContext, globalJSObj);
310 XPCWrappedNativeScope* scope =
311 XPCWrappedNativeScope::GetNewOrUsed(aJSContext, globalJSObj);
313 if (!scope)
314 return UnexpectedFailure(NS_ERROR_FAILURE);
316 scope->RemoveWrappedNativeProtos();
318 if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj))
319 return UnexpectedFailure(NS_ERROR_FAILURE);
321 return NS_OK;
322 }
324 #ifdef DEBUG
325 static void
326 VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind)
327 {
328 // We don't do anything here, we only want to verify that TraceXPCGlobal
329 // was called.
330 }
332 struct VerifyTraceXPCGlobalCalledTracer : public JSTracer
333 {
334 bool ok;
336 VerifyTraceXPCGlobalCalledTracer(JSRuntime *rt)
337 : JSTracer(rt, VerifyTraceXPCGlobalCalled), ok(false)
338 {}
339 };
340 #endif
342 void
343 xpc::TraceXPCGlobal(JSTracer *trc, JSObject *obj)
344 {
345 #ifdef DEBUG
346 if (trc->callback == VerifyTraceXPCGlobalCalled) {
347 // We don't do anything here, we only want to verify that TraceXPCGlobal
348 // was called.
349 reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = true;
350 return;
351 }
352 #endif
354 if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
355 mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
357 // We might be called from a GC during the creation of a global, before we've
358 // been able to set up the compartment private or the XPCWrappedNativeScope,
359 // so we need to null-check those.
360 xpc::CompartmentPrivate* compartmentPrivate = GetCompartmentPrivate(obj);
361 if (compartmentPrivate && compartmentPrivate->scope)
362 compartmentPrivate->scope->TraceInside(trc);
363 }
365 namespace xpc {
367 JSObject*
368 CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
369 JS::CompartmentOptions& aOptions)
370 {
371 MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
372 MOZ_ASSERT(principal);
374 RootedObject global(cx,
375 JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
376 JS::DontFireOnNewGlobalHook, aOptions));
377 if (!global)
378 return nullptr;
379 JSAutoCompartment ac(cx, global);
381 // The constructor automatically attaches the scope to the compartment private
382 // of |global|.
383 (void) new XPCWrappedNativeScope(cx, global);
385 #ifdef DEBUG
386 // Verify that the right trace hook is called. Note that this doesn't
387 // work right for wrapped globals, since the tracing situation there is
388 // more complicated. Manual inspection shows that they do the right thing.
389 if (!((const js::Class*)clasp)->ext.isWrappedNative)
390 {
391 VerifyTraceXPCGlobalCalledTracer trc(JS_GetRuntime(cx));
392 JS_TraceChildren(&trc, global, JSTRACE_OBJECT);
393 MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
394 }
395 #endif
397 if (clasp->flags & JSCLASS_DOM_GLOBAL) {
398 const char* className = clasp->name;
399 AllocateProtoAndIfaceCache(global,
400 (strcmp(className, "Window") == 0 ||
401 strcmp(className, "ChromeWindow") == 0)
402 ? ProtoAndIfaceCache::WindowLike
403 : ProtoAndIfaceCache::NonWindowLike);
404 }
406 return global;
407 }
409 bool
410 InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags)
411 {
412 // Immediately enter the global's compartment, so that everything else we
413 // create ends up there.
414 JSAutoCompartment ac(aJSContext, aGlobal);
415 if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
416 // XPCCallContext gives us an active request needed to save/restore.
417 if (!GetCompartmentPrivate(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
418 !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
419 return UnexpectedFailure(false);
420 }
421 }
423 if (ShouldDiscardSystemSource()) {
424 nsIPrincipal *prin = GetObjectPrincipal(aGlobal);
425 bool isSystem = nsContentUtils::IsSystemPrincipal(prin);
426 if (!isSystem) {
427 short status = prin->GetAppStatus();
428 isSystem = status == nsIPrincipal::APP_STATUS_PRIVILEGED ||
429 status == nsIPrincipal::APP_STATUS_CERTIFIED;
430 }
431 JS::CompartmentOptionsRef(aGlobal).setDiscardSource(isSystem);
432 }
434 // Stuff coming through this path always ends up as a DOM global.
435 MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
437 // Init WebIDL binding constructors wanted on all XPConnect globals.
438 //
439 // XXX Please do not add any additional classes here without the approval of
440 // the XPConnect module owner.
441 if (!PromiseBinding::GetConstructorObject(aJSContext, aGlobal) ||
442 !TextDecoderBinding::GetConstructorObject(aJSContext, aGlobal) ||
443 !TextEncoderBinding::GetConstructorObject(aJSContext, aGlobal) ||
444 !DOMErrorBinding::GetConstructorObject(aJSContext, aGlobal)) {
445 return UnexpectedFailure(false);
446 }
448 if (!(aFlags & nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK))
449 JS_FireOnNewGlobalObject(aJSContext, aGlobal);
451 return true;
452 }
454 } // namespace xpc
456 NS_IMETHODIMP
457 nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
458 nsISupports *aCOMObj,
459 nsIPrincipal * aPrincipal,
460 uint32_t aFlags,
461 JS::CompartmentOptions& aOptions,
462 nsIXPConnectJSObjectHolder **_retval)
463 {
464 MOZ_ASSERT(aJSContext, "bad param");
465 MOZ_ASSERT(aCOMObj, "bad param");
466 MOZ_ASSERT(_retval, "bad param");
468 // We pass null for the 'extra' pointer during global object creation, so
469 // we need to have a principal.
470 MOZ_ASSERT(aPrincipal);
472 // Call into XPCWrappedNative to make a new global object, scope, and global
473 // prototype.
474 xpcObjectHelper helper(aCOMObj);
475 MOZ_ASSERT(helper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
476 nsRefPtr<XPCWrappedNative> wrappedGlobal;
477 nsresult rv =
478 XPCWrappedNative::WrapNewGlobal(helper, aPrincipal,
479 aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
480 aOptions, getter_AddRefs(wrappedGlobal));
481 NS_ENSURE_SUCCESS(rv, rv);
483 // Grab a copy of the global and enter its compartment.
484 RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
485 MOZ_ASSERT(!js::GetObjectParent(global));
487 if (!InitGlobalObject(aJSContext, global, aFlags))
488 return UnexpectedFailure(NS_ERROR_FAILURE);
490 wrappedGlobal.forget(_retval);
491 return NS_OK;
492 }
494 static nsresult
495 NativeInterface2JSObject(HandleObject aScope,
496 nsISupports *aCOMObj,
497 nsWrapperCache *aCache,
498 const nsIID * aIID,
499 bool aAllowWrapping,
500 MutableHandleValue aVal,
501 nsIXPConnectJSObjectHolder **aHolder)
502 {
503 AutoJSContext cx;
504 JSAutoCompartment ac(cx, aScope);
506 nsresult rv;
507 xpcObjectHelper helper(aCOMObj, aCache);
508 if (!XPCConvert::NativeInterface2JSObject(aVal, aHolder, helper, aIID,
509 nullptr, aAllowWrapping, &rv))
510 return rv;
512 MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
513 "Shouldn't be returning a xray wrapper here");
515 return NS_OK;
516 }
518 /* nsIXPConnectJSObjectHolder wrapNative (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */
519 NS_IMETHODIMP
520 nsXPConnect::WrapNative(JSContext * aJSContext,
521 JSObject * aScopeArg,
522 nsISupports *aCOMObj,
523 const nsIID & aIID,
524 nsIXPConnectJSObjectHolder **aHolder)
525 {
526 MOZ_ASSERT(aHolder, "bad param");
527 MOZ_ASSERT(aJSContext, "bad param");
528 MOZ_ASSERT(aScopeArg, "bad param");
529 MOZ_ASSERT(aCOMObj, "bad param");
531 RootedObject aScope(aJSContext, aScopeArg);
532 RootedValue v(aJSContext);
533 return NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
534 true, &v, aHolder);
535 }
537 /* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDPtr aIID, out jsval aVal, out nsIXPConnectJSObjectHolder aHolder); */
538 NS_IMETHODIMP
539 nsXPConnect::WrapNativeToJSVal(JSContext *aJSContext,
540 JSObject *aScopeArg,
541 nsISupports *aCOMObj,
542 nsWrapperCache *aCache,
543 const nsIID *aIID,
544 bool aAllowWrapping,
545 MutableHandleValue aVal)
546 {
547 MOZ_ASSERT(aJSContext, "bad param");
548 MOZ_ASSERT(aScopeArg, "bad param");
549 MOZ_ASSERT(aCOMObj, "bad param");
551 RootedObject aScope(aJSContext, aScopeArg);
552 return NativeInterface2JSObject(aScope, aCOMObj, aCache, aIID,
553 aAllowWrapping, aVal, nullptr);
554 }
556 /* void wrapJS (in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
557 NS_IMETHODIMP
558 nsXPConnect::WrapJS(JSContext * aJSContext,
559 JSObject * aJSObjArg,
560 const nsIID & aIID,
561 void * *result)
562 {
563 MOZ_ASSERT(aJSContext, "bad param");
564 MOZ_ASSERT(aJSObjArg, "bad param");
565 MOZ_ASSERT(result, "bad param");
567 *result = nullptr;
569 RootedObject aJSObj(aJSContext, aJSObjArg);
570 JSAutoCompartment ac(aJSContext, aJSObj);
572 nsresult rv = NS_ERROR_UNEXPECTED;
573 if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
574 &aIID, nullptr, &rv))
575 return rv;
576 return NS_OK;
577 }
579 NS_IMETHODIMP
580 nsXPConnect::JSValToVariant(JSContext *cx,
581 HandleValue aJSVal,
582 nsIVariant **aResult)
583 {
584 NS_PRECONDITION(aResult, "bad param");
586 nsRefPtr<XPCVariant> variant = XPCVariant::newVariant(cx, aJSVal);
587 variant.forget(aResult);
588 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
590 return NS_OK;
591 }
593 /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
594 NS_IMETHODIMP
595 nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,
596 JSContext *aJSContext,
597 JSObject *aJSObjArg,
598 const nsIID &aIID,
599 void **result)
600 {
601 MOZ_ASSERT(aOuter, "bad param");
602 MOZ_ASSERT(aJSContext, "bad param");
603 MOZ_ASSERT(aJSObjArg, "bad param");
604 MOZ_ASSERT(result, "bad param");
606 *result = nullptr;
608 RootedObject aJSObj(aJSContext, aJSObjArg);
609 nsresult rv;
610 if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
611 &aIID, aOuter, &rv))
612 return rv;
613 return NS_OK;
614 }
616 /* nsIXPConnectWrappedNative getWrappedNativeOfJSObject (in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */
617 NS_IMETHODIMP
618 nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext,
619 JSObject * aJSObjArg,
620 nsIXPConnectWrappedNative **_retval)
621 {
622 MOZ_ASSERT(aJSContext, "bad param");
623 MOZ_ASSERT(aJSObjArg, "bad param");
624 MOZ_ASSERT(_retval, "bad param");
626 RootedObject aJSObj(aJSContext, aJSObjArg);
627 aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false);
628 if (!aJSObj || !IS_WN_REFLECTOR(aJSObj)) {
629 *_retval = nullptr;
630 return NS_ERROR_FAILURE;
631 }
633 nsRefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj);
634 temp.forget(_retval);
635 return NS_OK;
636 }
638 /* nsISupports getNativeOfWrapper(in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */
639 NS_IMETHODIMP_(nsISupports*)
640 nsXPConnect::GetNativeOfWrapper(JSContext *aJSContext,
641 JSObject *aJSObj)
642 {
643 MOZ_ASSERT(aJSContext, "bad param");
644 MOZ_ASSERT(aJSObj, "bad param");
646 aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false);
647 if (!aJSObj) {
648 JS_ReportError(aJSContext, "Permission denied to get native of security wrapper");
649 return nullptr;
650 }
651 if (IS_WN_REFLECTOR(aJSObj)) {
652 if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj))
653 return wn->Native();
654 return nullptr;
655 }
657 nsCOMPtr<nsISupports> canonical =
658 do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(aJSObj));
659 return canonical;
660 }
662 /* nsIXPConnectWrappedNative getWrappedNativeOfNativeObject (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */
663 NS_IMETHODIMP
664 nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext,
665 JSObject * aScopeArg,
666 nsISupports *aCOMObj,
667 const nsIID & aIID,
668 nsIXPConnectWrappedNative **_retval)
669 {
670 MOZ_ASSERT(aJSContext, "bad param");
671 MOZ_ASSERT(aScopeArg, "bad param");
672 MOZ_ASSERT(aCOMObj, "bad param");
673 MOZ_ASSERT(_retval, "bad param");
675 *_retval = nullptr;
677 RootedObject aScope(aJSContext, aScopeArg);
679 XPCWrappedNativeScope* scope = GetObjectScope(aScope);
680 if (!scope)
681 return UnexpectedFailure(NS_ERROR_FAILURE);
683 AutoMarkingNativeInterfacePtr iface(aJSContext);
684 iface = XPCNativeInterface::GetNewOrUsed(&aIID);
685 if (!iface)
686 return NS_ERROR_FAILURE;
688 XPCWrappedNative* wrapper;
690 nsresult rv = XPCWrappedNative::GetUsedOnly(aCOMObj, scope, iface, &wrapper);
691 if (NS_FAILED(rv))
692 return NS_ERROR_FAILURE;
693 *_retval = static_cast<nsIXPConnectWrappedNative*>(wrapper);
694 return NS_OK;
695 }
697 /* void reparentWrappedNativeIfFound (in JSContextPtr aJSContext,
698 * in JSObjectPtr aScope,
699 * in JSObjectPtr aNewParent,
700 * in nsISupports aCOMObj); */
701 NS_IMETHODIMP
702 nsXPConnect::ReparentWrappedNativeIfFound(JSContext * aJSContext,
703 JSObject * aScopeArg,
704 JSObject * aNewParentArg,
705 nsISupports *aCOMObj)
706 {
707 RootedObject aScope(aJSContext, aScopeArg);
708 RootedObject aNewParent(aJSContext, aNewParentArg);
710 XPCWrappedNativeScope* scope = GetObjectScope(aScope);
711 XPCWrappedNativeScope* scope2 = GetObjectScope(aNewParent);
712 if (!scope || !scope2)
713 return UnexpectedFailure(NS_ERROR_FAILURE);
715 RootedObject newParent(aJSContext, aNewParent);
716 return XPCWrappedNative::
717 ReparentWrapperIfFound(scope, scope2, newParent, aCOMObj);
718 }
720 static PLDHashOperator
721 MoveableWrapperFinder(PLDHashTable *table, PLDHashEntryHdr *hdr,
722 uint32_t number, void *arg)
723 {
724 nsTArray<nsRefPtr<XPCWrappedNative> > *array =
725 static_cast<nsTArray<nsRefPtr<XPCWrappedNative> > *>(arg);
726 XPCWrappedNative *wn = ((Native2WrappedNativeMap::Entry*)hdr)->value;
728 // If a wrapper is expired, then there are no references to it from JS, so
729 // we don't have to move it.
730 if (!wn->IsWrapperExpired())
731 array->AppendElement(wn);
732 return PL_DHASH_NEXT;
733 }
735 /* void rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr aScope); */
736 NS_IMETHODIMP
737 nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScopeArg)
738 {
739 RootedObject aScope(aJSContext, aScopeArg);
741 XPCWrappedNativeScope *scope = GetObjectScope(aScope);
742 if (!scope)
743 return UnexpectedFailure(NS_ERROR_FAILURE);
745 // First, look through the old scope and find all of the wrappers that we
746 // might need to rescue.
747 nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
749 Native2WrappedNativeMap *map = scope->GetWrappedNativeMap();
750 wrappersToMove.SetCapacity(map->Count());
751 map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
753 // Now that we have the wrappers, reparent them to the new scope.
754 for (uint32_t i = 0, stop = wrappersToMove.Length(); i < stop; ++i) {
755 nsresult rv = wrappersToMove[i]->RescueOrphans();
756 NS_ENSURE_SUCCESS(rv, rv);
757 }
759 return NS_OK;
760 }
762 /* void setDefaultSecurityManager (in nsIXPCSecurityManager aManager); */
763 NS_IMETHODIMP
764 nsXPConnect::SetDefaultSecurityManager(nsIXPCSecurityManager *aManager)
765 {
766 mDefaultSecurityManager = aManager;
768 nsCOMPtr<nsIScriptSecurityManager> ssm =
769 do_QueryInterface(mDefaultSecurityManager);
771 // Remember the result of the above QI for fast access to the
772 // script securityt manager.
773 gScriptSecurityManager = ssm;
775 return NS_OK;
776 }
778 /* nsIStackFrame createStackFrameLocation (in uint32_t aLanguage, in string aFilename, in string aFunctionName, in int32_t aLineNumber, in nsIStackFrame aCaller); */
779 NS_IMETHODIMP
780 nsXPConnect::CreateStackFrameLocation(uint32_t aLanguage,
781 const char *aFilename,
782 const char *aFunctionName,
783 int32_t aLineNumber,
784 nsIStackFrame *aCaller,
785 nsIStackFrame **_retval)
786 {
787 MOZ_ASSERT(_retval, "bad param");
789 nsCOMPtr<nsIStackFrame> stackFrame =
790 exceptions::CreateStackFrameLocation(aLanguage,
791 aFilename,
792 aFunctionName,
793 aLineNumber,
794 aCaller);
795 stackFrame.forget(_retval);
796 return NS_OK;
797 }
799 /* readonly attribute nsIStackFrame CurrentJSStack; */
800 NS_IMETHODIMP
801 nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack)
802 {
803 MOZ_ASSERT(aCurrentJSStack, "bad param");
805 nsCOMPtr<nsIStackFrame> currentStack = dom::GetCurrentJSStack();
806 currentStack.forget(aCurrentJSStack);
808 return NS_OK;
809 }
811 /* readonly attribute nsIXPCNativeCallContext CurrentNativeCallContext; */
812 NS_IMETHODIMP
813 nsXPConnect::GetCurrentNativeCallContext(nsAXPCNativeCallContext * *aCurrentNativeCallContext)
814 {
815 MOZ_ASSERT(aCurrentNativeCallContext, "bad param");
817 *aCurrentNativeCallContext = XPCJSRuntime::Get()->GetCallContext();
818 return NS_OK;
819 }
821 /* void setFunctionThisTranslator (in nsIIDRef aIID, in nsIXPCFunctionThisTranslator aTranslator); */
822 NS_IMETHODIMP
823 nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
824 nsIXPCFunctionThisTranslator *aTranslator)
825 {
826 XPCJSRuntime* rt = GetRuntime();
827 IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
828 map->Add(aIID, aTranslator);
829 return NS_OK;
830 }
832 NS_IMETHODIMP
833 nsXPConnect::CreateSandbox(JSContext *cx, nsIPrincipal *principal,
834 nsIXPConnectJSObjectHolder **_retval)
835 {
836 *_retval = nullptr;
838 RootedValue rval(cx);
839 SandboxOptions options;
840 nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
841 MOZ_ASSERT(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval),
842 "Bad return value from xpc_CreateSandboxObject()!");
844 if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(rval)) {
845 *_retval = XPCJSObjectHolder::newHolder(JSVAL_TO_OBJECT(rval));
846 NS_ENSURE_TRUE(*_retval, NS_ERROR_OUT_OF_MEMORY);
848 NS_ADDREF(*_retval);
849 }
851 return rv;
852 }
854 NS_IMETHODIMP
855 nsXPConnect::EvalInSandboxObject(const nsAString& source, const char *filename,
856 JSContext *cx, JSObject *sandboxArg,
857 bool returnStringOnly, MutableHandleValue rval)
858 {
859 if (!sandboxArg)
860 return NS_ERROR_INVALID_ARG;
862 RootedObject sandbox(cx, sandboxArg);
863 nsCString filenameStr;
864 if (filename) {
865 filenameStr.Assign(filename);
866 } else {
867 filenameStr = NS_LITERAL_CSTRING("x-bogus://XPConnect/Sandbox");
868 }
869 return EvalInSandbox(cx, sandbox, source, filenameStr, 1,
870 JSVERSION_DEFAULT, returnStringOnly, rval);
871 }
873 /* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */
874 NS_IMETHODIMP
875 nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,
876 JSObject * aScopeArg,
877 nsIClassInfo *aClassInfo,
878 nsIXPConnectJSObjectHolder **_retval)
879 {
880 RootedObject aScope(aJSContext, aScopeArg);
881 JSAutoCompartment ac(aJSContext, aScope);
883 XPCWrappedNativeScope* scope = GetObjectScope(aScope);
884 if (!scope)
885 return UnexpectedFailure(NS_ERROR_FAILURE);
887 XPCNativeScriptableCreateInfo sciProto;
888 XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
890 AutoMarkingWrappedNativeProtoPtr proto(aJSContext);
891 proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, &sciProto);
892 if (!proto)
893 return UnexpectedFailure(NS_ERROR_FAILURE);
895 nsIXPConnectJSObjectHolder* holder;
896 *_retval = holder = XPCJSObjectHolder::newHolder(proto->GetJSProtoObject());
897 if (!holder)
898 return UnexpectedFailure(NS_ERROR_FAILURE);
900 NS_ADDREF(holder);
901 return NS_OK;
902 }
904 /* void debugDump (in short depth); */
905 NS_IMETHODIMP
906 nsXPConnect::DebugDump(int16_t depth)
907 {
908 #ifdef DEBUG
909 depth-- ;
910 XPC_LOG_ALWAYS(("nsXPConnect @ %x with mRefCnt = %d", this, mRefCnt.get()));
911 XPC_LOG_INDENT();
912 XPC_LOG_ALWAYS(("gSelf @ %x", gSelf));
913 XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead));
914 XPC_LOG_ALWAYS(("mDefaultSecurityManager @ %x", mDefaultSecurityManager.get()));
915 if (mRuntime) {
916 if (depth)
917 mRuntime->DebugDump(depth);
918 else
919 XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", mRuntime));
920 } else
921 XPC_LOG_ALWAYS(("mRuntime is null"));
922 XPCWrappedNativeScope::DebugDumpAllScopes(depth);
923 XPC_LOG_OUTDENT();
924 #endif
925 return NS_OK;
926 }
928 /* void debugDumpObject (in nsISupports aCOMObj, in short depth); */
929 NS_IMETHODIMP
930 nsXPConnect::DebugDumpObject(nsISupports *p, int16_t depth)
931 {
932 #ifdef DEBUG
933 if (!depth)
934 return NS_OK;
935 if (!p) {
936 XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address"));
937 return NS_OK;
938 }
940 nsIXPConnect* xpc;
941 nsIXPCWrappedJSClass* wjsc;
942 nsIXPConnectWrappedNative* wn;
943 nsIXPConnectWrappedJS* wjs;
945 if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnect),
946 (void**)&xpc))) {
947 XPC_LOG_ALWAYS(("Dumping a nsIXPConnect..."));
948 xpc->DebugDump(depth);
949 NS_RELEASE(xpc);
950 } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPCWrappedJSClass),
951 (void**)&wjsc))) {
952 XPC_LOG_ALWAYS(("Dumping a nsIXPCWrappedJSClass..."));
953 wjsc->DebugDump(depth);
954 NS_RELEASE(wjsc);
955 } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedNative),
956 (void**)&wn))) {
957 XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative..."));
958 wn->DebugDump(depth);
959 NS_RELEASE(wn);
960 } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedJS),
961 (void**)&wjs))) {
962 XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS..."));
963 wjs->DebugDump(depth);
964 NS_RELEASE(wjs);
965 } else
966 XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %x", p));
967 #endif
968 return NS_OK;
969 }
971 /* void debugDumpJSStack (in bool showArgs, in bool showLocals, in bool showThisProps); */
972 NS_IMETHODIMP
973 nsXPConnect::DebugDumpJSStack(bool showArgs,
974 bool showLocals,
975 bool showThisProps)
976 {
977 JSContext* cx = GetCurrentJSContext();
978 if (!cx)
979 printf("there is no JSContext on the nsIThreadJSContextStack!\n");
980 else
981 xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps);
983 return NS_OK;
984 }
986 char*
987 nsXPConnect::DebugPrintJSStack(bool showArgs,
988 bool showLocals,
989 bool showThisProps)
990 {
991 JSContext* cx = GetCurrentJSContext();
992 if (!cx)
993 printf("there is no JSContext on the nsIThreadJSContextStack!\n");
994 else
995 return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps);
997 return nullptr;
998 }
1000 /* void debugDumpEvalInJSStackFrame (in uint32_t aFrameNumber, in string aSourceText); */
1001 NS_IMETHODIMP
1002 nsXPConnect::DebugDumpEvalInJSStackFrame(uint32_t aFrameNumber, const char *aSourceText)
1003 {
1004 JSContext* cx = GetCurrentJSContext();
1005 if (!cx)
1006 printf("there is no JSContext on the nsIThreadJSContextStack!\n");
1007 else
1008 xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText);
1010 return NS_OK;
1011 }
1013 /* jsval variantToJS (in JSContextPtr ctx, in JSObjectPtr scope, in nsIVariant value); */
1014 NS_IMETHODIMP
1015 nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg, nsIVariant* value,
1016 MutableHandleValue _retval)
1017 {
1018 NS_PRECONDITION(ctx, "bad param");
1019 NS_PRECONDITION(scopeArg, "bad param");
1020 NS_PRECONDITION(value, "bad param");
1022 RootedObject scope(ctx, scopeArg);
1023 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx));
1025 nsresult rv = NS_OK;
1026 if (!XPCVariant::VariantDataToJS(value, &rv, _retval)) {
1027 if (NS_FAILED(rv))
1028 return rv;
1030 return NS_ERROR_FAILURE;
1031 }
1032 return NS_OK;
1033 }
1035 /* nsIVariant JSToVariant (in JSContextPtr ctx, in jsval value); */
1036 NS_IMETHODIMP
1037 nsXPConnect::JSToVariant(JSContext* ctx, HandleValue value, nsIVariant** _retval)
1038 {
1039 NS_PRECONDITION(ctx, "bad param");
1040 NS_PRECONDITION(_retval, "bad param");
1042 nsRefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value);
1043 variant.forget(_retval);
1044 if (!(*_retval))
1045 return NS_ERROR_FAILURE;
1047 return NS_OK;
1048 }
1050 NS_IMETHODIMP
1051 nsXPConnect::OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait,
1052 uint32_t aRecursionDepth)
1053 {
1054 // Record this event.
1055 mEventDepth++;
1057 // Push a null JSContext so that we don't see any script during
1058 // event processing.
1059 MOZ_ASSERT(NS_IsMainThread());
1060 bool ok = PushJSContextNoScriptContext(nullptr);
1061 NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
1062 return NS_OK;
1063 }
1065 NS_IMETHODIMP
1066 nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread,
1067 uint32_t aRecursionDepth,
1068 bool aEventWasProcessed)
1069 {
1070 // Watch out for unpaired events during observer registration.
1071 if (MOZ_UNLIKELY(mEventDepth == 0))
1072 return NS_OK;
1073 mEventDepth--;
1075 // Now that we're back to the event loop, reset the slow script checkpoint.
1076 mRuntime->OnAfterProcessNextEvent();
1078 // Call cycle collector occasionally.
1079 MOZ_ASSERT(NS_IsMainThread());
1080 nsJSContext::MaybePokeCC();
1081 nsDOMMutationObserver::HandleMutations();
1083 PopJSContextNoScriptContext();
1085 // If the cx stack is empty, that means we're at the an un-nested event
1086 // loop. This is a good time to make changes to debug mode.
1087 if (XPCJSRuntime::Get()->GetJSContextStack()->Count() == 0) {
1088 MOZ_ASSERT(mEventDepth == 0);
1089 CheckForDebugMode(XPCJSRuntime::Get()->Runtime());
1090 }
1091 return NS_OK;
1092 }
1094 NS_IMETHODIMP
1095 nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
1096 {
1097 NS_NOTREACHED("Why tell us?");
1098 return NS_ERROR_UNEXPECTED;
1099 }
1101 NS_IMETHODIMP
1102 nsXPConnect::SetReportAllJSExceptions(bool newval)
1103 {
1104 // Ignore if the environment variable was set.
1105 if (gReportAllJSExceptions != 1)
1106 gReportAllJSExceptions = newval ? 2 : 0;
1108 return NS_OK;
1109 }
1111 /* attribute JSRuntime runtime; */
1112 NS_IMETHODIMP
1113 nsXPConnect::GetRuntime(JSRuntime **runtime)
1114 {
1115 if (!runtime)
1116 return NS_ERROR_NULL_POINTER;
1118 JSRuntime *rt = GetRuntime()->Runtime();
1119 JS_AbortIfWrongThread(rt);
1120 *runtime = rt;
1121 return NS_OK;
1122 }
1124 /* [noscript, notxpcom] void registerGCCallback(in xpcGCCallback func); */
1125 NS_IMETHODIMP_(void)
1126 nsXPConnect::RegisterGCCallback(xpcGCCallback func)
1127 {
1128 mRuntime->AddGCCallback(func);
1129 }
1131 /* [noscript, notxpcom] void unregisterGCCallback(in xpcGCCallback func); */
1132 NS_IMETHODIMP_(void)
1133 nsXPConnect::UnregisterGCCallback(xpcGCCallback func)
1134 {
1135 mRuntime->RemoveGCCallback(func);
1136 }
1138 /* [noscript, notxpcom] void registerContextCallback(in xpcContextCallback func); */
1139 NS_IMETHODIMP_(void)
1140 nsXPConnect::RegisterContextCallback(xpcContextCallback func)
1141 {
1142 mRuntime->AddContextCallback(func);
1143 }
1145 /* [noscript, notxpcom] void unregisterContextCallback(in xpcContextCallback func); */
1146 NS_IMETHODIMP_(void)
1147 nsXPConnect::UnregisterContextCallback(xpcContextCallback func)
1148 {
1149 mRuntime->RemoveContextCallback(func);
1150 }
1152 #ifdef MOZ_JSDEBUGGER
1153 void
1154 nsXPConnect::CheckForDebugMode(JSRuntime *rt)
1155 {
1156 if (gDebugMode == gDesiredDebugMode) {
1157 return;
1158 }
1160 // This can happen if a Worker is running, but we don't have the ability to
1161 // debug workers right now, so just return.
1162 if (!NS_IsMainThread())
1163 MOZ_CRASH();
1165 AutoSafeJSContext cx;
1166 JS_SetRuntimeDebugMode(rt, gDesiredDebugMode);
1168 nsresult rv;
1169 const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
1170 nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
1171 if (NS_FAILED(rv)) {
1172 goto fail;
1173 }
1175 if (!JS_SetDebugModeForAllCompartments(cx, gDesiredDebugMode))
1176 goto fail;
1178 if (gDesiredDebugMode) {
1179 rv = jsds->ActivateDebugger(rt);
1180 }
1182 gDebugMode = gDesiredDebugMode;
1183 return;
1185 fail:
1186 if (jsds)
1187 jsds->DeactivateDebugger();
1189 /*
1190 * If an attempt to turn debug mode on fails, cancel the request. It's
1191 * always safe to turn debug mode off, since DeactivateDebugger prevents
1192 * debugger callbacks from having any effect.
1193 */
1194 if (gDesiredDebugMode)
1195 JS_SetRuntimeDebugMode(rt, false);
1196 gDesiredDebugMode = gDebugMode = false;
1197 }
1198 #else //MOZ_JSDEBUGGER not defined
1199 void
1200 nsXPConnect::CheckForDebugMode(JSRuntime *rt)
1201 {
1202 gDesiredDebugMode = gDebugMode = false;
1203 }
1204 #endif //#ifdef MOZ_JSDEBUGGER
1207 void
1208 xpc_ActivateDebugMode()
1209 {
1210 XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
1211 nsXPConnect::XPConnect()->SetDebugModeWhenPossible(true, true);
1212 nsXPConnect::CheckForDebugMode(rt->Runtime());
1213 }
1215 /* virtual */
1216 JSContext*
1217 nsXPConnect::GetCurrentJSContext()
1218 {
1219 return GetRuntime()->GetJSContextStack()->Peek();
1220 }
1222 /* virtual */
1223 JSContext*
1224 nsXPConnect::InitSafeJSContext()
1225 {
1226 return GetRuntime()->GetJSContextStack()->InitSafeJSContext();
1227 }
1229 /* virtual */
1230 JSContext*
1231 nsXPConnect::GetSafeJSContext()
1232 {
1233 return GetRuntime()->GetJSContextStack()->GetSafeJSContext();
1234 }
1236 namespace xpc {
1238 bool
1239 PushJSContextNoScriptContext(JSContext *aCx)
1240 {
1241 MOZ_ASSERT_IF(aCx, !GetScriptContextFromJSContext(aCx));
1242 return XPCJSRuntime::Get()->GetJSContextStack()->Push(aCx);
1243 }
1245 void
1246 PopJSContextNoScriptContext()
1247 {
1248 XPCJSRuntime::Get()->GetJSContextStack()->Pop();
1249 }
1251 } // namespace xpc
1253 nsIPrincipal*
1254 nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const
1255 {
1256 MOZ_ASSERT(IS_WN_REFLECTOR(obj), "What kind of wrapper is this?");
1258 XPCWrappedNative *xpcWrapper = XPCWrappedNative::Get(obj);
1259 if (xpcWrapper) {
1260 if (allowShortCircuit) {
1261 nsIPrincipal *result = xpcWrapper->GetObjectPrincipal();
1262 if (result) {
1263 return result;
1264 }
1265 }
1267 // If not, check if it points to an nsIScriptObjectPrincipal
1268 nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
1269 do_QueryInterface(xpcWrapper->Native());
1270 if (objPrin) {
1271 nsIPrincipal *result = objPrin->GetPrincipal();
1272 if (result) {
1273 return result;
1274 }
1275 }
1276 }
1278 return nullptr;
1279 }
1281 NS_IMETHODIMP
1282 nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObjectArg,
1283 nsIXPConnectJSObjectHolder **aHolder)
1284 {
1285 RootedObject aObject(aJSContext, aObjectArg);
1286 XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(aObject);
1287 if (!objHolder)
1288 return NS_ERROR_OUT_OF_MEMORY;
1290 NS_ADDREF(*aHolder = objHolder);
1291 return NS_OK;
1292 }
1294 namespace xpc {
1296 bool
1297 Base64Encode(JSContext *cx, HandleValue val, MutableHandleValue out)
1298 {
1299 MOZ_ASSERT(cx);
1301 JS::RootedValue root(cx, val);
1302 xpc_qsACString encodedString(cx, root, &root, false,
1303 xpc_qsACString::eStringify,
1304 xpc_qsACString::eStringify);
1305 if (!encodedString.IsValid())
1306 return false;
1308 nsAutoCString result;
1309 if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
1310 JS_ReportError(cx, "Failed to encode base64 data!");
1311 return false;
1312 }
1314 JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
1315 if (!str)
1316 return false;
1318 out.setString(str);
1319 return true;
1320 }
1322 bool
1323 Base64Decode(JSContext *cx, HandleValue val, MutableHandleValue out)
1324 {
1325 MOZ_ASSERT(cx);
1327 JS::RootedValue root(cx, val);
1328 xpc_qsACString encodedString(cx, root, &root, false,
1329 xpc_qsACString::eStringify,
1330 xpc_qsACString::eStringify);
1331 if (!encodedString.IsValid())
1332 return false;
1334 nsAutoCString result;
1335 if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
1336 JS_ReportError(cx, "Failed to decode base64 string!");
1337 return false;
1338 }
1340 JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
1341 if (!str)
1342 return false;
1344 out.setString(str);
1345 return true;
1346 }
1348 void
1349 SetLocationForGlobal(JSObject *global, const nsACString& location)
1350 {
1351 MOZ_ASSERT(global);
1352 EnsureCompartmentPrivate(global)->SetLocation(location);
1353 }
1355 void
1356 SetLocationForGlobal(JSObject *global, nsIURI *locationURI)
1357 {
1358 MOZ_ASSERT(global);
1359 EnsureCompartmentPrivate(global)->SetLocationURI(locationURI);
1360 }
1362 } // namespace xpc
1364 NS_IMETHODIMP
1365 nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable)
1366 {
1367 gDesiredDebugMode = mode;
1368 if (!mode && allowSyncDisable)
1369 CheckForDebugMode(mRuntime->Runtime());
1370 return NS_OK;
1371 }
1373 NS_IMETHODIMP
1374 nsXPConnect::NotifyDidPaint()
1375 {
1376 JS::NotifyDidPaint(GetRuntime()->Runtime());
1377 return NS_OK;
1378 }
1380 // Note - We used to have HAS_PRINCIPALS_FLAG = 1 here, so reusing that flag
1381 // will require bumping the XDR version number.
1382 static const uint8_t HAS_ORIGIN_PRINCIPALS_FLAG = 2;
1384 static nsresult
1385 WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx,
1386 JSScript *scriptArg, HandleObject functionObj)
1387 {
1388 // Exactly one of script or functionObj must be given
1389 MOZ_ASSERT(!scriptArg != !functionObj);
1391 RootedScript script(cx, scriptArg);
1392 if (!script) {
1393 RootedFunction fun(cx, JS_GetObjectFunction(functionObj));
1394 script.set(JS_GetFunctionScript(cx, fun));
1395 }
1397 nsIPrincipal *principal =
1398 nsJSPrincipals::get(JS_GetScriptPrincipals(script));
1399 nsIPrincipal *originPrincipal =
1400 nsJSPrincipals::get(JS_GetScriptOriginPrincipals(script));
1402 uint8_t flags = 0;
1404 // Optimize for the common case when originPrincipals == principals. As
1405 // originPrincipals is set to principals when the former is null we can
1406 // simply skip the originPrincipals when they are the same as principals.
1407 if (originPrincipal && originPrincipal != principal)
1408 flags |= HAS_ORIGIN_PRINCIPALS_FLAG;
1410 nsresult rv = stream->Write8(flags);
1411 if (NS_FAILED(rv))
1412 return rv;
1414 if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
1415 rv = stream->WriteObject(originPrincipal, true);
1416 if (NS_FAILED(rv))
1417 return rv;
1418 }
1420 uint32_t size;
1421 void* data;
1422 {
1423 if (functionObj)
1424 data = JS_EncodeInterpretedFunction(cx, functionObj, &size);
1425 else
1426 data = JS_EncodeScript(cx, script, &size);
1427 }
1429 if (!data)
1430 return NS_ERROR_OUT_OF_MEMORY;
1431 MOZ_ASSERT(size);
1432 rv = stream->Write32(size);
1433 if (NS_SUCCEEDED(rv))
1434 rv = stream->WriteBytes(static_cast<char *>(data), size);
1435 js_free(data);
1437 return rv;
1438 }
1440 static nsresult
1441 ReadScriptOrFunction(nsIObjectInputStream *stream, JSContext *cx,
1442 JSScript **scriptp, JSObject **functionObjp)
1443 {
1444 // Exactly one of script or functionObj must be given
1445 MOZ_ASSERT(!scriptp != !functionObjp);
1447 uint8_t flags;
1448 nsresult rv = stream->Read8(&flags);
1449 if (NS_FAILED(rv))
1450 return rv;
1452 nsJSPrincipals* originPrincipal = nullptr;
1453 nsCOMPtr<nsIPrincipal> readOriginPrincipal;
1454 if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
1455 nsCOMPtr<nsISupports> supports;
1456 rv = stream->ReadObject(true, getter_AddRefs(supports));
1457 if (NS_FAILED(rv))
1458 return rv;
1459 readOriginPrincipal = do_QueryInterface(supports);
1460 originPrincipal = nsJSPrincipals::get(readOriginPrincipal);
1461 }
1463 uint32_t size;
1464 rv = stream->Read32(&size);
1465 if (NS_FAILED(rv))
1466 return rv;
1468 char* data;
1469 rv = stream->ReadBytes(size, &data);
1470 if (NS_FAILED(rv))
1471 return rv;
1473 {
1474 if (scriptp) {
1475 JSScript *script = JS_DecodeScript(cx, data, size, originPrincipal);
1476 if (!script)
1477 rv = NS_ERROR_OUT_OF_MEMORY;
1478 else
1479 *scriptp = script;
1480 } else {
1481 JSObject *funobj = JS_DecodeInterpretedFunction(cx, data, size,
1482 originPrincipal);
1483 if (!funobj)
1484 rv = NS_ERROR_OUT_OF_MEMORY;
1485 else
1486 *functionObjp = funobj;
1487 }
1488 }
1490 nsMemory::Free(data);
1491 return rv;
1492 }
1494 NS_IMETHODIMP
1495 nsXPConnect::WriteScript(nsIObjectOutputStream *stream, JSContext *cx, JSScript *script)
1496 {
1497 return WriteScriptOrFunction(stream, cx, script, NullPtr());
1498 }
1500 NS_IMETHODIMP
1501 nsXPConnect::ReadScript(nsIObjectInputStream *stream, JSContext *cx, JSScript **scriptp)
1502 {
1503 return ReadScriptOrFunction(stream, cx, scriptp, nullptr);
1504 }
1506 NS_IMETHODIMP
1507 nsXPConnect::WriteFunction(nsIObjectOutputStream *stream, JSContext *cx, JSObject *functionObjArg)
1508 {
1509 RootedObject functionObj(cx, functionObjArg);
1510 return WriteScriptOrFunction(stream, cx, nullptr, functionObj);
1511 }
1513 NS_IMETHODIMP
1514 nsXPConnect::ReadFunction(nsIObjectInputStream *stream, JSContext *cx, JSObject **functionObjp)
1515 {
1516 return ReadScriptOrFunction(stream, cx, nullptr, functionObjp);
1517 }
1519 NS_IMETHODIMP
1520 nsXPConnect::MarkErrorUnreported(JSContext *cx)
1521 {
1522 XPCContext *xpcc = XPCContext::GetXPCContext(cx);
1523 xpcc->MarkErrorUnreported();
1524 return NS_OK;
1525 }
1527 /* These are here to be callable from a debugger */
1528 extern "C" {
1529 JS_EXPORT_API(void) DumpJSStack()
1530 {
1531 nsresult rv;
1532 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1533 if (NS_SUCCEEDED(rv) && xpc)
1534 xpc->DebugDumpJSStack(true, true, false);
1535 else
1536 printf("failed to get XPConnect service!\n");
1537 }
1539 JS_EXPORT_API(char*) PrintJSStack()
1540 {
1541 nsresult rv;
1542 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1543 return (NS_SUCCEEDED(rv) && xpc) ?
1544 xpc->DebugPrintJSStack(true, true, false) :
1545 nullptr;
1546 }
1548 JS_EXPORT_API(void) DumpJSEval(uint32_t frameno, const char* text)
1549 {
1550 nsresult rv;
1551 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1552 if (NS_SUCCEEDED(rv) && xpc)
1553 xpc->DebugDumpEvalInJSStackFrame(frameno, text);
1554 else
1555 printf("failed to get XPConnect service!\n");
1556 }
1558 JS_EXPORT_API(void) DumpCompleteHeap()
1559 {
1560 nsCOMPtr<nsICycleCollectorListener> listener =
1561 do_CreateInstance("@mozilla.org/cycle-collector-logger;1");
1562 if (!listener) {
1563 NS_WARNING("Failed to create CC logger");
1564 return;
1565 }
1567 nsCOMPtr<nsICycleCollectorListener> alltracesListener;
1568 listener->AllTraces(getter_AddRefs(alltracesListener));
1569 if (!alltracesListener) {
1570 NS_WARNING("Failed to get all traces logger");
1571 return;
1572 }
1574 nsJSContext::CycleCollectNow(alltracesListener);
1575 }
1577 } // extern "C"
1579 namespace xpc {
1581 bool
1582 Atob(JSContext *cx, unsigned argc, Value *vp)
1583 {
1584 CallArgs args = CallArgsFromVp(argc, vp);
1585 if (!args.length())
1586 return true;
1588 return xpc::Base64Decode(cx, args[0], args.rval());
1589 }
1591 bool
1592 Btoa(JSContext *cx, unsigned argc, Value *vp)
1593 {
1594 CallArgs args = CallArgsFromVp(argc, vp);
1595 if (!args.length())
1596 return true;
1598 return xpc::Base64Encode(cx, args[0], args.rval());
1599 }
1601 bool
1602 IsXrayWrapper(JSObject *obj)
1603 {
1604 return WrapperFactory::IsXrayWrapper(obj);
1605 }
1607 } // namespace xpc
1609 namespace mozilla {
1610 namespace dom {
1612 bool
1613 IsChromeOrXBL(JSContext* cx, JSObject* /* unused */)
1614 {
1615 MOZ_ASSERT(NS_IsMainThread());
1616 JSCompartment* c = js::GetContextCompartment(cx);
1618 // For remote XUL, we run XBL in the XUL scope. Given that we care about
1619 // compat and not security for remote XUL, we just always claim to be XBL.
1620 //
1621 // Note that, for performance, we don't check AllowXULXBLForPrincipal here,
1622 // and instead rely on the fact that AllowXBLScope() only returns false in
1623 // remote XUL situations.
1624 return AccessCheck::isChrome(c) || IsXBLScope(c) || !AllowXBLScope(c);
1625 }
1627 } // namespace dom
1628 } // namespace mozilla