Backed out changeset 9d8b4c0b99ed (bug 1945683) for causing btime failures. CLOSED...
[gecko.git] / js / loader / ScriptLoadRequest.h
bloba20493001963110fbbacb87e15e58fecc7309521
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 #ifndef js_loader_ScriptLoadRequest_h
8 #define js_loader_ScriptLoadRequest_h
10 #include "js/experimental/JSStencil.h"
11 #include "js/RootingAPI.h"
12 #include "js/SourceText.h"
13 #include "js/TypeDecls.h"
14 #include "mozilla/Atomics.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/dom/CacheExpirationTime.h"
17 #include "mozilla/dom/SRIMetadata.h"
18 #include "mozilla/LinkedList.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/PreloaderBase.h"
21 #include "mozilla/RefPtr.h"
22 #include "mozilla/SharedSubResourceCache.h" // mozilla::SubResourceNetworkMetadataHolder
23 #include "mozilla/StaticPrefs_dom.h"
24 #include "mozilla/Variant.h"
25 #include "mozilla/Vector.h"
26 #include "nsCycleCollectionParticipant.h"
27 #include "nsIGlobalObject.h"
28 #include "LoadedScript.h"
29 #include "ScriptKind.h"
30 #include "ScriptFetchOptions.h"
32 class nsICacheInfoChannel;
34 namespace mozilla::dom {
36 class ScriptLoadContext;
37 class WorkerLoadContext;
38 class WorkletLoadContext;
39 enum class RequestPriority : uint8_t;
41 } // namespace mozilla::dom
43 namespace mozilla::loader {
44 class SyncLoadContext;
45 } // namespace mozilla::loader
47 namespace JS {
48 namespace loader {
50 class LoadContextBase;
51 class ModuleLoadRequest;
52 class ScriptLoadRequestList;
55 * ScriptLoadRequest
57 * ScriptLoadRequest is a generic representation of a JavaScript script that
58 * will be loaded by a Script/Module loader. This representation is used by the
59 * DOM ScriptLoader and will be used by workers and MOZJSComponentLoader.
61 * The ScriptLoadRequest contains information about the kind of script (classic
62 * or module), the URI, and the ScriptFetchOptions associated with the script.
63 * It is responsible for holding the script data once the fetch is complete, or
64 * if the request is cached, the bytecode.
66 * Relationship to ScriptLoadContext:
68 * ScriptLoadRequest and ScriptLoadContexts have a circular pointer. A
69 * ScriptLoadContext augments the loading of a ScriptLoadRequest by providing
70 * additional information regarding the loading and evaluation behavior (see
71 * the ScriptLoadContext class for details). In terms of responsibility,
72 * the ScriptLoadRequest represents "What" is being loaded, and the
73 * ScriptLoadContext represents "How".
75 * TODO: see if we can use it in the jsshell script loader. We need to either
76 * remove ISUPPORTS or find a way to encorporate that in the jsshell. We would
77 * then only have one implementation of the script loader, and it would be
78 * tested whenever jsshell tests are run. This would mean finding another way to
79 * create ScriptLoadRequest lists.
83 class ScriptLoadRequest : public nsISupports,
84 private mozilla::LinkedListElement<ScriptLoadRequest>,
85 public LoadedScriptDelegate<ScriptLoadRequest> {
86 using super = LinkedListElement<ScriptLoadRequest>;
88 // Allow LinkedListElement<ScriptLoadRequest> to cast us to itself as needed.
89 friend class mozilla::LinkedListElement<ScriptLoadRequest>;
90 friend class ScriptLoadRequestList;
92 protected:
93 virtual ~ScriptLoadRequest();
95 public:
96 using SRIMetadata = mozilla::dom::SRIMetadata;
97 ScriptLoadRequest(ScriptKind aKind, nsIURI* aURI,
98 mozilla::dom::ReferrerPolicy aReferrerPolicy,
99 ScriptFetchOptions* aFetchOptions,
100 const SRIMetadata& aIntegrity, nsIURI* aReferrer,
101 LoadContextBase* aContext);
103 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
104 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScriptLoadRequest)
106 using super::getNext;
107 using super::isInList;
109 template <typename T, typename D = JS::DeletePolicy<T>>
110 using UniquePtr = mozilla::UniquePtr<T, D>;
112 bool IsModuleRequest() const { return mKind == ScriptKind::eModule; }
113 bool IsImportMapRequest() const { return mKind == ScriptKind::eImportMap; }
115 ModuleLoadRequest* AsModuleRequest();
116 const ModuleLoadRequest* AsModuleRequest() const;
118 bool IsCacheable() const;
120 CacheExpirationTime ExpirationTime() const { return mExpirationTime; }
122 void SetMinimumExpirationTime(const CacheExpirationTime& aExpirationTime) {
123 mExpirationTime.SetMinimum(aExpirationTime);
126 virtual bool IsTopLevel() const { return true; };
128 virtual void Cancel();
130 virtual void SetReady();
132 enum class State : uint8_t {
133 CheckingCache,
134 PendingFetchingError,
135 Fetching,
136 Compiling,
137 LoadingImports,
138 CancelingImports,
139 Ready,
140 Canceled
143 // Before any attempt at fetching resources from the cache we should first
144 // make sure that the resource does not yet exists in the cache. In which case
145 // we might simply alias its LoadedScript. Otherwise a new one would be
146 // created.
147 bool IsCheckingCache() const { return mState == State::CheckingCache; }
149 // Setup and load resources, to fill the LoadedScript and make it usable by
150 // the JavaScript engine.
151 bool IsFetching() const { return mState == State::Fetching; }
152 bool IsCompiling() const { return mState == State::Compiling; }
153 bool IsLoadingImports() const { return mState == State::LoadingImports; }
154 bool IsCancelingImports() const { return mState == State::CancelingImports; }
155 bool IsCanceled() const { return mState == State::Canceled; }
157 bool IsPendingFetchingError() const {
158 return mState == State::PendingFetchingError;
161 // Return whether the request has been completed, either successfully or
162 // otherwise.
163 bool IsFinished() const {
164 return mState == State::Ready || mState == State::Canceled;
167 mozilla::dom::RequestPriority FetchPriority() const {
168 return mFetchOptions->mFetchPriority;
171 enum mozilla::dom::ReferrerPolicy ReferrerPolicy() const {
172 return mReferrerPolicy;
175 void UpdateReferrerPolicy(mozilla::dom::ReferrerPolicy aReferrerPolicy) {
176 mReferrerPolicy = aReferrerPolicy;
179 enum ParserMetadata ParserMetadata() const {
180 return mFetchOptions->mParserMetadata;
183 const nsString& Nonce() const { return mFetchOptions->mNonce; }
185 nsIPrincipal* TriggeringPrincipal() const {
186 return mFetchOptions->mTriggeringPrincipal;
189 // Convert a CheckingCache ScriptLoadRequest into a Ready one, by populating
190 // the script data from cached script.
191 void CacheEntryFound(LoadedScript* aLoadedScript);
193 // Convert a CheckingCache ScriptLoadRequest into a Fetching one, by creating
194 // a new LoadedScript which is matching the ScriptKind provided when
195 // constructing this ScriptLoadRequest.
196 void NoCacheEntryFound();
198 void SetPendingFetchingError();
200 bool PassedConditionForBytecodeEncoding() const {
201 return mBytecodeEncodingPlan == BytecodeEncodingPlan::PassedCondition ||
202 mBytecodeEncodingPlan == BytecodeEncodingPlan::MarkedForEncode;
205 void MarkSkippedBytecodeEncoding() {
206 MOZ_ASSERT(mBytecodeEncodingPlan == BytecodeEncodingPlan::Uninitialized ||
207 mBytecodeEncodingPlan == BytecodeEncodingPlan::PassedCondition);
208 mBytecodeEncodingPlan = BytecodeEncodingPlan::Skipped;
211 void MarkPassedConditionForBytecodeEncoding() {
212 MOZ_ASSERT(mBytecodeEncodingPlan == BytecodeEncodingPlan::Uninitialized);
213 mBytecodeEncodingPlan = BytecodeEncodingPlan::PassedCondition;
216 bool IsMarkedForBytecodeEncoding() const {
217 return mBytecodeEncodingPlan == BytecodeEncodingPlan::MarkedForEncode;
220 protected:
221 void MarkForBytecodeEncoding() {
222 MOZ_ASSERT(mBytecodeEncodingPlan == BytecodeEncodingPlan::PassedCondition);
223 mBytecodeEncodingPlan = BytecodeEncodingPlan::MarkedForEncode;
226 public:
227 void MarkScriptForBytecodeEncoding(JSScript* aScript);
229 mozilla::CORSMode CORSMode() const { return mFetchOptions->mCORSMode; }
231 void DropBytecodeCacheReferences();
233 bool HasLoadContext() const { return mLoadContext; }
234 bool HasScriptLoadContext() const;
235 bool HasWorkerLoadContext() const;
237 mozilla::dom::ScriptLoadContext* GetScriptLoadContext();
238 const mozilla::dom::ScriptLoadContext* GetScriptLoadContext() const;
240 mozilla::loader::SyncLoadContext* GetSyncLoadContext();
242 mozilla::dom::WorkerLoadContext* GetWorkerLoadContext();
244 mozilla::dom::WorkletLoadContext* GetWorkletLoadContext();
246 const LoadedScript* getLoadedScript() const { return mLoadedScript.get(); }
247 LoadedScript* getLoadedScript() { return mLoadedScript.get(); }
250 * Set the request's mBaseURL, based on aChannel.
251 * aOriginalURI is the result of aChannel->GetOriginalURI.
253 void SetBaseURLFromChannelAndOriginalURI(nsIChannel* aChannel,
254 nsIURI* aOriginalURI);
256 const ScriptKind mKind; // Whether this is a classic script or a module
257 // script.
259 State mState; // Are we still waiting for a load to complete?
260 bool mFetchSourceOnly; // Request source, not cached bytecode.
262 enum class BytecodeEncodingPlan : uint8_t {
263 // This is not yet considered for encoding.
264 Uninitialized,
266 // This is marked for skipping the encoding.
267 Skipped,
269 // This fits the condition for the encoding (e.g. file size, fetch count).
270 PassedCondition,
272 // This is marked for encoding, with setting sufficient input,
273 // e.g. mScriptForBytecodeEncoding for script.
274 MarkedForEncode,
276 BytecodeEncodingPlan mBytecodeEncodingPlan =
277 BytecodeEncodingPlan::Uninitialized;
279 // The referrer policy used for the initial fetch and for fetching any
280 // imported modules
281 enum mozilla::dom::ReferrerPolicy mReferrerPolicy;
283 CacheExpirationTime mExpirationTime = CacheExpirationTime::Never();
285 RefPtr<ScriptFetchOptions> mFetchOptions;
286 RefPtr<mozilla::SubResourceNetworkMetadataHolder> mNetworkMetadata;
287 const SRIMetadata mIntegrity;
288 const nsCOMPtr<nsIURI> mReferrer;
289 mozilla::Maybe<nsString>
290 mSourceMapURL; // Holds source map url for loaded scripts
292 const nsCOMPtr<nsIURI> mURI;
293 nsCOMPtr<nsIPrincipal> mOriginPrincipal;
295 // Keep the URI's filename alive during off thread parsing.
296 // Also used by workers to report on errors while loading, and used by
297 // worklets as the file name in compile options.
298 nsAutoCString mURL;
300 // The base URL used for resolving relative module imports.
301 nsCOMPtr<nsIURI> mBaseURL;
303 // The loaded script holds the source / bytecode which is loaded.
305 // Currently it is used to hold information which are needed by the Debugger.
306 // Soon it would be used as a way to dissociate the LoadRequest from the
307 // loaded value, such that multiple request referring to the same content
308 // would share the same loaded script.
309 RefPtr<LoadedScript> mLoadedScript;
311 // Holds the top-level JSScript that corresponds to the current source, once
312 // it is parsed, and marked to be saved in the bytecode cache.
314 // NOTE: This field is not used for ModuleLoadRequest.
315 JS::Heap<JSScript*> mScriptForBytecodeEncoding;
317 // Holds the Cache information, which is used to register the bytecode
318 // on the cache entry, such that we can load it the next time.
319 nsCOMPtr<nsICacheInfoChannel> mCacheInfo;
321 // LoadContext for augmenting the load depending on the loading
322 // context (DOM, Worker, etc.)
323 RefPtr<LoadContextBase> mLoadContext;
325 // EarlyHintRegistrar id to connect the http channel back to the preload, with
326 // a default of value of 0 indicating that this request is not an early hints
327 // preload.
328 uint64_t mEarlyHintPreloaderId;
331 class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest> {
332 using super = mozilla::LinkedList<ScriptLoadRequest>;
334 public:
335 ~ScriptLoadRequestList();
337 void CancelRequestsAndClear();
339 #ifdef DEBUG
340 bool Contains(ScriptLoadRequest* aElem) const;
341 #endif // DEBUG
343 using super::getFirst;
344 using super::isEmpty;
346 void AppendElement(ScriptLoadRequest* aElem) {
347 MOZ_ASSERT(!aElem->isInList());
348 NS_ADDREF(aElem);
349 insertBack(aElem);
352 already_AddRefed<ScriptLoadRequest> Steal(ScriptLoadRequest* aElem) {
353 aElem->removeFrom(*this);
354 return dont_AddRef(aElem);
357 already_AddRefed<ScriptLoadRequest> StealFirst() {
358 MOZ_ASSERT(!isEmpty());
359 return Steal(getFirst());
362 void Remove(ScriptLoadRequest* aElem) {
363 aElem->removeFrom(*this);
364 NS_RELEASE(aElem);
368 inline void ImplCycleCollectionUnlink(ScriptLoadRequestList& aField) {
369 while (!aField.isEmpty()) {
370 RefPtr<ScriptLoadRequest> first = aField.StealFirst();
374 inline void ImplCycleCollectionTraverse(
375 nsCycleCollectionTraversalCallback& aCallback,
376 ScriptLoadRequestList& aField, const char* aName, uint32_t aFlags) {
377 for (ScriptLoadRequest* request = aField.getFirst(); request;
378 request = request->getNext()) {
379 CycleCollectionNoteChild(aCallback, request, aName, aFlags);
383 } // namespace loader
384 } // namespace JS
386 #endif // js_loader_ScriptLoadRequest_h