Bug 1843838 - Rename ScriptLoadRequest::IsReadyToRun to IsFinished since this returns...
[gecko.git] / dom / script / ScriptLoadContext.cpp
blobc0f9fea5bf66d218466384bb9905a61ca9f1105e
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 "GeckoProfiler.h"
9 #include "mozilla/dom/Document.h"
10 #include "mozilla/HoldDropJSObjects.h"
11 #include "mozilla/StaticPrefs_dom.h"
12 #include "mozilla/Unused.h"
13 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
15 #include "js/OffThreadScriptCompilation.h"
16 #include "js/SourceText.h"
17 #include "js/loader/LoadContextBase.h"
18 #include "js/loader/ModuleLoadRequest.h"
20 #include "ScriptLoadContext.h"
21 #include "ModuleLoadRequest.h"
22 #include "nsContentUtils.h"
23 #include "nsICacheInfoChannel.h"
24 #include "nsIClassOfService.h"
25 #include "nsISupportsPriority.h"
27 namespace mozilla::dom {
29 //////////////////////////////////////////////////////////////
30 // ScriptLoadContext
31 //////////////////////////////////////////////////////////////
33 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadContext)
34 NS_INTERFACE_MAP_END_INHERITING(JS::loader::LoadContextBase)
36 NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadContext)
38 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ScriptLoadContext,
39 JS::loader::LoadContextBase)
40 MOZ_ASSERT(!tmp->mOffThreadToken);
41 MOZ_ASSERT(!tmp->mRunnable);
42 tmp->MaybeUnblockOnload();
43 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
45 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ScriptLoadContext,
46 JS::loader::LoadContextBase)
47 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDocument)
48 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
50 NS_IMPL_ADDREF_INHERITED(ScriptLoadContext, JS::loader::LoadContextBase)
51 NS_IMPL_RELEASE_INHERITED(ScriptLoadContext, JS::loader::LoadContextBase)
53 ScriptLoadContext::ScriptLoadContext()
54 : JS::loader::LoadContextBase(JS::loader::ContextKind::Window),
55 mScriptMode(ScriptMode::eBlocking),
56 mScriptFromHead(false),
57 mIsInline(true),
58 mInDeferList(false),
59 mInAsyncList(false),
60 mIsNonAsyncScriptInserted(false),
61 mIsXSLT(false),
62 mInCompilingList(false),
63 mIsTracking(false),
64 mWasCompiledOMT(false),
65 mOffThreadToken(nullptr),
66 mRunnable(nullptr),
67 mLineNo(1),
68 mColumnNo(0),
69 mIsPreload(false),
70 mUnreportedPreloadError(NS_OK) {}
72 ScriptLoadContext::~ScriptLoadContext() {
73 MOZ_ASSERT(NS_IsMainThread());
75 // Off-thread parsing must have completed by this point.
76 MOZ_DIAGNOSTIC_ASSERT(!mOffThreadToken && !mRunnable);
78 mRequest = nullptr;
80 MaybeUnblockOnload();
83 void ScriptLoadContext::BlockOnload(Document* aDocument) {
84 MOZ_ASSERT(!mLoadBlockedDocument);
85 aDocument->BlockOnload();
86 mLoadBlockedDocument = aDocument;
89 void ScriptLoadContext::MaybeUnblockOnload() {
90 if (mLoadBlockedDocument) {
91 mLoadBlockedDocument->UnblockOnload(false);
92 mLoadBlockedDocument = nullptr;
96 void ScriptLoadContext::MaybeCancelOffThreadScript() {
97 MOZ_ASSERT(NS_IsMainThread());
99 if (!mOffThreadToken) {
100 return;
103 // Cancel parse if it hasn't been started yet or wait for it to finish and
104 // clean up finished parse data.
105 JSContext* cx = danger::GetJSContext();
106 JS::CancelOffThreadToken(cx, mOffThreadToken);
107 mOffThreadToken = nullptr;
109 // Clear the pointer to the runnable. It may still run later if we didn't
110 // cancel in time. In this case the runnable is held live by the reference
111 // passed to Dispatch, which is dropped after it runs.
112 mRunnable = nullptr;
114 MaybeUnblockOnload();
117 void ScriptLoadContext::SetScriptMode(bool aDeferAttr, bool aAsyncAttr,
118 bool aLinkPreload) {
119 if (aLinkPreload) {
120 mScriptMode = ScriptMode::eLinkPreload;
121 } else if (aAsyncAttr) {
122 mScriptMode = ScriptMode::eAsync;
123 } else if (aDeferAttr || mRequest->IsModuleRequest()) {
124 mScriptMode = ScriptMode::eDeferred;
125 } else {
126 mScriptMode = ScriptMode::eBlocking;
130 // static
131 void ScriptLoadContext::PrioritizeAsPreload(nsIChannel* aChannel) {
132 if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(aChannel)) {
133 cos->AddClassFlags(nsIClassOfService::Unblocked);
135 if (nsCOMPtr<nsISupportsPriority> sp = do_QueryInterface(aChannel)) {
136 sp->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
140 void ScriptLoadContext::PrioritizeAsPreload() {
141 if (!IsLinkPreloadScript()) {
142 // Do the prioritization only if this request has not already been created
143 // as a preload.
144 PrioritizeAsPreload(Channel());
148 bool ScriptLoadContext::IsPreload() const {
149 if (mRequest->IsModuleRequest() && !mRequest->IsTopLevel()) {
150 JS::loader::ModuleLoadRequest* root =
151 mRequest->AsModuleRequest()->GetRootModule();
152 return root->GetScriptLoadContext()->IsPreload();
155 MOZ_ASSERT_IF(mIsPreload, !GetScriptElement());
156 return mIsPreload;
159 bool ScriptLoadContext::CompileStarted() const {
160 return mRequest->IsCompiling() || (mRequest->IsFinished() && mWasCompiledOMT);
163 nsIScriptElement* ScriptLoadContext::GetScriptElement() const {
164 nsCOMPtr<nsIScriptElement> scriptElement =
165 do_QueryInterface(mRequest->mFetchOptions->mElement);
166 return scriptElement;
169 void ScriptLoadContext::SetIsLoadRequest(nsIScriptElement* aElement) {
170 MOZ_ASSERT(aElement);
171 MOZ_ASSERT(!GetScriptElement());
172 MOZ_ASSERT(IsPreload());
173 // We are not tracking our own element, and are relying on the one in
174 // FetchOptions.
175 mRequest->mFetchOptions->mElement = do_QueryInterface(aElement);
176 mIsPreload = false;
179 void ScriptLoadContext::GetProfilerLabel(nsACString& aOutString) {
180 if (!profiler_is_active()) {
181 aOutString.Append("<script> element");
182 return;
184 aOutString.Append("<script");
185 if (IsAsyncScript()) {
186 aOutString.Append(" async");
187 } else if (IsDeferredScript()) {
188 aOutString.Append(" defer");
190 if (mRequest->IsModuleRequest()) {
191 aOutString.Append(" type=\"module\"");
194 nsAutoCString url;
195 if (mRequest->mURI) {
196 mRequest->mURI->GetAsciiSpec(url);
197 } else {
198 url = "<unknown>";
201 if (mIsInline) {
202 if (GetParserCreated() != NOT_FROM_PARSER) {
203 aOutString.Append("> inline at line ");
204 aOutString.AppendInt(mLineNo);
205 aOutString.Append(" of ");
206 } else {
207 aOutString.Append("> inline (dynamically created) in ");
209 aOutString.Append(url);
210 } else {
211 aOutString.Append(" src=\"");
212 aOutString.Append(url);
213 aOutString.Append("\">");
217 } // namespace mozilla::dom