Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /* High level class and public functions implementation. */
8 :
9 : #include "mozilla/Assertions.h"
10 : #include "mozilla/Base64.h"
11 : #include "mozilla/Likely.h"
12 : #include "mozilla/Unused.h"
13 :
14 : #include "xpcprivate.h"
15 : #include "XPCWrapper.h"
16 : #include "jsfriendapi.h"
17 : #include "nsJSEnvironment.h"
18 : #include "nsThreadUtils.h"
19 : #include "nsDOMJSUtils.h"
20 :
21 : #include "WrapperFactory.h"
22 : #include "AccessCheck.h"
23 :
24 : #include "mozilla/dom/BindingUtils.h"
25 : #include "mozilla/dom/DOMException.h"
26 : #include "mozilla/dom/Exceptions.h"
27 : #include "mozilla/dom/Promise.h"
28 :
29 : #include "nsDOMMutationObserver.h"
30 : #include "nsICycleCollectorListener.h"
31 : #include "mozilla/XPTInterfaceInfoManager.h"
32 : #include "nsIObjectInputStream.h"
33 : #include "nsIObjectOutputStream.h"
34 : #include "nsScriptSecurityManager.h"
35 : #include "nsIPermissionManager.h"
36 : #include "nsIScriptError.h"
37 : #include "nsContentUtils.h"
38 : #include "nsScriptError.h"
39 : #include "jsfriendapi.h"
40 :
41 : using namespace mozilla;
42 : using namespace mozilla::dom;
43 : using namespace xpc;
44 : using namespace JS;
45 :
46 98291 : NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)
47 :
48 : nsXPConnect* nsXPConnect::gSelf = nullptr;
49 : bool nsXPConnect::gOnceAliveNowDead = false;
50 :
51 : // Global cache of the default script security manager (QI'd to
52 : // nsIScriptSecurityManager) and the system principal.
53 : nsIScriptSecurityManager* nsXPConnect::gScriptSecurityManager = nullptr;
54 : nsIPrincipal* nsXPConnect::gSystemPrincipal = nullptr;
55 :
56 : const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
57 : const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1";
58 : const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1";
59 : const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1";
60 : const char XPC_ID_CONTRACTID[] = "@mozilla.org/js/xpc/ID;1";
61 : const char XPC_XPCONNECT_CONTRACTID[] = "@mozilla.org/js/xpc/XPConnect;1";
62 :
63 : /***************************************************************************/
64 :
65 : // This global should be used very sparingly: only to create and destroy
66 : // nsXPConnect and when creating a new cooperative (non-primary) XPCJSContext.
67 : static XPCJSContext* gPrimaryContext;
68 :
69 3 : nsXPConnect::nsXPConnect()
70 3 : : mShuttingDown(false)
71 : {
72 3 : XPCJSContext::InitTLS();
73 :
74 3 : XPCJSContext* xpccx = XPCJSContext::NewXPCJSContext(nullptr);
75 3 : if (!xpccx) {
76 0 : NS_RUNTIMEABORT("Couldn't create XPCJSContext.");
77 : }
78 3 : gPrimaryContext = xpccx;
79 3 : mRuntime = xpccx->Runtime();
80 3 : }
81 :
82 0 : nsXPConnect::~nsXPConnect()
83 : {
84 0 : MOZ_ASSERT(XPCJSContext::Get() == gPrimaryContext);
85 :
86 0 : mRuntime->DeleteSingletonScopes();
87 :
88 : // In order to clean up everything properly, we need to GC twice: once now,
89 : // to clean anything that can go away on its own (like the Junk Scope, which
90 : // we unrooted above), and once after forcing a bunch of shutdown in
91 : // XPConnect, to clean the stuff we forcibly disconnected. The forced
92 : // shutdown code defaults to leaking in a number of situations, so we can't
93 : // get by with only the second GC. :-(
94 0 : mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
95 :
96 0 : mShuttingDown = true;
97 0 : XPCWrappedNativeScope::SystemIsBeingShutDown();
98 :
99 : // The above causes us to clean up a bunch of XPConnect data structures,
100 : // after which point we need to GC to clean everything up. We need to do
101 : // this before deleting the XPCJSContext, because doing so destroys the
102 : // maps that our finalize callback depends on.
103 0 : mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
104 :
105 0 : NS_RELEASE(gSystemPrincipal);
106 0 : gScriptSecurityManager = nullptr;
107 :
108 : // shutdown the logging system
109 0 : XPC_LOG_FINISH();
110 :
111 0 : delete gPrimaryContext;
112 :
113 0 : gSelf = nullptr;
114 0 : gOnceAliveNowDead = true;
115 0 : }
116 :
117 : // static
118 : void
119 3 : nsXPConnect::InitStatics()
120 : {
121 3 : gSelf = new nsXPConnect();
122 3 : gOnceAliveNowDead = false;
123 :
124 : // Initial extra ref to keep the singleton alive
125 : // balanced by explicit call to ReleaseXPConnectSingleton()
126 3 : NS_ADDREF(gSelf);
127 :
128 : // Fire up the SSM.
129 3 : nsScriptSecurityManager::InitStatics();
130 3 : gScriptSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
131 3 : gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal);
132 3 : MOZ_RELEASE_ASSERT(gSystemPrincipal);
133 :
134 3 : JSContext* cx = XPCJSContext::Get()->Context();
135 3 : if (!JS::InitSelfHostedCode(cx))
136 0 : MOZ_CRASH("InitSelfHostedCode failed");
137 3 : if (!gSelf->mRuntime->InitializeStrings(cx))
138 0 : MOZ_CRASH("InitializeStrings failed");
139 :
140 : // Initialize our singleton scopes.
141 3 : gSelf->mRuntime->InitSingletonScopes();
142 3 : }
143 :
144 : nsXPConnect*
145 1 : nsXPConnect::GetSingleton()
146 : {
147 1 : nsXPConnect* xpc = nsXPConnect::XPConnect();
148 1 : NS_IF_ADDREF(xpc);
149 1 : return xpc;
150 : }
151 :
152 : // static
153 : void
154 0 : nsXPConnect::ReleaseXPConnectSingleton()
155 : {
156 0 : nsXPConnect* xpc = gSelf;
157 0 : if (xpc) {
158 : nsrefcnt cnt;
159 0 : NS_RELEASE2(xpc, cnt);
160 : }
161 0 : }
162 :
163 : // static
164 : XPCJSRuntime*
165 40946 : nsXPConnect::GetRuntimeInstance()
166 : {
167 40946 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
168 40946 : return gSelf->mRuntime;
169 : }
170 :
171 : // static
172 : bool
173 1917 : nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info)
174 : {
175 1917 : bool found = false;
176 1917 : if (info)
177 1917 : info->HasAncestor(&NS_GET_IID(nsISupports), &found);
178 1917 : return found;
179 : }
180 :
181 : void
182 0 : xpc::ErrorBase::Init(JSErrorBase* aReport)
183 : {
184 0 : if (!aReport->filename)
185 0 : mFileName.SetIsVoid(true);
186 : else
187 0 : mFileName.AssignWithConversion(aReport->filename);
188 :
189 0 : mLineNumber = aReport->lineno;
190 0 : mColumn = aReport->column;
191 0 : }
192 :
193 : void
194 0 : xpc::ErrorNote::Init(JSErrorNotes::Note* aNote)
195 : {
196 0 : xpc::ErrorBase::Init(aNote);
197 :
198 0 : ErrorNoteToMessageString(aNote, mErrorMsg);
199 0 : }
200 :
201 : void
202 0 : xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aToStringResult,
203 : bool aIsChrome, uint64_t aWindowID)
204 : {
205 0 : xpc::ErrorBase::Init(aReport);
206 0 : mCategory = aIsChrome ? NS_LITERAL_CSTRING("chrome javascript")
207 0 : : NS_LITERAL_CSTRING("content javascript");
208 0 : mWindowID = aWindowID;
209 :
210 0 : ErrorReportToMessageString(aReport, mErrorMsg);
211 0 : if (mErrorMsg.IsEmpty() && aToStringResult) {
212 0 : AppendUTF8toUTF16(aToStringResult, mErrorMsg);
213 : }
214 :
215 0 : mSourceLine.Assign(aReport->linebuf(), aReport->linebufLength());
216 0 : const JSErrorFormatString* efs = js::GetErrorMessage(nullptr, aReport->errorNumber);
217 :
218 0 : if (efs == nullptr) {
219 0 : mErrorMsgName.AssignASCII("");
220 : } else {
221 0 : mErrorMsgName.AssignASCII(efs->name);
222 : }
223 :
224 0 : mFlags = aReport->flags;
225 0 : mIsMuted = aReport->isMuted;
226 :
227 0 : if (aReport->notes) {
228 0 : if (!mNotes.SetLength(aReport->notes->length(), fallible))
229 0 : return;
230 :
231 0 : size_t i = 0;
232 0 : for (auto&& note : *aReport->notes) {
233 0 : mNotes.ElementAt(i).Init(note.get());
234 0 : i++;
235 : }
236 : }
237 : }
238 :
239 : void
240 0 : xpc::ErrorReport::Init(JSContext* aCx, mozilla::dom::Exception* aException,
241 : bool aIsChrome, uint64_t aWindowID)
242 : {
243 0 : mCategory = aIsChrome ? NS_LITERAL_CSTRING("chrome javascript")
244 0 : : NS_LITERAL_CSTRING("content javascript");
245 0 : mWindowID = aWindowID;
246 :
247 0 : aException->GetErrorMessage(mErrorMsg);
248 :
249 0 : aException->GetFilename(aCx, mFileName);
250 0 : if (mFileName.IsEmpty()) {
251 0 : mFileName.SetIsVoid(true);
252 : }
253 0 : aException->GetLineNumber(aCx, &mLineNumber);
254 0 : aException->GetColumnNumber(&mColumn);
255 :
256 0 : mFlags = JSREPORT_EXCEPTION;
257 0 : }
258 :
259 : static LazyLogModule gJSDiagnostics("JSDiagnostics");
260 :
261 : void
262 0 : xpc::ErrorBase::AppendErrorDetailsTo(nsCString& error)
263 : {
264 0 : error.Append(NS_LossyConvertUTF16toASCII(mFileName));
265 0 : error.AppendLiteral(", line ");
266 0 : error.AppendInt(mLineNumber, 10);
267 0 : error.AppendLiteral(": ");
268 0 : error.Append(NS_LossyConvertUTF16toASCII(mErrorMsg));
269 0 : }
270 :
271 : void
272 0 : xpc::ErrorNote::LogToStderr()
273 : {
274 0 : if (!nsContentUtils::DOMWindowDumpEnabled())
275 0 : return;
276 :
277 0 : nsAutoCString error;
278 0 : error.AssignLiteral("JavaScript note: ");
279 0 : AppendErrorDetailsTo(error);
280 :
281 0 : fprintf(stderr, "%s\n", error.get());
282 0 : fflush(stderr);
283 : }
284 :
285 : void
286 0 : xpc::ErrorReport::LogToStderr()
287 : {
288 0 : if (!nsContentUtils::DOMWindowDumpEnabled())
289 0 : return;
290 :
291 0 : nsAutoCString error;
292 0 : error.AssignLiteral("JavaScript ");
293 0 : if (JSREPORT_IS_STRICT(mFlags))
294 0 : error.AppendLiteral("strict ");
295 0 : if (JSREPORT_IS_WARNING(mFlags))
296 0 : error.AppendLiteral("warning: ");
297 : else
298 0 : error.AppendLiteral("error: ");
299 0 : AppendErrorDetailsTo(error);
300 :
301 0 : fprintf(stderr, "%s\n", error.get());
302 0 : fflush(stderr);
303 :
304 0 : for (size_t i = 0, len = mNotes.Length(); i < len; i++) {
305 0 : ErrorNote& note = mNotes[i];
306 0 : note.LogToStderr();
307 : }
308 : }
309 :
310 : void
311 0 : xpc::ErrorReport::LogToConsole()
312 : {
313 0 : LogToConsoleWithStack(nullptr);
314 0 : }
315 : void
316 0 : xpc::ErrorReport::LogToConsoleWithStack(JS::HandleObject aStack)
317 : {
318 0 : LogToStderr();
319 :
320 0 : MOZ_LOG(gJSDiagnostics,
321 : JSREPORT_IS_WARNING(mFlags) ? LogLevel::Warning : LogLevel::Error,
322 : ("file %s, line %u\n%s", NS_LossyConvertUTF16toASCII(mFileName).get(),
323 : mLineNumber, NS_LossyConvertUTF16toASCII(mErrorMsg).get()));
324 :
325 : // Log to the console. We do this last so that we can simply return if
326 : // there's no console service without affecting the other reporting
327 : // mechanisms.
328 : nsCOMPtr<nsIConsoleService> consoleService =
329 0 : do_GetService(NS_CONSOLESERVICE_CONTRACTID);
330 0 : NS_ENSURE_TRUE_VOID(consoleService);
331 :
332 0 : RefPtr<nsScriptErrorBase> errorObject;
333 0 : if (mWindowID && aStack) {
334 : // Only set stack on messages related to a document
335 : // As we cache messages in the console service,
336 : // we have to ensure not leaking them after the related
337 : // context is destroyed and we only track document lifecycle for now.
338 0 : errorObject = new nsScriptErrorWithStack(aStack);
339 : } else {
340 0 : errorObject = new nsScriptError();
341 : }
342 0 : errorObject->SetErrorMessageName(mErrorMsgName);
343 :
344 0 : nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName, mSourceLine,
345 : mLineNumber, mColumn, mFlags,
346 0 : mCategory, mWindowID);
347 0 : NS_ENSURE_SUCCESS_VOID(rv);
348 :
349 0 : for (size_t i = 0, len = mNotes.Length(); i < len; i++) {
350 0 : ErrorNote& note = mNotes[i];
351 :
352 0 : nsScriptErrorNote* noteObject = new nsScriptErrorNote();
353 0 : noteObject->Init(note.mErrorMsg, note.mFileName,
354 0 : note.mLineNumber, note.mColumn);
355 0 : errorObject->AddNote(noteObject);
356 : }
357 :
358 0 : consoleService->LogMessage(errorObject);
359 :
360 : }
361 :
362 : /* static */
363 : void
364 0 : xpc::ErrorNote::ErrorNoteToMessageString(JSErrorNotes::Note* aNote,
365 : nsAString& aString)
366 : {
367 0 : aString.Truncate();
368 0 : if (aNote->message())
369 0 : aString.Append(NS_ConvertUTF8toUTF16(aNote->message().c_str()));
370 0 : }
371 :
372 : /* static */
373 : void
374 0 : xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport,
375 : nsAString& aString)
376 : {
377 0 : aString.Truncate();
378 0 : if (aReport->message()) {
379 0 : JSFlatString* name = js::GetErrorTypeName(CycleCollectedJSContext::Get()->Context(), aReport->exnType);
380 0 : if (name) {
381 0 : AssignJSFlatString(aString, name);
382 0 : aString.AppendLiteral(": ");
383 : }
384 0 : aString.Append(NS_ConvertUTF8toUTF16(aReport->message().c_str()));
385 : }
386 0 : }
387 :
388 : /***************************************************************************/
389 :
390 :
391 : nsresult
392 683 : nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info)
393 : {
394 683 : return XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(aIID, info);
395 : }
396 :
397 : nsresult
398 0 : nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
399 : {
400 0 : nsresult rv = XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, info);
401 0 : return NS_FAILED(rv) ? NS_OK : NS_ERROR_NO_INTERFACE;
402 : }
403 :
404 : NS_IMETHODIMP
405 0 : nsXPConnect::GarbageCollect(uint32_t reason)
406 : {
407 0 : mRuntime->GarbageCollect(reason);
408 0 : return NS_OK;
409 : }
410 :
411 : void
412 0 : xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration)
413 : {
414 0 : nsCOMPtr<XPCVariant> variant = do_QueryInterface(aVariant);
415 0 : if (variant) {
416 0 : variant->SetCCGeneration(aGeneration);
417 0 : variant->GetJSVal(); // Unmarks gray JSObject.
418 0 : XPCVariant* weak = variant.get();
419 0 : variant = nullptr;
420 0 : if (weak->IsPurple()) {
421 0 : weak->RemovePurple();
422 : }
423 : }
424 0 : }
425 :
426 : void
427 0 : xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS)
428 : {
429 : // QIing to nsIXPConnectWrappedJSUnmarkGray may have side effects!
430 : nsCOMPtr<nsIXPConnectWrappedJSUnmarkGray> wjsug =
431 0 : do_QueryInterface(aWrappedJS);
432 : Unused << wjsug;
433 0 : MOZ_ASSERT(!wjsug, "One should never be able to QI to "
434 : "nsIXPConnectWrappedJSUnmarkGray successfully!");
435 0 : }
436 :
437 : /***************************************************************************/
438 : /***************************************************************************/
439 : // nsIXPConnect interface methods...
440 :
441 : template<typename T>
442 0 : static inline T UnexpectedFailure(T rv)
443 : {
444 0 : NS_ERROR("This is not supposed to fail!");
445 0 : return rv;
446 : }
447 :
448 : void
449 26 : xpc::TraceXPCGlobal(JSTracer* trc, JSObject* obj)
450 : {
451 26 : if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
452 26 : mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
453 :
454 : // We might be called from a GC during the creation of a global, before we've
455 : // been able to set up the compartment private or the XPCWrappedNativeScope,
456 : // so we need to null-check those.
457 26 : xpc::CompartmentPrivate* compartmentPrivate = xpc::CompartmentPrivate::Get(obj);
458 26 : if (compartmentPrivate && compartmentPrivate->scope)
459 26 : compartmentPrivate->scope->TraceInside(trc);
460 26 : }
461 :
462 :
463 : namespace xpc {
464 :
465 : JSObject*
466 286 : CreateGlobalObject(JSContext* cx, const JSClass* clasp, nsIPrincipal* principal,
467 : JS::CompartmentOptions& aOptions)
468 : {
469 286 : MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
470 286 : MOZ_ASSERT(principal);
471 :
472 286 : MOZ_RELEASE_ASSERT(principal != nsContentUtils::GetNullSubjectPrincipal(),
473 : "The null subject principal is getting inherited - fix that!");
474 :
475 : RootedObject global(cx,
476 572 : JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
477 572 : JS::DontFireOnNewGlobalHook, aOptions));
478 286 : if (!global)
479 0 : return nullptr;
480 572 : JSAutoCompartment ac(cx, global);
481 :
482 : // The constructor automatically attaches the scope to the compartment private
483 : // of |global|.
484 572 : (void) new XPCWrappedNativeScope(cx, global);
485 :
486 286 : if (clasp->flags & JSCLASS_DOM_GLOBAL) {
487 : #ifdef DEBUG
488 : // Verify that the right trace hook is called. Note that this doesn't
489 : // work right for wrapped globals, since the tracing situation there is
490 : // more complicated. Manual inspection shows that they do the right
491 : // thing. Also note that we only check this for JSCLASS_DOM_GLOBAL
492 : // classes because xpc::TraceXPCGlobal won't call
493 : // TraceProtoAndIfaceCache unless that flag is set.
494 285 : if (!((const js::Class*)clasp)->isWrappedNative())
495 : {
496 25 : VerifyTraceProtoAndIfaceCacheCalledTracer trc(cx);
497 25 : TraceChildren(&trc, GCCellPtr(global.get()));
498 25 : MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
499 : }
500 : #endif
501 :
502 285 : const char* className = clasp->name;
503 570 : AllocateProtoAndIfaceCache(global,
504 570 : (strcmp(className, "Window") == 0 ||
505 285 : strcmp(className, "ChromeWindow") == 0)
506 : ? ProtoAndIfaceCache::WindowLike
507 570 : : ProtoAndIfaceCache::NonWindowLike);
508 : }
509 :
510 286 : return global;
511 : }
512 :
513 : void
514 267 : InitGlobalObjectOptions(JS::CompartmentOptions& aOptions,
515 : nsIPrincipal* aPrincipal)
516 : {
517 267 : bool shouldDiscardSystemSource = ShouldDiscardSystemSource();
518 267 : bool extraWarningsForSystemJS = ExtraWarningsForSystemJS();
519 :
520 267 : bool isSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
521 :
522 267 : if (isSystem) {
523 : // Make sure [SecureContext] APIs are visible:
524 263 : aOptions.creationOptions().setSecureContext(true);
525 : }
526 :
527 267 : if (shouldDiscardSystemSource) {
528 0 : bool discardSource = isSystem;
529 :
530 0 : aOptions.behaviors().setDiscardSource(discardSource);
531 : }
532 :
533 267 : if (extraWarningsForSystemJS) {
534 0 : if (isSystem)
535 0 : aOptions.behaviors().extraWarningsOverride().set(true);
536 : }
537 267 : }
538 :
539 : bool
540 267 : InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags)
541 : {
542 : // Immediately enter the global's compartment so that everything we create
543 : // ends up there.
544 534 : JSAutoCompartment ac(aJSContext, aGlobal);
545 :
546 : // Stuff coming through this path always ends up as a DOM global.
547 267 : MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
548 :
549 267 : if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
550 : // XPCCallContext gives us an active request needed to save/restore.
551 526 : if (!CompartmentPrivate::Get(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
552 263 : !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
553 0 : return UnexpectedFailure(false);
554 : }
555 : }
556 :
557 267 : if (!(aFlags & nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK))
558 5 : JS_FireOnNewGlobalObject(aJSContext, aGlobal);
559 :
560 267 : return true;
561 : }
562 :
563 : } // namespace xpc
564 :
565 : NS_IMETHODIMP
566 260 : nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
567 : nsISupports* aCOMObj,
568 : nsIPrincipal * aPrincipal,
569 : uint32_t aFlags,
570 : JS::CompartmentOptions& aOptions,
571 : nsIXPConnectJSObjectHolder** _retval)
572 : {
573 260 : MOZ_ASSERT(aJSContext, "bad param");
574 260 : MOZ_ASSERT(aCOMObj, "bad param");
575 260 : MOZ_ASSERT(_retval, "bad param");
576 :
577 : // We pass null for the 'extra' pointer during global object creation, so
578 : // we need to have a principal.
579 260 : MOZ_ASSERT(aPrincipal);
580 :
581 260 : InitGlobalObjectOptions(aOptions, aPrincipal);
582 :
583 : // Call into XPCWrappedNative to make a new global object, scope, and global
584 : // prototype.
585 520 : xpcObjectHelper helper(aCOMObj);
586 260 : MOZ_ASSERT(helper.GetScriptableFlags() & XPC_SCRIPTABLE_IS_GLOBAL_OBJECT);
587 520 : RefPtr<XPCWrappedNative> wrappedGlobal;
588 : nsresult rv =
589 520 : XPCWrappedNative::WrapNewGlobal(helper, aPrincipal,
590 260 : aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
591 520 : aOptions, getter_AddRefs(wrappedGlobal));
592 260 : NS_ENSURE_SUCCESS(rv, rv);
593 :
594 : // Grab a copy of the global and enter its compartment.
595 520 : RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
596 260 : MOZ_ASSERT(JS_IsGlobalObject(global));
597 :
598 260 : if (!InitGlobalObject(aJSContext, global, aFlags))
599 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
600 :
601 260 : wrappedGlobal.forget(_retval);
602 260 : return NS_OK;
603 : }
604 :
605 : static nsresult
606 5847 : NativeInterface2JSObject(HandleObject aScope,
607 : nsISupports* aCOMObj,
608 : nsWrapperCache* aCache,
609 : const nsIID * aIID,
610 : bool aAllowWrapping,
611 : MutableHandleValue aVal,
612 : nsIXPConnectJSObjectHolder** aHolder)
613 : {
614 11694 : AutoJSContext cx;
615 11694 : JSAutoCompartment ac(cx, aScope);
616 :
617 : nsresult rv;
618 11694 : xpcObjectHelper helper(aCOMObj, aCache);
619 5847 : if (!XPCConvert::NativeInterface2JSObject(aVal, aHolder, helper, aIID,
620 : aAllowWrapping, &rv))
621 0 : return rv;
622 :
623 5847 : MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
624 : "Shouldn't be returning a xray wrapper here");
625 :
626 5847 : return NS_OK;
627 : }
628 :
629 : NS_IMETHODIMP
630 2103 : nsXPConnect::WrapNative(JSContext * aJSContext,
631 : JSObject * aScopeArg,
632 : nsISupports* aCOMObj,
633 : const nsIID & aIID,
634 : JSObject** aRetVal)
635 : {
636 2103 : MOZ_ASSERT(aJSContext, "bad param");
637 2103 : MOZ_ASSERT(aScopeArg, "bad param");
638 2103 : MOZ_ASSERT(aCOMObj, "bad param");
639 :
640 4206 : RootedObject aScope(aJSContext, aScopeArg);
641 4206 : RootedValue v(aJSContext);
642 4206 : nsresult rv = NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
643 2103 : true, &v, nullptr);
644 2103 : if (NS_FAILED(rv))
645 0 : return rv;
646 :
647 2103 : if (!v.isObjectOrNull())
648 0 : return NS_ERROR_FAILURE;
649 :
650 2103 : *aRetVal = v.toObjectOrNull();
651 2103 : return NS_OK;
652 : }
653 :
654 : NS_IMETHODIMP
655 2 : nsXPConnect::WrapNativeHolder(JSContext * aJSContext,
656 : JSObject * aScopeArg,
657 : nsISupports* aCOMObj,
658 : const nsIID & aIID,
659 : nsIXPConnectJSObjectHolder **aHolder)
660 : {
661 2 : MOZ_ASSERT(aHolder, "bad param");
662 2 : MOZ_ASSERT(aJSContext, "bad param");
663 2 : MOZ_ASSERT(aScopeArg, "bad param");
664 2 : MOZ_ASSERT(aCOMObj, "bad param");
665 :
666 4 : RootedObject aScope(aJSContext, aScopeArg);
667 4 : RootedValue v(aJSContext);
668 4 : return NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
669 4 : true, &v, aHolder);
670 : }
671 :
672 : NS_IMETHODIMP
673 3742 : nsXPConnect::WrapNativeToJSVal(JSContext* aJSContext,
674 : JSObject* aScopeArg,
675 : nsISupports* aCOMObj,
676 : nsWrapperCache* aCache,
677 : const nsIID* aIID,
678 : bool aAllowWrapping,
679 : MutableHandleValue aVal)
680 : {
681 3742 : MOZ_ASSERT(aJSContext, "bad param");
682 3742 : MOZ_ASSERT(aScopeArg, "bad param");
683 3742 : MOZ_ASSERT(aCOMObj, "bad param");
684 :
685 7484 : RootedObject aScope(aJSContext, aScopeArg);
686 7484 : return NativeInterface2JSObject(aScope, aCOMObj, aCache, aIID,
687 7484 : aAllowWrapping, aVal, nullptr);
688 : }
689 :
690 : NS_IMETHODIMP
691 49 : nsXPConnect::WrapJS(JSContext * aJSContext,
692 : JSObject * aJSObjArg,
693 : const nsIID & aIID,
694 : void * *result)
695 : {
696 49 : MOZ_ASSERT(aJSContext, "bad param");
697 49 : MOZ_ASSERT(aJSObjArg, "bad param");
698 49 : MOZ_ASSERT(result, "bad param");
699 :
700 49 : *result = nullptr;
701 :
702 98 : RootedObject aJSObj(aJSContext, aJSObjArg);
703 98 : JSAutoCompartment ac(aJSContext, aJSObj);
704 :
705 49 : nsresult rv = NS_ERROR_UNEXPECTED;
706 49 : if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
707 : &aIID, nullptr, &rv))
708 0 : return rv;
709 49 : return NS_OK;
710 : }
711 :
712 : NS_IMETHODIMP
713 0 : nsXPConnect::JSValToVariant(JSContext* cx,
714 : HandleValue aJSVal,
715 : nsIVariant** aResult)
716 : {
717 0 : NS_PRECONDITION(aResult, "bad param");
718 :
719 0 : RefPtr<XPCVariant> variant = XPCVariant::newVariant(cx, aJSVal);
720 0 : variant.forget(aResult);
721 0 : NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
722 :
723 0 : return NS_OK;
724 : }
725 :
726 : NS_IMETHODIMP
727 18 : nsXPConnect::WrapJSAggregatedToNative(nsISupports* aOuter,
728 : JSContext* aJSContext,
729 : JSObject* aJSObjArg,
730 : const nsIID& aIID,
731 : void** result)
732 : {
733 18 : MOZ_ASSERT(aOuter, "bad param");
734 18 : MOZ_ASSERT(aJSContext, "bad param");
735 18 : MOZ_ASSERT(aJSObjArg, "bad param");
736 18 : MOZ_ASSERT(result, "bad param");
737 :
738 18 : *result = nullptr;
739 :
740 36 : RootedObject aJSObj(aJSContext, aJSObjArg);
741 : nsresult rv;
742 18 : if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
743 : &aIID, aOuter, &rv))
744 0 : return rv;
745 18 : return NS_OK;
746 : }
747 :
748 : NS_IMETHODIMP
749 77 : nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext,
750 : JSObject * aJSObjArg,
751 : nsIXPConnectWrappedNative** _retval)
752 : {
753 77 : MOZ_ASSERT(aJSContext, "bad param");
754 77 : MOZ_ASSERT(aJSObjArg, "bad param");
755 77 : MOZ_ASSERT(_retval, "bad param");
756 :
757 154 : RootedObject aJSObj(aJSContext, aJSObjArg);
758 77 : aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtWindowProxy = */ false);
759 77 : if (!aJSObj || !IS_WN_REFLECTOR(aJSObj)) {
760 0 : *_retval = nullptr;
761 0 : return NS_ERROR_FAILURE;
762 : }
763 :
764 154 : RefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj);
765 77 : temp.forget(_retval);
766 77 : return NS_OK;
767 : }
768 :
769 : already_AddRefed<nsISupports>
770 515 : xpc::UnwrapReflectorToISupports(JSObject* reflector)
771 : {
772 : // Unwrap security wrappers, if allowed.
773 515 : reflector = js::CheckedUnwrap(reflector, /* stopAtWindowProxy = */ false);
774 515 : if (!reflector)
775 0 : return nullptr;
776 :
777 : // Try XPCWrappedNatives.
778 515 : if (IS_WN_REFLECTOR(reflector)) {
779 255 : XPCWrappedNative* wn = XPCWrappedNative::Get(reflector);
780 255 : if (!wn)
781 0 : return nullptr;
782 510 : nsCOMPtr<nsISupports> native = wn->Native();
783 255 : return native.forget();
784 : }
785 :
786 : // Try DOM objects. This QI without taking a ref first is safe, because
787 : // this if non-null our thing will definitely be a DOM object, and we know
788 : // their QI to nsISupports doesn't do anything weird.
789 : nsCOMPtr<nsISupports> canonical =
790 520 : do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(reflector));
791 260 : return canonical.forget();
792 : }
793 :
794 : NS_IMETHODIMP
795 0 : nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext,
796 : JSObject * aScopeArg,
797 : nsISupports* aCOMObj,
798 : const nsIID & aIID,
799 : nsIXPConnectWrappedNative** _retval)
800 : {
801 0 : MOZ_ASSERT(aJSContext, "bad param");
802 0 : MOZ_ASSERT(aScopeArg, "bad param");
803 0 : MOZ_ASSERT(aCOMObj, "bad param");
804 0 : MOZ_ASSERT(_retval, "bad param");
805 :
806 0 : *_retval = nullptr;
807 :
808 0 : RootedObject aScope(aJSContext, aScopeArg);
809 :
810 0 : XPCWrappedNativeScope* scope = ObjectScope(aScope);
811 0 : if (!scope)
812 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
813 :
814 : RefPtr<XPCNativeInterface> iface =
815 0 : XPCNativeInterface::GetNewOrUsed(&aIID);
816 0 : if (!iface)
817 0 : return NS_ERROR_FAILURE;
818 :
819 : XPCWrappedNative* wrapper;
820 :
821 0 : nsresult rv = XPCWrappedNative::GetUsedOnly(aCOMObj, scope, iface, &wrapper);
822 0 : if (NS_FAILED(rv))
823 0 : return NS_ERROR_FAILURE;
824 0 : *_retval = static_cast<nsIXPConnectWrappedNative*>(wrapper);
825 0 : return NS_OK;
826 : }
827 :
828 : NS_IMETHODIMP
829 41 : nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack)
830 : {
831 41 : MOZ_ASSERT(aCurrentJSStack, "bad param");
832 :
833 82 : nsCOMPtr<nsIStackFrame> currentStack = dom::GetCurrentJSStack();
834 41 : currentStack.forget(aCurrentJSStack);
835 :
836 82 : return NS_OK;
837 : }
838 :
839 : NS_IMETHODIMP
840 16 : nsXPConnect::GetCurrentNativeCallContext(nsAXPCNativeCallContext * *aCurrentNativeCallContext)
841 : {
842 16 : MOZ_ASSERT(aCurrentNativeCallContext, "bad param");
843 :
844 16 : *aCurrentNativeCallContext = XPCJSContext::Get()->GetCallContext();
845 16 : return NS_OK;
846 : }
847 :
848 : NS_IMETHODIMP
849 3 : nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
850 : nsIXPCFunctionThisTranslator* aTranslator)
851 : {
852 3 : XPCJSRuntime* rt = GetRuntimeInstance();
853 3 : IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
854 3 : map->Add(aIID, aTranslator);
855 3 : return NS_OK;
856 : }
857 :
858 : NS_IMETHODIMP
859 0 : nsXPConnect::CreateSandbox(JSContext* cx, nsIPrincipal* principal,
860 : JSObject** _retval)
861 : {
862 0 : *_retval = nullptr;
863 :
864 0 : RootedValue rval(cx);
865 0 : SandboxOptions options;
866 0 : nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
867 0 : MOZ_ASSERT(NS_FAILED(rv) || !rval.isPrimitive(),
868 : "Bad return value from xpc_CreateSandboxObject()!");
869 :
870 0 : if (NS_SUCCEEDED(rv) && !rval.isPrimitive()) {
871 0 : *_retval = rval.toObjectOrNull();
872 : }
873 :
874 0 : return rv;
875 : }
876 :
877 : NS_IMETHODIMP
878 0 : nsXPConnect::EvalInSandboxObject(const nsAString& source, const char* filename,
879 : JSContext* cx, JSObject* sandboxArg,
880 : MutableHandleValue rval)
881 : {
882 0 : if (!sandboxArg)
883 0 : return NS_ERROR_INVALID_ARG;
884 :
885 0 : RootedObject sandbox(cx, sandboxArg);
886 0 : nsCString filenameStr;
887 0 : if (filename) {
888 0 : filenameStr.Assign(filename);
889 : } else {
890 0 : filenameStr = NS_LITERAL_CSTRING("x-bogus://XPConnect/Sandbox");
891 : }
892 0 : return EvalInSandbox(cx, sandbox, source, filenameStr, 1,
893 0 : JSVERSION_DEFAULT, rval);
894 : }
895 :
896 : NS_IMETHODIMP
897 0 : nsXPConnect::GetWrappedNativePrototype(JSContext* aJSContext,
898 : JSObject* aScopeArg,
899 : nsIClassInfo* aClassInfo,
900 : JSObject** aRetVal)
901 : {
902 0 : RootedObject aScope(aJSContext, aScopeArg);
903 0 : JSAutoCompartment ac(aJSContext, aScope);
904 :
905 0 : XPCWrappedNativeScope* scope = ObjectScope(aScope);
906 0 : if (!scope)
907 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
908 :
909 : nsCOMPtr<nsIXPCScriptable> scrProto =
910 0 : XPCWrappedNative::GatherProtoScriptable(aClassInfo);
911 :
912 0 : AutoMarkingWrappedNativeProtoPtr proto(aJSContext);
913 0 : proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, scrProto);
914 0 : if (!proto)
915 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
916 :
917 0 : JSObject* protoObj = proto->GetJSProtoObject();
918 0 : if (!protoObj)
919 0 : return UnexpectedFailure(NS_ERROR_FAILURE);
920 :
921 0 : *aRetVal = protoObj;
922 :
923 0 : return NS_OK;
924 : }
925 :
926 : NS_IMETHODIMP
927 0 : nsXPConnect::DebugDump(int16_t depth)
928 : {
929 : #ifdef DEBUG
930 0 : depth-- ;
931 0 : XPC_LOG_ALWAYS(("nsXPConnect @ %p with mRefCnt = %" PRIuPTR, this, mRefCnt.get()));
932 0 : XPC_LOG_INDENT();
933 0 : XPC_LOG_ALWAYS(("gSelf @ %p", gSelf));
934 0 : XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead));
935 0 : XPCWrappedNativeScope::DebugDumpAllScopes(depth);
936 0 : XPC_LOG_OUTDENT();
937 : #endif
938 0 : return NS_OK;
939 : }
940 :
941 : NS_IMETHODIMP
942 0 : nsXPConnect::DebugDumpObject(nsISupports* p, int16_t depth)
943 : {
944 : #ifdef DEBUG
945 0 : if (!depth)
946 0 : return NS_OK;
947 0 : if (!p) {
948 0 : XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address"));
949 0 : return NS_OK;
950 : }
951 :
952 0 : nsCOMPtr<nsIXPConnect> xpc;
953 0 : nsCOMPtr<nsIXPCWrappedJSClass> wjsc;
954 0 : nsCOMPtr<nsIXPConnectWrappedNative> wn;
955 0 : nsCOMPtr<nsIXPConnectWrappedJS> wjs;
956 :
957 0 : if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnect),
958 : getter_AddRefs(xpc)))) {
959 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPConnect..."));
960 0 : xpc->DebugDump(depth);
961 0 : } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPCWrappedJSClass),
962 : getter_AddRefs(wjsc)))) {
963 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPCWrappedJSClass..."));
964 0 : wjsc->DebugDump(depth);
965 0 : } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedNative),
966 : getter_AddRefs(wn)))) {
967 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative..."));
968 0 : wn->DebugDump(depth);
969 0 : } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedJS),
970 : getter_AddRefs(wjs)))) {
971 0 : XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS..."));
972 0 : wjs->DebugDump(depth);
973 : } else {
974 0 : XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %p", p));
975 : }
976 : #endif
977 0 : return NS_OK;
978 : }
979 :
980 : NS_IMETHODIMP
981 0 : nsXPConnect::DebugDumpJSStack(bool showArgs,
982 : bool showLocals,
983 : bool showThisProps)
984 : {
985 0 : xpc_DumpJSStack(showArgs, showLocals, showThisProps);
986 :
987 0 : return NS_OK;
988 : }
989 :
990 : char*
991 0 : nsXPConnect::DebugPrintJSStack(bool showArgs,
992 : bool showLocals,
993 : bool showThisProps)
994 : {
995 0 : JSContext* cx = nsContentUtils::GetCurrentJSContext();
996 0 : if (!cx)
997 0 : printf("there is no JSContext on the nsIThreadJSContextStack!\n");
998 : else
999 0 : return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps).release();
1000 :
1001 0 : return nullptr;
1002 : }
1003 :
1004 : NS_IMETHODIMP
1005 0 : nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg, nsIVariant* value,
1006 : MutableHandleValue _retval)
1007 : {
1008 0 : NS_PRECONDITION(ctx, "bad param");
1009 0 : NS_PRECONDITION(scopeArg, "bad param");
1010 0 : NS_PRECONDITION(value, "bad param");
1011 :
1012 0 : RootedObject scope(ctx, scopeArg);
1013 0 : MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx));
1014 :
1015 0 : nsresult rv = NS_OK;
1016 0 : if (!XPCVariant::VariantDataToJS(value, &rv, _retval)) {
1017 0 : if (NS_FAILED(rv))
1018 0 : return rv;
1019 :
1020 0 : return NS_ERROR_FAILURE;
1021 : }
1022 0 : return NS_OK;
1023 : }
1024 :
1025 : NS_IMETHODIMP
1026 0 : nsXPConnect::JSToVariant(JSContext* ctx, HandleValue value, nsIVariant** _retval)
1027 : {
1028 0 : NS_PRECONDITION(ctx, "bad param");
1029 0 : NS_PRECONDITION(_retval, "bad param");
1030 :
1031 0 : RefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value);
1032 0 : variant.forget(_retval);
1033 0 : if (!(*_retval))
1034 0 : return NS_ERROR_FAILURE;
1035 :
1036 0 : return NS_OK;
1037 : }
1038 :
1039 : nsIPrincipal*
1040 0 : nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const
1041 : {
1042 0 : MOZ_ASSERT(IS_WN_REFLECTOR(obj), "What kind of wrapper is this?");
1043 :
1044 0 : XPCWrappedNative* xpcWrapper = XPCWrappedNative::Get(obj);
1045 0 : if (xpcWrapper) {
1046 0 : if (allowShortCircuit) {
1047 0 : nsIPrincipal* result = xpcWrapper->GetObjectPrincipal();
1048 0 : if (result) {
1049 0 : return result;
1050 : }
1051 : }
1052 :
1053 : // If not, check if it points to an nsIScriptObjectPrincipal
1054 : nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
1055 0 : do_QueryInterface(xpcWrapper->Native());
1056 0 : if (objPrin) {
1057 0 : nsIPrincipal* result = objPrin->GetPrincipal();
1058 0 : if (result) {
1059 0 : return result;
1060 : }
1061 : }
1062 : }
1063 :
1064 0 : return nullptr;
1065 : }
1066 :
1067 : namespace xpc {
1068 :
1069 : bool
1070 0 : Base64Encode(JSContext* cx, HandleValue val, MutableHandleValue out)
1071 : {
1072 0 : MOZ_ASSERT(cx);
1073 :
1074 0 : nsAutoCString encodedString;
1075 0 : if (!ConvertJSValueToByteString(cx, val, false, encodedString)) {
1076 0 : return false;
1077 : }
1078 :
1079 0 : nsAutoCString result;
1080 0 : if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
1081 0 : JS_ReportErrorASCII(cx, "Failed to encode base64 data!");
1082 0 : return false;
1083 : }
1084 :
1085 0 : JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
1086 0 : if (!str)
1087 0 : return false;
1088 :
1089 0 : out.setString(str);
1090 0 : return true;
1091 : }
1092 :
1093 : bool
1094 0 : Base64Decode(JSContext* cx, HandleValue val, MutableHandleValue out)
1095 : {
1096 0 : MOZ_ASSERT(cx);
1097 :
1098 0 : nsAutoCString encodedString;
1099 0 : if (!ConvertJSValueToByteString(cx, val, false, encodedString)) {
1100 0 : return false;
1101 : }
1102 :
1103 0 : nsAutoCString result;
1104 0 : if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
1105 0 : JS_ReportErrorASCII(cx, "Failed to decode base64 string!");
1106 0 : return false;
1107 : }
1108 :
1109 0 : JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
1110 0 : if (!str)
1111 0 : return false;
1112 :
1113 0 : out.setString(str);
1114 0 : return true;
1115 : }
1116 :
1117 : void
1118 285 : SetLocationForGlobal(JSObject* global, const nsACString& location)
1119 : {
1120 285 : MOZ_ASSERT(global);
1121 285 : CompartmentPrivate::Get(global)->SetLocation(location);
1122 285 : }
1123 :
1124 : void
1125 7 : SetLocationForGlobal(JSObject* global, nsIURI* locationURI)
1126 : {
1127 7 : MOZ_ASSERT(global);
1128 7 : CompartmentPrivate::Get(global)->SetLocationURI(locationURI);
1129 7 : }
1130 :
1131 : } // namespace xpc
1132 :
1133 : NS_IMETHODIMP
1134 0 : nsXPConnect::NotifyDidPaint()
1135 : {
1136 0 : JS::NotifyDidPaint(XPCJSContext::Get()->Context());
1137 0 : return NS_OK;
1138 : }
1139 :
1140 : static nsresult
1141 0 : WriteScriptOrFunction(nsIObjectOutputStream* stream, JSContext* cx,
1142 : JSScript* scriptArg, HandleObject functionObj)
1143 : {
1144 : // Exactly one of script or functionObj must be given
1145 0 : MOZ_ASSERT(!scriptArg != !functionObj);
1146 :
1147 0 : RootedScript script(cx, scriptArg);
1148 0 : if (!script) {
1149 0 : RootedFunction fun(cx, JS_GetObjectFunction(functionObj));
1150 0 : script.set(JS_GetFunctionScript(cx, fun));
1151 : }
1152 :
1153 0 : uint8_t flags = 0; // We don't have flags anymore.
1154 0 : nsresult rv = stream->Write8(flags);
1155 0 : if (NS_FAILED(rv))
1156 0 : return rv;
1157 :
1158 :
1159 0 : TranscodeBuffer buffer;
1160 : TranscodeResult code;
1161 : {
1162 0 : if (functionObj)
1163 0 : code = EncodeInterpretedFunction(cx, buffer, functionObj);
1164 : else
1165 0 : code = EncodeScript(cx, buffer, script);
1166 : }
1167 :
1168 0 : if (code != TranscodeResult_Ok) {
1169 0 : if ((code & TranscodeResult_Failure) != 0)
1170 0 : return NS_ERROR_FAILURE;
1171 0 : MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
1172 0 : JS_ClearPendingException(cx);
1173 0 : return NS_ERROR_OUT_OF_MEMORY;
1174 : }
1175 :
1176 0 : size_t size = buffer.length();
1177 0 : if (size > UINT32_MAX)
1178 0 : return NS_ERROR_FAILURE;
1179 0 : rv = stream->Write32(size);
1180 0 : if (NS_SUCCEEDED(rv))
1181 0 : rv = stream->WriteBytes(reinterpret_cast<char*>(buffer.begin()), size);
1182 :
1183 0 : return rv;
1184 : }
1185 :
1186 : static nsresult
1187 1129 : ReadScriptOrFunction(nsIObjectInputStream* stream, JSContext* cx,
1188 : JSScript** scriptp, JSObject** functionObjp)
1189 : {
1190 : // Exactly one of script or functionObj must be given
1191 1129 : MOZ_ASSERT(!scriptp != !functionObjp);
1192 :
1193 : uint8_t flags;
1194 1129 : nsresult rv = stream->Read8(&flags);
1195 1129 : if (NS_FAILED(rv))
1196 0 : return rv;
1197 :
1198 : // We don't serialize mutedError-ness of scripts, which is fine as long as
1199 : // we only serialize system and XUL-y things. We can detect this by checking
1200 : // where the caller wants us to deserialize.
1201 1129 : MOZ_RELEASE_ASSERT(nsContentUtils::IsSystemCaller(cx) ||
1202 : CurrentGlobalOrNull(cx) == xpc::CompilationScope());
1203 :
1204 : uint32_t size;
1205 1129 : rv = stream->Read32(&size);
1206 1129 : if (NS_FAILED(rv))
1207 0 : return rv;
1208 :
1209 : char* data;
1210 1129 : rv = stream->ReadBytes(size, &data);
1211 1129 : if (NS_FAILED(rv))
1212 0 : return rv;
1213 :
1214 2258 : TranscodeBuffer buffer;
1215 1129 : buffer.replaceRawBuffer(reinterpret_cast<uint8_t*>(data), size);
1216 :
1217 : {
1218 : TranscodeResult code;
1219 1129 : if (scriptp) {
1220 76 : Rooted<JSScript*> script(cx);
1221 38 : code = DecodeScript(cx, buffer, &script);
1222 38 : if (code == TranscodeResult_Ok)
1223 38 : *scriptp = script.get();
1224 : } else {
1225 2182 : Rooted<JSFunction*> funobj(cx);
1226 1091 : code = DecodeInterpretedFunction(cx, buffer, &funobj);
1227 1091 : if (code == TranscodeResult_Ok)
1228 1091 : *functionObjp = JS_GetFunctionObject(funobj.get());
1229 : }
1230 :
1231 1129 : if (code != TranscodeResult_Ok) {
1232 0 : if ((code & TranscodeResult_Failure) != 0)
1233 0 : return NS_ERROR_FAILURE;
1234 0 : MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
1235 0 : JS_ClearPendingException(cx);
1236 0 : return NS_ERROR_OUT_OF_MEMORY;
1237 : }
1238 : }
1239 :
1240 1129 : return rv;
1241 : }
1242 :
1243 : NS_IMETHODIMP
1244 0 : nsXPConnect::WriteScript(nsIObjectOutputStream* stream, JSContext* cx, JSScript* script)
1245 : {
1246 0 : return WriteScriptOrFunction(stream, cx, script, nullptr);
1247 : }
1248 :
1249 : NS_IMETHODIMP
1250 38 : nsXPConnect::ReadScript(nsIObjectInputStream* stream, JSContext* cx, JSScript** scriptp)
1251 : {
1252 38 : return ReadScriptOrFunction(stream, cx, scriptp, nullptr);
1253 : }
1254 :
1255 : NS_IMETHODIMP
1256 0 : nsXPConnect::WriteFunction(nsIObjectOutputStream* stream, JSContext* cx, JSObject* functionObjArg)
1257 : {
1258 0 : RootedObject functionObj(cx, functionObjArg);
1259 0 : return WriteScriptOrFunction(stream, cx, nullptr, functionObj);
1260 : }
1261 :
1262 : NS_IMETHODIMP
1263 1091 : nsXPConnect::ReadFunction(nsIObjectInputStream* stream, JSContext* cx, JSObject** functionObjp)
1264 : {
1265 1091 : return ReadScriptOrFunction(stream, cx, nullptr, functionObjp);
1266 : }
1267 :
1268 : /* These are here to be callable from a debugger */
1269 : extern "C" {
1270 0 : JS_EXPORT_API(void) DumpJSStack()
1271 : {
1272 0 : xpc_DumpJSStack(true, true, false);
1273 0 : }
1274 :
1275 0 : JS_EXPORT_API(char*) PrintJSStack()
1276 : {
1277 : nsresult rv;
1278 0 : nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1279 0 : return (NS_SUCCEEDED(rv) && xpc) ?
1280 0 : xpc->DebugPrintJSStack(true, true, false) :
1281 0 : nullptr;
1282 : }
1283 :
1284 0 : JS_EXPORT_API(void) DumpCompleteHeap()
1285 : {
1286 : nsCOMPtr<nsICycleCollectorListener> listener =
1287 0 : do_CreateInstance("@mozilla.org/cycle-collector-logger;1");
1288 0 : if (!listener) {
1289 0 : NS_WARNING("Failed to create CC logger");
1290 0 : return;
1291 : }
1292 :
1293 0 : nsCOMPtr<nsICycleCollectorListener> alltracesListener;
1294 0 : listener->AllTraces(getter_AddRefs(alltracesListener));
1295 0 : if (!alltracesListener) {
1296 0 : NS_WARNING("Failed to get all traces logger");
1297 0 : return;
1298 : }
1299 :
1300 0 : nsJSContext::CycleCollectNow(alltracesListener);
1301 : }
1302 :
1303 : } // extern "C"
1304 :
1305 : namespace xpc {
1306 :
1307 : bool
1308 0 : Atob(JSContext* cx, unsigned argc, Value* vp)
1309 : {
1310 0 : CallArgs args = CallArgsFromVp(argc, vp);
1311 0 : if (!args.length())
1312 0 : return true;
1313 :
1314 0 : return xpc::Base64Decode(cx, args[0], args.rval());
1315 : }
1316 :
1317 : bool
1318 0 : Btoa(JSContext* cx, unsigned argc, Value* vp)
1319 : {
1320 0 : CallArgs args = CallArgsFromVp(argc, vp);
1321 0 : if (!args.length())
1322 0 : return true;
1323 :
1324 0 : return xpc::Base64Encode(cx, args[0], args.rval());
1325 : }
1326 :
1327 : bool
1328 0 : IsXrayWrapper(JSObject* obj)
1329 : {
1330 0 : return WrapperFactory::IsXrayWrapper(obj);
1331 : }
1332 :
1333 : JSAddonId*
1334 0 : NewAddonId(JSContext* cx, const nsACString& id)
1335 : {
1336 0 : JS::RootedString str(cx, JS_NewStringCopyN(cx, id.BeginReading(), id.Length()));
1337 0 : if (!str)
1338 0 : return nullptr;
1339 0 : return JS::NewAddonId(cx, str);
1340 : }
1341 :
1342 : bool
1343 0 : SetAddonInterposition(const nsACString& addonIdStr, nsIAddonInterposition* interposition)
1344 : {
1345 : JSAddonId* addonId;
1346 : // We enter the junk scope just to allocate a string, which actually will go
1347 : // in the system zone.
1348 0 : AutoJSAPI jsapi;
1349 0 : if (!jsapi.Init(xpc::PrivilegedJunkScope()))
1350 0 : return false;
1351 0 : addonId = NewAddonId(jsapi.cx(), addonIdStr);
1352 0 : if (!addonId)
1353 0 : return false;
1354 0 : return XPCWrappedNativeScope::SetAddonInterposition(jsapi.cx(), addonId, interposition);
1355 : }
1356 :
1357 : bool
1358 0 : AllowCPOWsInAddon(const nsACString& addonIdStr, bool allow)
1359 : {
1360 : JSAddonId* addonId;
1361 : // We enter the junk scope just to allocate a string, which actually will go
1362 : // in the system zone.
1363 0 : AutoJSAPI jsapi;
1364 0 : if (!jsapi.Init(xpc::PrivilegedJunkScope()))
1365 0 : return false;
1366 0 : addonId = NewAddonId(jsapi.cx(), addonIdStr);
1367 0 : if (!addonId)
1368 0 : return false;
1369 0 : return XPCWrappedNativeScope::AllowCPOWsInAddon(jsapi.cx(), addonId, allow);
1370 : }
1371 :
1372 : } // namespace xpc
1373 :
1374 : namespace mozilla {
1375 : namespace dom {
1376 :
1377 : bool
1378 642 : IsChromeOrXBL(JSContext* cx, JSObject* /* unused */)
1379 : {
1380 642 : MOZ_ASSERT(NS_IsMainThread());
1381 642 : JSCompartment* c = js::GetContextCompartment(cx);
1382 :
1383 : // For remote XUL, we run XBL in the XUL scope. Given that we care about
1384 : // compat and not security for remote XUL, we just always claim to be XBL.
1385 : //
1386 : // Note that, for performance, we don't check AllowXULXBLForPrincipal here,
1387 : // and instead rely on the fact that AllowContentXBLScope() only returns false in
1388 : // remote XUL situations.
1389 642 : return AccessCheck::isChrome(c) || IsContentXBLScope(c) || !AllowContentXBLScope(c);
1390 : }
1391 :
1392 : namespace workers {
1393 : extern bool IsCurrentThreadRunningChromeWorker();
1394 : } // namespace workers
1395 :
1396 : bool
1397 6 : ThreadSafeIsChromeOrXBL(JSContext* cx, JSObject* obj)
1398 : {
1399 6 : if (NS_IsMainThread()) {
1400 6 : return IsChromeOrXBL(cx, obj);
1401 : }
1402 0 : return workers::IsCurrentThreadRunningChromeWorker();
1403 : }
1404 :
1405 : } // namespace dom
1406 : } // namespace mozilla
1407 :
1408 : void
1409 0 : xpc::CreateCooperativeContext()
1410 : {
1411 0 : MOZ_ASSERT(gPrimaryContext);
1412 0 : XPCJSContext::NewXPCJSContext(gPrimaryContext);
1413 0 : }
1414 :
1415 : void
1416 0 : xpc::DestroyCooperativeContext()
1417 : {
1418 0 : MOZ_ASSERT(XPCJSContext::Get() != gPrimaryContext);
1419 0 : delete XPCJSContext::Get();
1420 0 : }
1421 :
1422 : void
1423 0 : xpc::YieldCooperativeContext()
1424 : {
1425 0 : JS_YieldCooperativeContext(XPCJSContext::Get()->Context());
1426 0 : }
1427 :
1428 : void
1429 0 : xpc::ResumeCooperativeContext()
1430 : {
1431 0 : JS_ResumeCooperativeContext(XPCJSContext::Get()->Context());
1432 9 : }
|