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 mozilla_dom_ScriptLoadContext_h
8 #define mozilla_dom_ScriptLoadContext_h
10 #include "js/AllocPolicy.h"
11 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
12 #include "js/CompileOptions.h" // JS::OwningCompileOptions
13 #include "js/experimental/JSStencil.h" // JS::FrontendContext, JS::Stencil, JS::InstantiationStorage
14 #include "js/RootingAPI.h"
15 #include "js/SourceText.h"
16 #include "js/Transcoding.h" // JS::TranscodeResult
17 #include "js/TypeDecls.h"
18 #include "js/loader/LoadContextBase.h"
19 #include "js/loader/ScriptKind.h"
20 #include "mozilla/AlreadyAddRefed.h"
21 #include "mozilla/Atomics.h"
22 #include "mozilla/Assertions.h"
23 #include "mozilla/CORSMode.h"
24 #include "mozilla/dom/SRIMetadata.h"
25 #include "mozilla/LinkedList.h"
26 #include "mozilla/Maybe.h"
27 #include "mozilla/MaybeOneOf.h"
28 #include "mozilla/Mutex.h"
29 #include "mozilla/PreloaderBase.h"
30 #include "mozilla/RefPtr.h"
31 #include "mozilla/StaticPrefs_dom.h"
32 #include "mozilla/TaskController.h" // mozilla::Task
33 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
34 #include "mozilla/Variant.h"
35 #include "mozilla/Vector.h"
37 #include "nsCycleCollectionParticipant.h"
38 #include "nsIScriptElement.h"
40 class nsICacheInfoChannel
;
43 namespace mozilla::dom
{
48 * DOM specific ScriptLoadContext.
50 * ScriptLoadContexts augment the loading of a ScriptLoadRequest. They
51 * describe how a ScriptLoadRequests loading and evaluation needs to be
52 * augmented, based on the information provided by the loading context. In
53 * the case of the DOM, the ScriptLoadContext is used to identify how a script
54 * should be loaded according to information found in the HTML document into
55 * which it will be loaded. The following fields describe how the
56 * ScriptLoadRequest will be loaded.
59 * stores the mode (Async, Sync, Deferred), and preload, which
60 * allows the ScriptLoader to decide if the script should be pushed
61 * offThread, or if the preloaded request should be used.
63 * Set when the script tag is in the head, and should be treated as
66 * Set for scripts whose bodies are inline in the html. In this case,
67 * the script does not need to be fetched first.
69 * Set if we are in an XSLT request.
71 * Set for scripts that are preloaded in a
72 * <link rel="preload" as="script"> or <link rel="modulepreload">
75 * In addition to describing how the ScriptLoadRequest will be loaded by the
76 * DOM ScriptLoader, the ScriptLoadContext contains fields that facilitate
77 * those custom behaviors, including support for offthread parsing and preload
78 * element specific controls.
82 // Base class for the off-thread compile or off-thread decode tasks.
83 class CompileOrDecodeTask
: public mozilla::Task
{
85 CompileOrDecodeTask();
86 virtual ~CompileOrDecodeTask();
88 nsresult
InitFrontendContext();
90 void DidRunTask(const MutexAutoLock
& aProofOfLock
,
91 RefPtr
<JS::Stencil
>&& aStencil
);
93 bool IsCancelled(const MutexAutoLock
& aProofOfLock
) const {
98 // Returns the result of the compilation or decode if it was successful.
99 // Returns nullptr otherwise, and sets pending exception on JSContext.
101 // aInstantiationStorage receives the storage allocated off main thread
102 // on successful case.
103 already_AddRefed
<JS::Stencil
> StealResult(
104 JSContext
* aCx
, JS::InstantiationStorage
* aInstantiationStorage
);
107 // If the task is already running, this waits for the task to finish.
111 // This mutex is locked during running the task or cancelling task.
112 mozilla::Mutex mMutex
;
114 // The result of decode task, to distinguish throwing case and decode error.
115 JS::TranscodeResult mResult
= JS::TranscodeResult::Ok
;
117 // An option used to compile the code, or the equivalent for decode.
118 // This holds the filename pointed by errors reported to JS::FrontendContext.
119 JS::OwningCompileOptions mOptions
;
121 // Owning-pointer for the context associated with the script compilation.
123 // The context is allocated on main thread in InitFrontendContext method,
124 // and is freed on any thread in the destructor.
125 JS::FrontendContext
* mFrontendContext
= nullptr;
127 bool mIsCancelled
= false;
130 // The result of the compilation or decode.
131 RefPtr
<JS::Stencil
> mStencil
;
133 JS::InstantiationStorage mInstantiationStorage
;
136 class ScriptLoadContext
: public JS::loader::LoadContextBase
,
137 public PreloaderBase
{
139 virtual ~ScriptLoadContext();
142 explicit ScriptLoadContext(nsIScriptElement
* aScriptElement
= nullptr);
144 NS_DECL_ISUPPORTS_INHERITED
145 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ScriptLoadContext
,
146 JS::loader::LoadContextBase
)
148 static void PrioritizeAsPreload(nsIChannel
* aChannel
);
150 bool IsPreload() const override
;
152 bool CompileStarted() const;
154 bool IsTracking() const { return mIsTracking
; }
155 void SetIsTracking() {
156 MOZ_ASSERT(!mIsTracking
);
160 void BlockOnload(Document
* aDocument
);
162 void MaybeUnblockOnload();
164 enum class ScriptMode
: uint8_t {
168 eLinkPreload
// this is a load initiated by <link rel="preload"
169 // as="script"> or <link rel="modulepreload"> tag
172 void SetScriptMode(bool aDeferAttr
, bool aAsyncAttr
, bool aLinkPreload
);
174 bool IsLinkPreloadScript() const {
175 return mScriptMode
== ScriptMode::eLinkPreload
;
178 bool IsBlockingScript() const { return mScriptMode
== ScriptMode::eBlocking
; }
180 bool IsDeferredScript() const { return mScriptMode
== ScriptMode::eDeferred
; }
182 bool IsAsyncScript() const { return mScriptMode
== ScriptMode::eAsync
; }
184 // Accessors for the script element, for each purpose.
186 // The script element reference is guaranteed to be available only for:
187 // * inline/external classic script
188 // * inline/external top-level module
190 // The reference is valid only for specific purpose explained below.
192 // For aLoadingNode parameter of a new channel.
193 // TODO: This is basically unnecessary and a document can be used instead.
195 inline nsIScriptElement
* GetScriptElementForLoadingNode() const {
196 MOZ_ASSERT(mScriptElement
);
197 return mScriptElement
;
200 // For TRACE_FOR_TEST macros.
201 // NOTE: This is called also for imported modules.
202 // The consumer allows nullptr.
203 inline nsIScriptElement
* GetScriptElementForTrace() const {
204 return mScriptElement
;
207 // Event target for beforescriptexecute/afterscriptexecute events.
208 inline nsIScriptElement
* GetScriptElementForExecuteEvents() const {
209 MOZ_ASSERT(mScriptElement
);
210 return mScriptElement
;
213 // For ScriptLoader::mCurrentParserInsertedScript.
214 inline nsIScriptElement
* GetScriptElementForCurrentParserInsertedScript()
216 MOZ_ASSERT(mScriptElement
);
217 return mScriptElement
;
220 // For nsIScriptLoaderObserver.
221 inline nsIScriptElement
* GetScriptElementForObserver() const {
222 MOZ_ASSERT(mScriptElement
);
223 return mScriptElement
;
226 // For URL classifier.
227 inline nsIScriptElement
* GetScriptElementForUrlClassifier() const {
228 return mScriptElement
;
231 // For AutoCurrentScriptUpdater.
232 // This is valid only for classic script.
233 inline nsIScriptElement
* GetScriptElementForCurrentScript() const {
234 MOZ_ASSERT(mScriptElement
);
235 return mScriptElement
;
238 bool HasScriptElement() const;
240 void GetInlineScriptText(nsAString
& aText
) const;
242 void GetHintCharset(nsAString
& aCharset
) const;
244 // TODO: Reimplement with mLineNo/mColumnNo.
245 uint32_t GetScriptLineNumber() const;
246 JS::ColumnNumberOneOrigin
GetScriptColumnNumber() const;
248 void BeginEvaluatingTopLevel() const;
249 void EndEvaluatingTopLevel() const;
251 void UnblockParser() const;
252 void ContinueParserAsync() const;
254 Document
* GetScriptOwnerDocument() const;
256 // Make this request a preload (speculative) request.
257 void SetIsPreloadRequest() {
258 MOZ_ASSERT(!HasScriptElement());
259 MOZ_ASSERT(!IsPreload());
263 // Make a preload request into an actual load request for the given element.
264 void SetIsLoadRequest(nsIScriptElement
* aElement
);
266 FromParser
GetParserCreated() const {
267 if (!mScriptElement
) {
268 return NOT_FROM_PARSER
;
270 return mScriptElement
->GetParserCreated();
273 // Used to output a string for the Gecko Profiler.
274 void GetProfilerLabel(nsACString
& aOutString
) override
;
276 void MaybeCancelOffThreadScript();
278 // Finish the off-main-thread compilation and return the result, or
279 // convert the compilation error to runtime error.
280 already_AddRefed
<JS::Stencil
> StealOffThreadResult(
281 JSContext
* aCx
, JS::InstantiationStorage
* aInstantiationStorage
);
283 ScriptMode mScriptMode
; // Whether this is a blocking, defer or async script.
284 bool mScriptFromHead
; // Synchronous head script block loading of other non
286 bool mIsInline
; // Is the script inline or loaded?
287 bool mInDeferList
; // True if we live in mDeferRequests.
288 bool mInAsyncList
; // True if we live in mLoadingAsyncRequests or
289 // mLoadedAsyncRequests.
290 bool mIsNonAsyncScriptInserted
; // True if we live in
291 // mNonAsyncExternalScriptInsertedRequests
292 bool mIsXSLT
; // True if we live in mXSLTRequests.
293 bool mInCompilingList
; // True if we are in mOffThreadCompilingRequests.
294 bool mIsTracking
; // True if the script comes from a source on our
295 // tracking protection list.
296 bool mWasCompiledOMT
; // True if the script has been compiled off main
299 // Task that performs off-thread compilation or off-thread decode.
300 // This field is used to take the result of the task, or cancel the task.
302 // Set to non-null on the task creation, and set to null when taking the
303 // result or cancelling the task.
304 RefPtr
<CompileOrDecodeTask
> mCompileOrDecodeTask
;
307 JS::ColumnNumberOneOrigin mColumnNo
;
309 // Set on scripts and top level modules.
312 // Non-null if there is a document that this request is blocking from loading.
313 RefPtr
<Document
> mLoadBlockedDocument
;
315 // The script element which trigerred this script load.
316 // This is valid only for classic script and top-level module script.
317 nsCOMPtr
<nsIScriptElement
> mScriptElement
;
319 // For preload requests, we defer reporting errors to the console until the
321 nsresult mUnreportedPreloadError
;
324 } // namespace mozilla::dom
326 #endif // mozilla_dom_ScriptLoadContext_h