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/AutoEntryScript.h"
11 #include "js/ProfilingCategory.h"
12 #include "js/ProfilingStack.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Maybe.h"
16 #include "mozilla/Span.h"
18 #include "nsContentUtils.h"
19 #include "nsGlobalWindowInner.h"
20 #include "nsIDocShell.h"
21 #include "nsJSUtils.h"
22 #include "nsPIDOMWindow.h"
23 #include "nsPIDOMWindowInlines.h"
25 #include "xpcpublic.h"
27 namespace mozilla::dom
{
30 // Assert if it's not safe to run script. The helper class
31 // AutoAllowLegacyScriptExecution allows to allow-list
32 // legacy cases where it's actually not safe to run script.
34 void AssertIfNotSafeToRunScript() {
35 // if it's safe to run script, then there is nothing to do here.
36 if (nsContentUtils::IsSafeToRunScript()) {
40 // auto allowing legacy script execution is fine for now.
41 if (AutoAllowLegacyScriptExecution::IsAllowed()) {
45 MOZ_ASSERT(false, "is it safe to run script?");
49 static unsigned long gRunToCompletionListeners
= 0;
53 void UseEntryScriptProfiling() {
54 MOZ_ASSERT(NS_IsMainThread());
55 ++gRunToCompletionListeners
;
58 void UnuseEntryScriptProfiling() {
59 MOZ_ASSERT(NS_IsMainThread());
60 MOZ_ASSERT(gRunToCompletionListeners
> 0);
61 --gRunToCompletionListeners
;
64 AutoEntryScript::AutoEntryScript(nsIGlobalObject
* aGlobalObject
,
65 const char* aReason
, bool aIsMainThread
)
66 : AutoJSAPI(aGlobalObject
, aIsMainThread
, eEntryScript
),
67 mWebIDLCallerPrincipal(nullptr)
68 // This relies on us having a cx() because the AutoJSAPI constructor
71 mCallerOverride(cx()),
73 "", aReason
, JS::ProfilingCategoryPair::JS
,
74 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS
)),
75 mJSThreadExecution(aGlobalObject
, aIsMainThread
) {
76 MOZ_ASSERT(aGlobalObject
);
80 AssertIfNotSafeToRunScript();
82 if (gRunToCompletionListeners
> 0) {
83 mDocShellEntryMonitor
.emplace(cx(), aReason
);
85 mScriptActivity
.emplace(true);
89 AutoEntryScript::AutoEntryScript(JSObject
* aObject
, const char* aReason
,
91 : AutoEntryScript(xpc::NativeGlobal(aObject
), aReason
, aIsMainThread
) {
92 // xpc::NativeGlobal uses JS::GetNonCCWObjectGlobal, which asserts that
93 // aObject is not a CCW.
96 AutoEntryScript::~AutoEntryScript() = default;
98 AutoEntryScript::DocshellEntryMonitor::DocshellEntryMonitor(JSContext
* aCx
,
100 : JS::dbg::AutoEntryMonitor(aCx
), mReason(aReason
) {}
102 void AutoEntryScript::DocshellEntryMonitor::Entry(
103 JSContext
* aCx
, JSFunction
* aFunction
, JSScript
* aScript
,
104 JS::Handle
<JS::Value
> aAsyncStack
, const char* aAsyncCause
) {
105 JS::Rooted
<JSFunction
*> rootedFunction(aCx
);
107 rootedFunction
= aFunction
;
109 JS::Rooted
<JSScript
*> rootedScript(aCx
);
111 rootedScript
= aScript
;
114 nsCOMPtr
<nsPIDOMWindowInner
> window
= xpc::CurrentWindowOrNull(aCx
);
115 if (!window
|| !window
->GetDocShell() ||
116 !window
->GetDocShell()->GetRecordProfileTimelineMarkers()) {
120 nsCOMPtr
<nsIDocShell
> docShellForJSRunToCompletion
= window
->GetDocShell();
122 nsAutoJSString functionName
;
123 if (rootedFunction
) {
124 JS::Rooted
<JSString
*> displayId(aCx
,
125 JS_GetFunctionDisplayId(rootedFunction
));
127 if (!functionName
.init(aCx
, displayId
)) {
128 JS_ClearPendingException(aCx
);
135 uint32_t lineNumber
= 0;
137 rootedScript
= JS_GetFunctionScript(aCx
, rootedFunction
);
140 CopyUTF8toUTF16(MakeStringSpan(JS_GetScriptFilename(rootedScript
)),
142 lineNumber
= JS_GetScriptBaseLineNumber(aCx
, rootedScript
);
145 if (!filename
.IsEmpty() || !functionName
.IsEmpty()) {
146 docShellForJSRunToCompletion
->NotifyJSRunToCompletionStart(
147 mReason
, functionName
, filename
, lineNumber
, aAsyncStack
, aAsyncCause
);
151 void AutoEntryScript::DocshellEntryMonitor::Exit(JSContext
* aCx
) {
152 nsCOMPtr
<nsPIDOMWindowInner
> window
= xpc::CurrentWindowOrNull(aCx
);
153 // Not really worth checking GetRecordProfileTimelineMarkers here.
154 if (window
&& window
->GetDocShell()) {
155 nsCOMPtr
<nsIDocShell
> docShellForJSRunToCompletion
= window
->GetDocShell();
156 docShellForJSRunToCompletion
->NotifyJSRunToCompletionStop();
160 } // namespace mozilla::dom