Bug 1843838 - Rename ScriptLoadRequest::IsReadyToRun to IsFinished since this returns...
[gecko.git] / js / loader / ScriptLoadRequest.cpp
blobf3bab584096bc1e1c432551fb208133463691d63
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 "ScriptLoadRequest.h"
8 #include "GeckoProfiler.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/ScriptLoadContext.h"
12 #include "mozilla/dom/WorkerLoadContext.h"
13 #include "mozilla/dom/ScriptSettings.h"
14 #include "mozilla/HoldDropJSObjects.h"
15 #include "mozilla/StaticPrefs_dom.h"
16 #include "mozilla/Unused.h"
17 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
19 #include "js/OffThreadScriptCompilation.h"
20 #include "js/SourceText.h"
22 #include "ModuleLoadRequest.h"
23 #include "nsContentUtils.h"
24 #include "nsICacheInfoChannel.h"
25 #include "nsIClassOfService.h"
26 #include "nsISupportsPriority.h"
28 using JS::SourceText;
30 namespace JS::loader {
32 //////////////////////////////////////////////////////////////
33 // ScriptFetchOptions
34 //////////////////////////////////////////////////////////////
36 NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions, mTriggeringPrincipal, mElement)
38 ScriptFetchOptions::ScriptFetchOptions(
39 mozilla::CORSMode aCORSMode, mozilla::dom::ReferrerPolicy aReferrerPolicy,
40 const nsAString& aNonce, const ParserMetadata aParserMetadata,
41 nsIPrincipal* aTriggeringPrincipal, mozilla::dom::Element* aElement)
42 : mCORSMode(aCORSMode),
43 mReferrerPolicy(aReferrerPolicy),
44 mNonce(aNonce),
45 mParserMetadata(aParserMetadata),
46 mTriggeringPrincipal(aTriggeringPrincipal),
47 mElement(aElement) {}
49 ScriptFetchOptions::~ScriptFetchOptions() = default;
51 //////////////////////////////////////////////////////////////
52 // ScriptLoadRequest
53 //////////////////////////////////////////////////////////////
55 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadRequest)
56 NS_INTERFACE_MAP_ENTRY(nsISupports)
57 NS_INTERFACE_MAP_END
59 NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoadRequest)
60 NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest)
62 NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest)
64 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest)
65 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions, mCacheInfo, mLoadContext)
66 tmp->mScriptForBytecodeEncoding = nullptr;
67 tmp->DropBytecodeCacheReferences();
68 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
70 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest)
71 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions, mCacheInfo, mLoadContext)
72 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
74 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadRequest)
75 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptForBytecodeEncoding)
76 NS_IMPL_CYCLE_COLLECTION_TRACE_END
78 ScriptLoadRequest::ScriptLoadRequest(ScriptKind aKind, nsIURI* aURI,
79 ScriptFetchOptions* aFetchOptions,
80 const SRIMetadata& aIntegrity,
81 nsIURI* aReferrer,
82 LoadContextBase* aContext)
83 : mKind(aKind),
84 mState(State::Fetching),
85 mFetchSourceOnly(false),
86 mDataType(DataType::eUnknown),
87 mFetchOptions(aFetchOptions),
88 mIntegrity(aIntegrity),
89 mReferrer(aReferrer),
90 mScriptTextLength(0),
91 mScriptBytecode(),
92 mBytecodeOffset(0),
93 mURI(aURI),
94 mLoadContext(aContext),
95 mEarlyHintPreloaderId(0) {
96 MOZ_ASSERT(mFetchOptions);
97 if (mLoadContext) {
98 mLoadContext->SetRequest(this);
102 ScriptLoadRequest::~ScriptLoadRequest() { DropJSObjects(this); }
104 void ScriptLoadRequest::SetReady() {
105 MOZ_ASSERT(!IsFinished());
106 mState = State::Ready;
109 void ScriptLoadRequest::Cancel() {
110 mState = State::Canceled;
111 if (HasScriptLoadContext()) {
112 GetScriptLoadContext()->MaybeCancelOffThreadScript();
116 void ScriptLoadRequest::DropBytecodeCacheReferences() {
117 mCacheInfo = nullptr;
118 DropJSObjects(this);
121 bool ScriptLoadRequest::HasScriptLoadContext() const {
122 return HasLoadContext() && mLoadContext->IsWindowContext();
125 bool ScriptLoadRequest::HasWorkerLoadContext() const {
126 return HasLoadContext() && mLoadContext->IsWorkerContext();
129 mozilla::dom::ScriptLoadContext* ScriptLoadRequest::GetScriptLoadContext() {
130 MOZ_ASSERT(mLoadContext);
131 return mLoadContext->AsWindowContext();
134 mozilla::loader::ComponentLoadContext*
135 ScriptLoadRequest::GetComponentLoadContext() {
136 MOZ_ASSERT(mLoadContext);
137 return mLoadContext->AsComponentContext();
140 mozilla::dom::WorkerLoadContext* ScriptLoadRequest::GetWorkerLoadContext() {
141 MOZ_ASSERT(mLoadContext);
142 return mLoadContext->AsWorkerContext();
145 mozilla::dom::WorkletLoadContext* ScriptLoadRequest::GetWorkletLoadContext() {
146 MOZ_ASSERT(mLoadContext);
147 return mLoadContext->AsWorkletContext();
150 ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() {
151 MOZ_ASSERT(IsModuleRequest());
152 return static_cast<ModuleLoadRequest*>(this);
155 const ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() const {
156 MOZ_ASSERT(IsModuleRequest());
157 return static_cast<const ModuleLoadRequest*>(this);
160 void ScriptLoadRequest::SetBytecode() {
161 MOZ_ASSERT(IsUnknownDataType());
162 mDataType = DataType::eBytecode;
165 bool ScriptLoadRequest::IsUTF8ParsingEnabled() {
166 if (HasLoadContext()) {
167 if (mLoadContext->IsWindowContext()) {
168 return mozilla::StaticPrefs::
169 dom_script_loader_external_scripts_utf8_parsing_enabled();
171 if (mLoadContext->IsWorkerContext()) {
172 return mozilla::StaticPrefs::
173 dom_worker_script_loader_utf8_parsing_enabled();
176 return false;
179 void ScriptLoadRequest::ClearScriptSource() {
180 if (IsTextSource()) {
181 ClearScriptText();
185 void ScriptLoadRequest::MarkForBytecodeEncoding(JSScript* aScript) {
186 MOZ_ASSERT(!IsModuleRequest());
187 MOZ_ASSERT(!IsMarkedForBytecodeEncoding());
188 mScriptForBytecodeEncoding = aScript;
189 HoldJSObjects(this);
192 bool ScriptLoadRequest::IsMarkedForBytecodeEncoding() const {
193 if (IsModuleRequest()) {
194 return AsModuleRequest()->IsModuleMarkedForBytecodeEncoding();
197 return !!mScriptForBytecodeEncoding;
200 nsresult ScriptLoadRequest::GetScriptSource(JSContext* aCx,
201 MaybeSourceText* aMaybeSource) {
202 // If there's no script text, we try to get it from the element
203 if (HasScriptLoadContext() && GetScriptLoadContext()->mIsInline) {
204 nsAutoString inlineData;
205 GetScriptLoadContext()->GetScriptElement()->GetScriptText(inlineData);
207 size_t nbytes = inlineData.Length() * sizeof(char16_t);
208 JS::UniqueTwoByteChars chars(
209 static_cast<char16_t*>(JS_malloc(aCx, nbytes)));
210 if (!chars) {
211 return NS_ERROR_OUT_OF_MEMORY;
214 memcpy(chars.get(), inlineData.get(), nbytes);
216 SourceText<char16_t> srcBuf;
217 if (!srcBuf.init(aCx, std::move(chars), inlineData.Length())) {
218 return NS_ERROR_OUT_OF_MEMORY;
221 aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
222 return NS_OK;
225 size_t length = ScriptTextLength();
226 if (IsUTF16Text()) {
227 JS::UniqueTwoByteChars chars;
228 chars.reset(ScriptText<char16_t>().extractOrCopyRawBuffer());
229 if (!chars) {
230 JS_ReportOutOfMemory(aCx);
231 return NS_ERROR_OUT_OF_MEMORY;
234 SourceText<char16_t> srcBuf;
235 if (!srcBuf.init(aCx, std::move(chars), length)) {
236 return NS_ERROR_OUT_OF_MEMORY;
239 aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
240 return NS_OK;
243 MOZ_ASSERT(IsUTF8Text());
244 UniquePtr<Utf8Unit[], JS::FreePolicy> chars;
245 chars.reset(ScriptText<Utf8Unit>().extractOrCopyRawBuffer());
246 if (!chars) {
247 JS_ReportOutOfMemory(aCx);
248 return NS_ERROR_OUT_OF_MEMORY;
251 SourceText<Utf8Unit> srcBuf;
252 if (!srcBuf.init(aCx, std::move(chars), length)) {
253 return NS_ERROR_OUT_OF_MEMORY;
256 aMaybeSource->construct<SourceText<Utf8Unit>>(std::move(srcBuf));
257 return NS_OK;
260 //////////////////////////////////////////////////////////////
261 // ScriptLoadRequestList
262 //////////////////////////////////////////////////////////////
264 ScriptLoadRequestList::~ScriptLoadRequestList() { CancelRequestsAndClear(); }
266 void ScriptLoadRequestList::CancelRequestsAndClear() {
267 while (!isEmpty()) {
268 RefPtr<ScriptLoadRequest> first = StealFirst();
269 first->Cancel();
270 // And just let it go out of scope and die.
274 #ifdef DEBUG
275 bool ScriptLoadRequestList::Contains(ScriptLoadRequest* aElem) const {
276 for (const ScriptLoadRequest* req = getFirst(); req; req = req->getNext()) {
277 if (req == aElem) {
278 return true;
282 return false;
284 #endif // DEBUG
286 } // namespace JS::loader