1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 #include "mozilla/dom/ScriptSettings.h"
10 #include "MainThreadUtils.h"
11 #include "js/CharacterEncoding.h"
12 #include "js/CompilationAndEvaluation.h"
13 #include "js/Conversions.h"
14 #include "js/ErrorReport.h"
15 #include "js/Exception.h"
17 #include "js/PropertyAndElement.h" // JS_GetProperty
18 #include "js/TypeDecls.h"
20 #include "js/Warnings.h"
21 #include "js/Wrapper.h"
22 #include "js/friend/ErrorMessages.h"
23 #include "js/loader/LoadedScript.h"
24 #include "js/loader/ScriptLoadRequest.h"
26 #include "mozilla/Assertions.h"
27 #include "mozilla/BasePrincipal.h"
28 #include "mozilla/CycleCollectedJSContext.h"
29 #include "mozilla/DebugOnly.h"
30 #include "mozilla/Maybe.h"
31 #include "mozilla/RefPtr.h"
32 #include "mozilla/ThreadLocal.h"
33 #include "mozilla/dom/AutoEntryScript.h"
34 #include "mozilla/dom/BindingUtils.h"
35 #include "mozilla/dom/Document.h"
36 #include "mozilla/dom/Element.h"
37 #include "mozilla/dom/WorkerCommon.h"
38 #include "nsContentUtils.h"
40 #include "nsGlobalWindowInner.h"
41 #include "nsIGlobalObject.h"
43 #include "nsIPrincipal.h"
44 #include "nsISupports.h"
45 #include "nsJSUtils.h"
46 #include "nsPIDOMWindow.h"
49 #include "xpcpublic.h"
54 static MOZ_THREAD_LOCAL(ScriptSettingsStackEntry
*) sScriptSettingsTLS
;
56 class ScriptSettingsStack
{
58 static ScriptSettingsStackEntry
* Top() { return sScriptSettingsTLS
.get(); }
60 static void Push(ScriptSettingsStackEntry
* aEntry
) {
61 MOZ_ASSERT(!aEntry
->mOlder
);
62 // Whenever JSAPI use is disabled, the next stack entry pushed must
63 // not be an AutoIncumbentScript.
64 MOZ_ASSERT_IF(!Top() || Top()->NoJSAPI(), !aEntry
->IsIncumbentScript());
65 // Whenever the top entry is not an incumbent canidate, the next stack entry
66 // pushed must not be an AutoIncumbentScript.
67 MOZ_ASSERT_IF(Top() && !Top()->IsIncumbentCandidate(),
68 !aEntry
->IsIncumbentScript());
70 aEntry
->mOlder
= Top();
71 sScriptSettingsTLS
.set(aEntry
);
74 static void Pop(ScriptSettingsStackEntry
* aEntry
) {
75 MOZ_ASSERT(aEntry
== Top());
76 sScriptSettingsTLS
.set(aEntry
->mOlder
);
79 static nsIGlobalObject
* IncumbentGlobal() {
80 ScriptSettingsStackEntry
* entry
= Top();
82 if (entry
->IsIncumbentCandidate()) {
83 return entry
->mGlobalObject
;
85 entry
= entry
->mOlder
;
90 static ScriptSettingsStackEntry
* EntryPoint() {
91 ScriptSettingsStackEntry
* entry
= Top();
93 if (entry
->IsEntryCandidate()) {
96 entry
= entry
->mOlder
;
101 static nsIGlobalObject
* EntryGlobal() {
102 ScriptSettingsStackEntry
* entry
= EntryPoint();
106 return entry
->mGlobalObject
;
110 static ScriptSettingsStackEntry
* TopNonIncumbentScript() {
111 ScriptSettingsStackEntry
* entry
= Top();
113 if (!entry
->IsIncumbentScript()) {
116 entry
= entry
->mOlder
;
123 void InitScriptSettings() {
124 bool success
= sScriptSettingsTLS
.init();
129 sScriptSettingsTLS
.set(nullptr);
132 void DestroyScriptSettings() {
133 MOZ_ASSERT(sScriptSettingsTLS
.get() == nullptr);
136 ScriptSettingsStackEntry::ScriptSettingsStackEntry(nsIGlobalObject
* aGlobal
,
138 : mGlobalObject(aGlobal
), mType(aType
), mOlder(nullptr) {
139 MOZ_ASSERT_IF(IsIncumbentCandidate() && !NoJSAPI(), mGlobalObject
);
140 MOZ_ASSERT(!mGlobalObject
|| mGlobalObject
->HasJSGlobal(),
141 "Must have an actual JS global for the duration on the stack");
144 JS_IsGlobalObject(mGlobalObject
->GetGlobalJSObjectPreserveColor()),
145 "No outer windows allowed");
148 ScriptSettingsStackEntry::~ScriptSettingsStackEntry() {
149 // We must have an actual JS global for the entire time this is on the stack.
150 MOZ_ASSERT_IF(mGlobalObject
, mGlobalObject
->HasJSGlobal());
153 // If the entry or incumbent global ends up being something that the subject
154 // principal doesn't subsume, we don't want to use it. This never happens on
155 // the web, but can happen with asymmetric privilege relationships (i.e.
156 // ExpandedPrincipal and System Principal).
158 // The most correct thing to use instead would be the topmost global on the
159 // callstack whose principal is subsumed by the subject principal. But that's
160 // hard to compute, so we just substitute the global of the current
161 // compartment. In practice, this is fine.
163 // Note that in particular things like:
165 // |SpecialPowers.wrap(crossOriginWindow).eval(open())|
167 // trigger this case. Although both the entry global and the current global
168 // have normal principals, the use of Gecko-specific System-Principaled JS
169 // puts the code from two different origins on the callstack at once, which
170 // doesn't happen normally on the web.
171 static nsIGlobalObject
* ClampToSubject(nsIGlobalObject
* aGlobalOrNull
) {
172 if (!aGlobalOrNull
|| !NS_IsMainThread()) {
173 return aGlobalOrNull
;
176 nsIPrincipal
* globalPrin
= aGlobalOrNull
->PrincipalOrNull();
177 NS_ENSURE_TRUE(globalPrin
, GetCurrentGlobal());
178 if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()
179 ->SubsumesConsideringDomain(globalPrin
)) {
180 return GetCurrentGlobal();
183 return aGlobalOrNull
;
186 nsIGlobalObject
* GetEntryGlobal() {
187 return ClampToSubject(ScriptSettingsStack::EntryGlobal());
190 Document
* GetEntryDocument() {
191 nsIGlobalObject
* global
= GetEntryGlobal();
192 nsCOMPtr
<nsPIDOMWindowInner
> entryWin
= do_QueryInterface(global
);
194 return entryWin
? entryWin
->GetExtantDoc() : nullptr;
197 nsIGlobalObject
* GetIncumbentGlobal() {
198 // We need the current JSContext in order to check the JS for
199 // scripted frames that may have appeared since anyone last
200 // manipulated the stack. If it's null, that means that there
201 // must be no entry global on the stack, and therefore no incumbent
203 JSContext
* cx
= nsContentUtils::GetCurrentJSContext();
205 MOZ_ASSERT(ScriptSettingsStack::EntryGlobal() == nullptr);
209 // See what the JS engine has to say. If we've got a scripted caller
210 // override in place, the JS engine will lie to us and pretend that
211 // there's nothing on the JS stack, which will cause us to check the
212 // incumbent script stack below.
213 if (JSObject
* global
= JS::GetScriptedCallerGlobal(cx
)) {
214 return ClampToSubject(xpc::NativeGlobal(global
));
217 // Ok, nothing from the JS engine. Let's use whatever's on the
219 return ClampToSubject(ScriptSettingsStack::IncumbentGlobal());
222 nsIGlobalObject
* GetCurrentGlobal() {
223 JSContext
* cx
= nsContentUtils::GetCurrentJSContext();
228 JSObject
* global
= JS::CurrentGlobalOrNull(cx
);
233 return xpc::NativeGlobal(global
);
236 nsIPrincipal
* GetWebIDLCallerPrincipal() {
237 MOZ_ASSERT(NS_IsMainThread());
238 ScriptSettingsStackEntry
* entry
= ScriptSettingsStack::EntryPoint();
240 // If we have an entry point that is not NoJSAPI, we know it must be an
242 if (!entry
|| entry
->NoJSAPI()) {
245 AutoEntryScript
* aes
= static_cast<AutoEntryScript
*>(entry
);
247 return aes
->mWebIDLCallerPrincipal
;
250 bool IsJSAPIActive() {
251 ScriptSettingsStackEntry
* topEntry
= ScriptSettingsStack::Top();
252 return topEntry
&& !topEntry
->NoJSAPI();
256 JSContext
* GetJSContext() { return CycleCollectedJSContext::Get()->Context(); }
257 } // namespace danger
259 JS::RootingContext
* RootingCx() {
260 return CycleCollectedJSContext::Get()->RootingCx();
263 AutoJSAPI::AutoJSAPI()
264 : ScriptSettingsStackEntry(nullptr, eJSAPI
),
266 mIsMainThread(false) // For lack of anything better
269 AutoJSAPI::~AutoJSAPI() {
271 // No need to do anything here: we never managed to Init, so can't have an
272 // exception on our (nonexistent) JSContext. We also don't need to restore
273 // any state on it. Finally, we never made it to pushing ourselves onto the
274 // ScriptSettingsStack, so shouldn't pop.
275 MOZ_ASSERT(ScriptSettingsStack::Top() != this);
281 if (mOldWarningReporter
.isSome()) {
282 JS::SetWarningReporter(cx(), mOldWarningReporter
.value());
285 ScriptSettingsStack::Pop(this);
288 void WarningOnlyErrorReporter(JSContext
* aCx
, JSErrorReport
* aRep
);
290 void AutoJSAPI::InitInternal(nsIGlobalObject
* aGlobalObject
, JSObject
* aGlobal
,
291 JSContext
* aCx
, bool aIsMainThread
) {
293 MOZ_ASSERT(aCx
== danger::GetJSContext());
294 MOZ_ASSERT(aIsMainThread
== NS_IsMainThread());
295 MOZ_ASSERT(bool(aGlobalObject
) == bool(aGlobal
));
296 MOZ_ASSERT_IF(aGlobalObject
,
297 aGlobalObject
->GetGlobalJSObjectPreserveColor() == aGlobal
);
299 bool haveException
= JS_IsExceptionPending(aCx
);
303 mIsMainThread
= aIsMainThread
;
305 JS::AssertObjectIsNotGray(aGlobal
);
307 mAutoNullableRealm
.emplace(mCx
, aGlobal
);
308 mGlobalObject
= aGlobalObject
;
310 ScriptSettingsStack::Push(this);
312 mOldWarningReporter
.emplace(JS::GetWarningReporter(aCx
));
314 JS::SetWarningReporter(aCx
, WarningOnlyErrorReporter
);
318 JS::Rooted
<JS::Value
> exn(aCx
);
319 JS_GetPendingException(aCx
, &exn
);
321 JS_ClearPendingException(aCx
);
322 if (exn
.isObject()) {
323 JS::Rooted
<JSObject
*> exnObj(aCx
, &exn
.toObject());
325 // Make sure we can actually read things from it. This UncheckedUwrap is
326 // safe because we're only getting data for a debug printf. In
327 // particular, we do not expose this data to anyone, which is very
328 // important; otherwise it could be a cross-origin information leak.
329 exnObj
= js::UncheckedUnwrap(exnObj
);
330 JSAutoRealm
ar(aCx
, exnObj
);
332 nsAutoJSString stack
, filename
, name
, message
;
335 JS::Rooted
<JS::Value
> tmp(aCx
);
336 if (!JS_GetProperty(aCx
, exnObj
, "filename", &tmp
)) {
337 JS_ClearPendingException(aCx
);
339 if (tmp
.isUndefined()) {
340 if (!JS_GetProperty(aCx
, exnObj
, "fileName", &tmp
)) {
341 JS_ClearPendingException(aCx
);
345 if (!filename
.init(aCx
, tmp
)) {
346 JS_ClearPendingException(aCx
);
349 if (!JS_GetProperty(aCx
, exnObj
, "stack", &tmp
) ||
350 !stack
.init(aCx
, tmp
)) {
351 JS_ClearPendingException(aCx
);
354 if (!JS_GetProperty(aCx
, exnObj
, "name", &tmp
) || !name
.init(aCx
, tmp
)) {
355 JS_ClearPendingException(aCx
);
358 if (!JS_GetProperty(aCx
, exnObj
, "message", &tmp
) ||
359 !message
.init(aCx
, tmp
)) {
360 JS_ClearPendingException(aCx
);
363 if (!JS_GetProperty(aCx
, exnObj
, "lineNumber", &tmp
) ||
364 !JS::ToInt32(aCx
, tmp
, &line
)) {
365 JS_ClearPendingException(aCx
);
369 printf_stderr("PREEXISTING EXCEPTION OBJECT: '%s: %s'\n%s:%d\n%s\n",
370 NS_ConvertUTF16toUTF8(name
).get(),
371 NS_ConvertUTF16toUTF8(message
).get(),
372 NS_ConvertUTF16toUTF8(filename
).get(), line
,
373 NS_ConvertUTF16toUTF8(stack
).get());
375 // It's a primitive... not much we can do other than stringify it.
376 nsAutoJSString exnStr
;
377 if (!exnStr
.init(aCx
, exn
)) {
378 JS_ClearPendingException(aCx
);
381 printf_stderr("PREEXISTING EXCEPTION PRIMITIVE: %s\n",
382 NS_ConvertUTF16toUTF8(exnStr
).get());
384 MOZ_ASSERT(false, "We had an exception; we should not have");
389 AutoJSAPI::AutoJSAPI(nsIGlobalObject
* aGlobalObject
, bool aIsMainThread
,
391 : ScriptSettingsStackEntry(aGlobalObject
, aType
),
392 mIsMainThread(aIsMainThread
) {
393 MOZ_ASSERT(aGlobalObject
);
394 MOZ_ASSERT(aGlobalObject
->HasJSGlobal(), "Must have a JS global");
395 MOZ_ASSERT(aIsMainThread
== NS_IsMainThread());
397 InitInternal(aGlobalObject
, aGlobalObject
->GetGlobalJSObject(),
398 danger::GetJSContext(), aIsMainThread
);
401 void AutoJSAPI::Init() {
402 MOZ_ASSERT(!mCx
, "An AutoJSAPI should only be initialised once");
404 InitInternal(/* aGlobalObject */ nullptr, /* aGlobal */ nullptr,
405 danger::GetJSContext(), NS_IsMainThread());
408 bool AutoJSAPI::Init(nsIGlobalObject
* aGlobalObject
, JSContext
* aCx
) {
409 MOZ_ASSERT(!mCx
, "An AutoJSAPI should only be initialised once");
412 if (NS_WARN_IF(!aGlobalObject
)) {
416 JSObject
* global
= aGlobalObject
->GetGlobalJSObject();
417 if (NS_WARN_IF(!global
)) {
421 InitInternal(aGlobalObject
, global
, aCx
, NS_IsMainThread());
425 bool AutoJSAPI::Init(nsIGlobalObject
* aGlobalObject
) {
426 return Init(aGlobalObject
, danger::GetJSContext());
429 bool AutoJSAPI::Init(JSObject
* aObject
) {
430 MOZ_ASSERT(!js::IsCrossCompartmentWrapper(aObject
));
431 return Init(xpc::NativeGlobal(aObject
));
434 bool AutoJSAPI::Init(nsPIDOMWindowInner
* aWindow
, JSContext
* aCx
) {
435 return Init(nsGlobalWindowInner::Cast(aWindow
), aCx
);
438 bool AutoJSAPI::Init(nsPIDOMWindowInner
* aWindow
) {
439 return Init(nsGlobalWindowInner::Cast(aWindow
));
442 bool AutoJSAPI::Init(nsGlobalWindowInner
* aWindow
, JSContext
* aCx
) {
443 return Init(static_cast<nsIGlobalObject
*>(aWindow
), aCx
);
446 bool AutoJSAPI::Init(nsGlobalWindowInner
* aWindow
) {
447 return Init(static_cast<nsIGlobalObject
*>(aWindow
));
450 // Even with autoJSAPIOwnsErrorReporting, the JS engine still sends warning
451 // reports to the JSErrorReporter as soon as they are generated. These go
452 // directly to the console, so we can handle them easily here.
454 // Eventually, SpiderMonkey will have a special-purpose callback for warnings
456 void WarningOnlyErrorReporter(JSContext
* aCx
, JSErrorReport
* aRep
) {
457 MOZ_ASSERT(aRep
->isWarning());
458 if (!NS_IsMainThread()) {
459 // Reporting a warning on workers is a bit complicated because we have to
460 // climb our parent chain until we get to the main thread. So go ahead and
461 // just go through the worker or worklet ReportError codepath here.
463 // That said, it feels like we should be able to short-circuit things a bit
464 // here by posting an appropriate runnable to the main thread directly...
465 // Worth looking into sometime.
466 CycleCollectedJSContext
* ccjscx
= CycleCollectedJSContext::GetFor(aCx
);
469 ccjscx
->ReportError(aRep
, JS::ConstUTF8CharsZ());
473 RefPtr
<xpc::ErrorReport
> xpcReport
= new xpc::ErrorReport();
474 nsGlobalWindowInner
* win
= xpc::CurrentWindowOrNull(aCx
);
475 xpcReport
->Init(aRep
, nullptr, nsContentUtils::IsSystemCaller(aCx
),
476 win
? win
->WindowID() : 0);
477 xpcReport
->LogToConsole();
480 void AutoJSAPI::ReportException() {
481 if (!HasException()) {
485 // AutoJSAPI uses a JSAutoNullableRealm, and may be in a null realm
486 // when the destructor is called. However, the JS engine requires us
487 // to be in a realm when we fetch the pending exception. In this case,
488 // we enter the privileged junk scope and don't dispatch any error events.
489 JS::Rooted
<JSObject
*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
492 errorGlobal
= xpc::PrivilegedJunkScope();
494 errorGlobal
= GetCurrentThreadWorkerGlobal();
496 // We might be reporting an error in debugger code that ran before the
497 // worker's global was created. Use the debugger global instead.
498 errorGlobal
= GetCurrentThreadWorkerDebuggerGlobal();
499 if (NS_WARN_IF(!errorGlobal
)) {
500 // An exception may have been thrown on attempt to create a global
501 // and now there is no realm from which to fetch the exception.
509 MOZ_ASSERT(JS_IsGlobalObject(errorGlobal
));
510 JSAutoRealm
ar(cx(), errorGlobal
);
511 JS::ExceptionStack
exnStack(cx());
512 JS::ErrorReportBuilder
jsReport(cx());
513 if (StealExceptionAndStack(&exnStack
) &&
514 jsReport
.init(cx(), exnStack
, JS::ErrorReportBuilder::WithSideEffects
)) {
516 RefPtr
<xpc::ErrorReport
> xpcReport
= new xpc::ErrorReport();
518 RefPtr
<nsGlobalWindowInner
> inner
= xpc::WindowOrNull(errorGlobal
);
520 // For WebExtension content script, `WindowOrNull` method will return
521 // null, whereas we would still like to flag the exception with the
522 // related WindowGlobal the content script executed against. So we only
523 // update the `innerWindowID` and not `inner` as we don't want to dispatch
524 // exceptions caused by the content script to the webpage.
525 uint64_t innerWindowID
= 0;
527 innerWindowID
= inner
->WindowID();
528 } else if (nsGlobalWindowInner
* win
= xpc::SandboxWindowOrNull(
529 JS::GetNonCCWObjectGlobal(errorGlobal
), cx())) {
530 innerWindowID
= win
->WindowID();
534 nsContentUtils::ObjectPrincipal(errorGlobal
)->IsSystemPrincipal();
535 xpcReport
->Init(jsReport
.report(), jsReport
.toStringResult().c_str(),
536 isChrome
, innerWindowID
);
537 if (inner
&& jsReport
.report()->errorNumber
!= JSMSG_OUT_OF_MEMORY
) {
538 JS::RootingContext
* rcx
= JS::RootingContext::get(cx());
539 DispatchScriptErrorEvent(inner
, rcx
, xpcReport
, exnStack
.exception(),
542 JS::Rooted
<JSObject
*> stack(cx());
543 JS::Rooted
<JSObject
*> stackGlobal(cx());
544 xpc::FindExceptionStackForConsoleReport(inner
, exnStack
.exception(),
545 exnStack
.stack(), &stack
,
547 // This error is not associated with a specific window,
548 // so omit the exception value to mitigate potential leaks.
549 xpcReport
->LogToConsoleWithStack(inner
, JS::NothingHandleValue
, stack
,
553 // On a worker or worklet, we just use the error reporting mechanism and
554 // don't bother with xpc::ErrorReport. This will ensure that all the
555 // right worker events (which are a lot more complicated than in the
556 // window case) get fired.
557 CycleCollectedJSContext
* ccjscx
= CycleCollectedJSContext::GetFor(cx());
559 // Before invoking ReportError, put the exception back on the context,
560 // because it may want to put it in its error events and has no other way
561 // to get hold of it. After we invoke ReportError, clear the exception on
562 // cx(), just in case ReportError didn't.
563 JS::SetPendingExceptionStack(cx(), exnStack
);
564 ccjscx
->ReportError(jsReport
.report(), jsReport
.toStringResult());
568 NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
573 bool AutoJSAPI::PeekException(JS::MutableHandle
<JS::Value
> aVal
) {
574 MOZ_ASSERT_IF(mIsMainThread
, IsStackTop());
575 MOZ_ASSERT(HasException());
576 MOZ_ASSERT(js::GetContextRealm(cx()));
577 return JS_GetPendingException(cx(), aVal
);
580 bool AutoJSAPI::StealException(JS::MutableHandle
<JS::Value
> aVal
) {
581 JS::ExceptionStack
exnStack(cx());
582 if (!StealExceptionAndStack(&exnStack
)) {
585 aVal
.set(exnStack
.exception());
589 bool AutoJSAPI::StealExceptionAndStack(JS::ExceptionStack
* aExnStack
) {
590 MOZ_ASSERT_IF(mIsMainThread
, IsStackTop());
591 MOZ_ASSERT(HasException());
592 MOZ_ASSERT(js::GetContextRealm(cx()));
594 return JS::StealPendingExceptionStack(cx(), aExnStack
);
598 bool AutoJSAPI::IsStackTop() const {
599 return ScriptSettingsStack::TopNonIncumbentScript() == this;
603 AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject
* aGlobalObject
)
604 : ScriptSettingsStackEntry(aGlobalObject
, eIncumbentScript
),
605 mCallerOverride(nsContentUtils::GetCurrentJSContext()) {
606 ScriptSettingsStack::Push(this);
609 AutoIncumbentScript::~AutoIncumbentScript() { ScriptSettingsStack::Pop(this); }
611 AutoNoJSAPI::AutoNoJSAPI(JSContext
* aCx
)
612 : ScriptSettingsStackEntry(nullptr, eNoJSAPI
),
613 JSAutoNullableRealm(aCx
, nullptr),
615 // Make sure we don't seem to have an incumbent global due to
616 // whatever script is running right now.
617 JS::HideScriptedCaller(aCx
);
619 // Make sure the fallback GetIncumbentGlobal() behavior and
620 // GetEntryGlobal() both return null.
621 ScriptSettingsStack::Push(this);
624 AutoNoJSAPI::~AutoNoJSAPI() {
625 ScriptSettingsStack::Pop(this);
626 JS::UnhideScriptedCaller(mCx
);
631 AutoJSContext::AutoJSContext() : mCx(nullptr) {
632 JS::AutoSuppressGCAnalysis nogc
;
633 MOZ_ASSERT(!mCx
, "mCx should not be initialized!");
634 MOZ_ASSERT(NS_IsMainThread());
636 if (dom::IsJSAPIActive()) {
637 mCx
= dom::danger::GetJSContext();
644 AutoJSContext::operator JSContext
*() const { return mCx
; }
646 AutoSafeJSContext::AutoSafeJSContext() {
647 MOZ_ASSERT(NS_IsMainThread());
649 DebugOnly
<bool> ok
= Init(xpc::UnprivilegedJunkScope());
651 "This is quite odd. We should have crashed in the "
652 "xpc::NativeGlobal() call if xpc::UnprivilegedJunkScope() "
653 "returned null, and inited correctly otherwise!");
656 AutoSlowOperation::AutoSlowOperation() : mIsMainThread(NS_IsMainThread()) {
658 mScriptActivity
.emplace(true);
662 void AutoSlowOperation::CheckForInterrupt() {
663 // For now we support only main thread!
665 // JS_CheckForInterrupt expects us to be in a realm, so we use a junk scope.
666 // In principle, it doesn't matter which one we use, since we aren't really
667 // running scripts here, and none of our interrupt callbacks can stop
668 // scripts in a junk scope anyway. In practice, though, the privileged junk
669 // scope is the same as the JSM global, and therefore always exists, while
670 // the unprivileged junk scope is created lazily, and may not exist until we
671 // try to use it. So we use the former for the sake of efficiency.
672 dom::AutoJSAPI jsapi
;
673 MOZ_ALWAYS_TRUE(jsapi
.Init(xpc::PrivilegedJunkScope()));
674 JS_CheckForInterrupt(jsapi
.cx());
678 AutoAllowLegacyScriptExecution::AutoAllowLegacyScriptExecution() {
680 // no need to do that dance if we are off the main thread,
681 // because we only assert if we are on the main thread!
682 if (!NS_IsMainThread()) {
685 sAutoAllowLegacyScriptExecution
++;
689 AutoAllowLegacyScriptExecution::~AutoAllowLegacyScriptExecution() {
691 // no need to do that dance if we are off the main thread,
692 // because we only assert if we are on the main thread!
693 if (!NS_IsMainThread()) {
696 sAutoAllowLegacyScriptExecution
--;
697 MOZ_ASSERT(sAutoAllowLegacyScriptExecution
>= 0,
698 "how can the stack guard produce a value less than 0?");
702 int AutoAllowLegacyScriptExecution::sAutoAllowLegacyScriptExecution
= 0;
705 bool AutoAllowLegacyScriptExecution::IsAllowed() {
706 return sAutoAllowLegacyScriptExecution
> 0;
709 } // namespace mozilla