summaryrefslogtreecommitdiffstats
path: root/dom/script/ScriptLoader.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/script/ScriptLoader.h780
1 files changed, 780 insertions, 0 deletions
diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h
new file mode 100644
index 0000000000..4228f7c758
--- /dev/null
+++ b/dom/script/ScriptLoader.h
@@ -0,0 +1,780 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_ScriptLoader_h
+#define mozilla_dom_ScriptLoader_h
+
+#include "js/TypeDecls.h"
+#include "nsCOMPtr.h"
+#include "nsRefPtrHashtable.h"
+#include "nsIScriptElement.h"
+#include "nsCOMArray.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsTArray.h"
+#include "nsINode.h"
+#include "nsIObserver.h"
+#include "nsIScriptLoaderObserver.h"
+#include "nsURIHashKey.h"
+#include "mozilla/CORSMode.h"
+#include "mozilla/dom/LoadedScript.h"
+#include "mozilla/dom/ScriptLoadRequest.h"
+#include "mozilla/MaybeOneOf.h"
+#include "mozilla/MozPromise.h"
+#include "ScriptKind.h"
+
+class nsCycleCollectionTraversalCallback;
+class nsIChannel;
+class nsIConsoleReportCollector;
+class nsIContent;
+class nsIIncrementalStreamLoader;
+class nsIPrincipal;
+class nsIScriptGlobalObject;
+class nsIURI;
+
+namespace JS {
+
+class CompileOptions;
+
+template <typename UnitT>
+class SourceText;
+
+} // namespace JS
+
+namespace mozilla {
+
+class LazyLogModule;
+union Utf8Unit;
+
+namespace dom {
+
+class AutoJSAPI;
+class DocGroup;
+class Document;
+class LoadedScript;
+class ModuleLoadRequest;
+class ModuleScript;
+class SRICheckDataVerifier;
+class SRIMetadata;
+class ScriptLoadHandler;
+class ScriptLoader;
+class ScriptRequestProcessor;
+
+enum class ReferrerPolicy : uint8_t;
+
+class AsyncCompileShutdownObserver final : public nsIObserver {
+ ~AsyncCompileShutdownObserver() { Unregister(); }
+
+ public:
+ explicit AsyncCompileShutdownObserver(ScriptLoader* aLoader)
+ : mScriptLoader(aLoader) {}
+
+ void OnShutdown();
+ void Unregister();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ private:
+ // Defined during registration in ScriptLoader constructor, and
+ // cleared during destructor, ScriptLoader::Destroy() or Shutdown.
+ ScriptLoader* mScriptLoader;
+};
+
+//////////////////////////////////////////////////////////////
+// Script loader implementation
+//////////////////////////////////////////////////////////////
+
+class ScriptLoader final : public nsISupports {
+ class MOZ_STACK_CLASS AutoCurrentScriptUpdater {
+ public:
+ AutoCurrentScriptUpdater(ScriptLoader* aScriptLoader,
+ nsIScriptElement* aCurrentScript)
+ : mOldScript(aScriptLoader->mCurrentScript),
+ mScriptLoader(aScriptLoader) {
+ nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentScript);
+ mScriptLoader->mCurrentScript =
+ node && !node->IsInShadowTree() ? aCurrentScript : nullptr;
+ }
+
+ ~AutoCurrentScriptUpdater() {
+ mScriptLoader->mCurrentScript.swap(mOldScript);
+ }
+
+ private:
+ nsCOMPtr<nsIScriptElement> mOldScript;
+ ScriptLoader* mScriptLoader;
+ };
+
+ friend class ModuleLoadRequest;
+ friend class ScriptRequestProcessor;
+ friend class ScriptLoadHandler;
+ friend class AutoCurrentScriptUpdater;
+
+ public:
+ explicit ScriptLoader(Document* aDocument);
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS(ScriptLoader)
+
+ /**
+ * The loader maintains a weak reference to the document with
+ * which it is initialized. This call forces the reference to
+ * be dropped.
+ */
+ void DropDocumentReference() { mDocument = nullptr; }
+
+ /**
+ * Add an observer for all scripts loaded through this loader.
+ *
+ * @param aObserver observer for all script processing.
+ */
+ nsresult AddObserver(nsIScriptLoaderObserver* aObserver) {
+ return mObservers.AppendObject(aObserver) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /**
+ * Remove an observer.
+ *
+ * @param aObserver observer to be removed
+ */
+ void RemoveObserver(nsIScriptLoaderObserver* aObserver) {
+ mObservers.RemoveObject(aObserver);
+ }
+
+ /**
+ * Process a script element. This will include both loading the
+ * source of the element if it is not inline and evaluating
+ * the script itself.
+ *
+ * If the script is an inline script that can be executed immediately
+ * (i.e. there are no other scripts pending) then ScriptAvailable
+ * and ScriptEvaluated will be called before the function returns.
+ *
+ * If true is returned the script could not be executed immediately.
+ * In this case ScriptAvailable is guaranteed to be called at a later
+ * point (as well as possibly ScriptEvaluated).
+ *
+ * @param aElement The element representing the script to be loaded and
+ * evaluated.
+ */
+ bool ProcessScriptElement(nsIScriptElement* aElement);
+
+ /**
+ * Gets the currently executing script. This is useful if you want to
+ * generate a unique key based on the currently executing script.
+ */
+ nsIScriptElement* GetCurrentScript() { return mCurrentScript; }
+
+ nsIScriptElement* GetCurrentParserInsertedScript() {
+ return mCurrentParserInsertedScript;
+ }
+
+ /**
+ * Whether the loader is enabled or not.
+ * When disabled, processing of new script elements is disabled.
+ * Any call to ProcessScriptElement() will return false. Note that
+ * this DOES NOT disable currently loading or executing scripts.
+ */
+ bool GetEnabled() { return mEnabled; }
+
+ void SetEnabled(bool aEnabled) {
+ if (!mEnabled && aEnabled) {
+ ProcessPendingRequestsAsync();
+ }
+ mEnabled = aEnabled;
+ }
+
+ /**
+ * Check whether to speculatively OMT parse scripts as soon as
+ * they are fetched, even if not a parser blocking request.
+ * Controlled by
+ * dom.script_loader.external_scripts.speculative_omt_parse_enabled
+ */
+ bool SpeculativeOMTParsingEnabled() const {
+ return mSpeculativeOMTParsingEnabled;
+ }
+
+ /**
+ * Add/remove a blocker for parser-blocking scripts (and XSLT
+ * scripts). Blockers will stop such scripts from executing, but not from
+ * loading.
+ */
+ void AddParserBlockingScriptExecutionBlocker() {
+ ++mParserBlockingBlockerCount;
+ }
+
+ void RemoveParserBlockingScriptExecutionBlocker() {
+ if (!--mParserBlockingBlockerCount && ReadyToExecuteScripts()) {
+ ProcessPendingRequestsAsync();
+ }
+ }
+
+ /**
+ * Add/remove a blocker for execution of all scripts. Blockers will stop
+ * scripts from executing, but not from loading.
+ */
+ void AddExecuteBlocker() { ++mBlockerCount; }
+
+ void RemoveExecuteBlocker() {
+ MOZ_ASSERT(mBlockerCount);
+ if (!--mBlockerCount) {
+ ProcessPendingRequestsAsync();
+ }
+ }
+
+ /**
+ * Convert the given buffer to a UTF-16 string. If the buffer begins with a
+ * BOM, it is interpreted as that encoding; otherwise the first of |aChannel|,
+ * |aHintCharset|, or |aDocument| that provides a recognized encoding is used,
+ * or Windows-1252 if none of them do.
+ *
+ * Encoding errors in the buffer are converted to replacement characters, so
+ * allocation failure is the only way this function can fail.
+ *
+ * @param aChannel Channel corresponding to the data. May be null.
+ * @param aData The data to convert
+ * @param aLength Length of the data
+ * @param aHintCharset Character set hint (e.g., from a charset attribute).
+ * @param aDocument Document which the data is loaded for. May be null.
+ * @param aBufOut [out] fresh char16_t array containing data converted to
+ * Unicode. Caller must js_free() this data when finished
+ * with it.
+ * @param aLengthOut [out] Length of array returned in aBufOut in number
+ * of char16_t code units.
+ */
+ static nsresult ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
+ uint32_t aLength,
+ const nsAString& aHintCharset,
+ Document* aDocument, char16_t*& aBufOut,
+ size_t& aLengthOut);
+
+ static inline nsresult ConvertToUTF16(nsIChannel* aChannel,
+ const uint8_t* aData, uint32_t aLength,
+ const nsAString& aHintCharset,
+ Document* aDocument,
+ JS::UniqueTwoByteChars& aBufOut,
+ size_t& aLengthOut) {
+ char16_t* bufOut;
+ nsresult rv = ConvertToUTF16(aChannel, aData, aLength, aHintCharset,
+ aDocument, bufOut, aLengthOut);
+ if (NS_SUCCEEDED(rv)) {
+ aBufOut.reset(bufOut);
+ }
+ return rv;
+ };
+
+ /**
+ * Convert the given buffer to a UTF-8 string. If the buffer begins with a
+ * BOM, it is interpreted as that encoding; otherwise the first of |aChannel|,
+ * |aHintCharset|, or |aDocument| that provides a recognized encoding is used,
+ * or Windows-1252 if none of them do.
+ *
+ * Encoding errors in the buffer are converted to replacement characters, so
+ * allocation failure is the only way this function can fail.
+ *
+ * @param aChannel Channel corresponding to the data. May be null.
+ * @param aData The data to convert
+ * @param aLength Length of the data
+ * @param aHintCharset Character set hint (e.g., from a charset attribute).
+ * @param aDocument Document which the data is loaded for. May be null.
+ * @param aBufOut [out] fresh Utf8Unit array containing data converted to
+ * Unicode. Caller must js_free() this data when finished
+ * with it.
+ * @param aLengthOut [out] Length of array returned in aBufOut in UTF-8 code
+ * units (i.e. in bytes).
+ */
+ static nsresult ConvertToUTF8(nsIChannel* aChannel, const uint8_t* aData,
+ uint32_t aLength, const nsAString& aHintCharset,
+ Document* aDocument, Utf8Unit*& aBufOut,
+ size_t& aLengthOut);
+
+ /**
+ * Handle the completion of a stream. This is called by the
+ * ScriptLoadHandler object which observes the IncrementalStreamLoader
+ * loading the script. The streamed content is expected to be stored on the
+ * aRequest argument.
+ */
+ nsresult OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
+ ScriptLoadRequest* aRequest,
+ nsresult aChannelStatus, nsresult aSRIStatus,
+ SRICheckDataVerifier* aSRIDataVerifier);
+
+ /**
+ * Returns wether any request is queued, and not executed yet.
+ */
+ bool HasPendingRequests();
+
+ /**
+ * Processes any pending requests that are ready for processing.
+ */
+ void ProcessPendingRequests();
+
+ /**
+ * Starts deferring deferred scripts and puts them in the mDeferredRequests
+ * queue instead.
+ */
+ void BeginDeferringScripts();
+
+ /**
+ * Notifies the script loader that parsing is done. If aTerminated is true,
+ * this will drop any pending scripts that haven't run yet, otherwise it will
+ * do nothing.
+ */
+ void ParsingComplete(bool aTerminated);
+
+ /**
+ * Notifies the script loader that the checkpoint to begin execution of defer
+ * scripts has been reached. This is either the end of of the document parse
+ * or the end of loading of parser-inserted stylesheets, whatever happens
+ * last.
+ *
+ * Otherwise, it will stop deferring scripts and immediately processes the
+ * mDeferredRequests queue.
+ *
+ * WARNING: This function will synchronously execute content scripts, so be
+ * prepared that the world might change around you.
+ */
+ void DeferCheckpointReached();
+
+ /**
+ * Returns the number of pending scripts, deferred or not.
+ */
+ uint32_t HasPendingOrCurrentScripts() {
+ return mCurrentScript || mParserBlockingRequest;
+ }
+
+ /**
+ * Adds aURI to the preload list and starts loading it.
+ *
+ * @param aURI The URI of the external script.
+ * @param aCharset The charset parameter for the script.
+ * @param aType The type parameter for the script.
+ * @param aCrossOrigin The crossorigin attribute for the script.
+ * Void if not present.
+ * @param aIntegrity The expect hash url, if avail, of the request
+ * @param aScriptFromHead Whether or not the script was a child of head
+ */
+ virtual void PreloadURI(nsIURI* aURI, const nsAString& aCharset,
+ const nsAString& aType, const nsAString& aCrossOrigin,
+ const nsAString& aIntegrity, bool aScriptFromHead,
+ bool aAsync, bool aDefer, bool aNoModule,
+ bool aLinkPreload,
+ const ReferrerPolicy aReferrerPolicy);
+
+ /**
+ * Process a request that was deferred so that the script could be compiled
+ * off thread.
+ */
+ nsresult ProcessOffThreadRequest(ScriptLoadRequest* aRequest);
+
+ bool AddPendingChildLoader(ScriptLoader* aChild) {
+ // XXX(Bug 1631371) Check if this should use a fallible operation as it
+ // pretended earlier. Else, change the return type to void.
+ mPendingChildLoaders.AppendElement(aChild);
+ return true;
+ }
+
+ mozilla::dom::DocGroup* GetDocGroup() const;
+
+ /**
+ * Register the fact that we saw the load event, and that we need to save the
+ * bytecode at the next loop cycle unless new scripts are waiting in the
+ * pipeline.
+ */
+ void LoadEventFired();
+
+ /**
+ * Destroy and prevent the ScriptLoader or the ScriptLoadRequests from owning
+ * any references to the JSScript or to the Request which might be used for
+ * caching the encoded bytecode.
+ */
+ void Destroy();
+
+ /**
+ * Implement the HostResolveImportedModule abstract operation.
+ *
+ * Resolve a module specifier string and look this up in the module
+ * map, returning the result. This is only called for previously
+ * loaded modules and always succeeds.
+ *
+ * @param aReferencingPrivate A JS::Value which is either undefined
+ * or contains a LoadedScript private pointer.
+ * @param aSpecifier The module specifier.
+ * @param aModuleOut This is set to the module found.
+ */
+ static void ResolveImportedModule(JSContext* aCx,
+ JS::Handle<JS::Value> aReferencingPrivate,
+ JS::Handle<JSString*> aSpecifier,
+ JS::MutableHandle<JSObject*> aModuleOut);
+
+ void StartDynamicImport(ModuleLoadRequest* aRequest);
+
+ /**
+ * Shorthand Wrapper for JSAPI FinishDynamicImport function for the reject
+ * case where we do not have `aEvaluationPromise`. As there is no evaluation
+ * Promise, JS::FinishDynamicImport will always reject.
+ *
+ * @param aRequest
+ * The module load request for the dynamic module.
+ * @param aResult
+ * The result of running ModuleEvaluate -- If this is successful, then
+ * we can await the associated EvaluationPromise.
+ */
+ void FinishDynamicImportAndReject(ModuleLoadRequest* aRequest,
+ nsresult aResult);
+
+ /**
+ * Wrapper for JSAPI FinishDynamicImport function. Takes an optional argument
+ * `aEvaluationPromise` which, if null, exits early.
+ *
+ * This is the non-tla version, which works with modules which return
+ * completion records.
+ *
+ * @param aCX
+ * The JSContext for the module.
+ * @param aRequest
+ * The module load request for the dynamic module.
+ * @param aResult
+ * The result of running ModuleEvaluate
+ */
+ void FinishDynamicImport_NoTLA(JSContext* aCx, ModuleLoadRequest* aRequest,
+ nsresult aResult);
+
+ /**
+ * Wrapper for JSAPI FinishDynamicImport function. Takes an optional argument
+ * `aEvaluationPromise` which, if null, exits early.
+ *
+ * This is the Top Level Await version, which works with modules which return
+ * promises.
+ *
+ * @param aCX
+ * The JSContext for the module.
+ * @param aRequest
+ * The module load request for the dynamic module.
+ * @param aResult
+ * The result of running ModuleEvaluate -- If this is successful, then
+ * we can await the associated EvaluationPromise.
+ * @param aEvaluationPromise
+ * The evaluation promise returned from evaluating the module. If this
+ * is null, JS::FinishDynamicImport will reject the dynamic import
+ * module promise.
+ */
+ void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest,
+ nsresult aResult,
+ JS::Handle<JSObject*> aEvaluationPromise);
+
+ /*
+ * Get the currently active script. This is used as the initiating script when
+ * executing timeout handler scripts.
+ */
+ static LoadedScript* GetActiveScript(JSContext* aCx);
+
+ Document* GetDocument() const { return mDocument; }
+
+ /**
+ * Called by shutdown observer.
+ */
+ void Shutdown();
+
+ private:
+ virtual ~ScriptLoader();
+
+ void EnsureModuleHooksInitialized();
+
+ ScriptLoadRequest* CreateLoadRequest(ScriptKind aKind, nsIURI* aURI,
+ nsIScriptElement* aElement,
+ nsIPrincipal* aTriggeringPrincipal,
+ mozilla::CORSMode aCORSMode,
+ const SRIMetadata& aIntegrity,
+ ReferrerPolicy aReferrerPolicy);
+
+ /**
+ * Unblocks the creator parser of the parser-blocking scripts.
+ */
+ void UnblockParser(ScriptLoadRequest* aParserBlockingRequest);
+
+ /**
+ * Asynchronously resumes the creator parser of the parser-blocking scripts.
+ */
+ void ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest);
+
+ bool ProcessExternalScript(nsIScriptElement* aElement, ScriptKind aScriptKind,
+ nsAutoString aTypeAttr,
+ nsIContent* aScriptContent);
+
+ bool ProcessInlineScript(nsIScriptElement* aElement, ScriptKind aScriptKind);
+
+ ScriptLoadRequest* LookupPreloadRequest(nsIScriptElement* aElement,
+ ScriptKind aScriptKind,
+ const SRIMetadata& aSRIMetadata);
+
+ void GetSRIMetadata(const nsAString& aIntegrityAttr,
+ SRIMetadata* aMetadataOut);
+
+ /**
+ * Given a script element, get the referrer policy should be applied to load
+ * requests.
+ */
+ ReferrerPolicy GetReferrerPolicy(nsIScriptElement* aElement);
+
+ /**
+ * Helper function to check the content policy for a given request.
+ */
+ static nsresult CheckContentPolicy(Document* aDocument, nsISupports* aContext,
+ const nsAString& aType,
+ ScriptLoadRequest* aRequest);
+
+ /**
+ * Helper function to determine whether an about: page loads a chrome: URI.
+ * Please note that this function only returns true if:
+ * * the about: page uses a ContentPrincipal with scheme about:
+ * * the about: page is not linkable from content
+ * (e.g. the function will return false for about:blank or about:srcdoc)
+ */
+ static bool IsAboutPageLoadingChromeURI(ScriptLoadRequest* aRequest,
+ Document* aDocument);
+
+ /**
+ * Start a load for aRequest's URI.
+ */
+ nsresult StartLoad(ScriptLoadRequest* aRequest);
+
+ /**
+ * Abort the current stream, and re-start with a new load request from scratch
+ * without requesting any alternate data. Returns NS_BINDING_RETARGETED on
+ * success, as this error code is used to abort the input stream.
+ */
+ nsresult RestartLoad(ScriptLoadRequest* aRequest);
+
+ void HandleLoadError(ScriptLoadRequest* aRequest, nsresult aResult);
+
+ /**
+ * Process any pending requests asynchronously (i.e. off an event) if there
+ * are any. Note that this is a no-op if there aren't any currently pending
+ * requests.
+ *
+ * This function is virtual to allow cross-library calls to SetEnabled()
+ */
+ virtual void ProcessPendingRequestsAsync();
+
+ /**
+ * If true, the loader is ready to execute parser-blocking scripts, and so are
+ * all its ancestors. If the loader itself is ready but some ancestor is not,
+ * this function will add an execute blocker and ask the ancestor to remove it
+ * once it becomes ready.
+ */
+ bool ReadyToExecuteParserBlockingScripts();
+
+ /**
+ * Return whether just this loader is ready to execute parser-blocking
+ * scripts.
+ */
+ bool SelfReadyToExecuteParserBlockingScripts() {
+ return ReadyToExecuteScripts() && !mParserBlockingBlockerCount;
+ }
+
+ /**
+ * Return whether this loader is ready to execute scripts in general.
+ */
+ bool ReadyToExecuteScripts() { return mEnabled && !mBlockerCount; }
+
+ nsresult VerifySRI(ScriptLoadRequest* aRequest,
+ nsIIncrementalStreamLoader* aLoader, nsresult aSRIStatus,
+ SRICheckDataVerifier* aSRIDataVerifier) const;
+
+ nsresult SaveSRIHash(ScriptLoadRequest* aRequest,
+ SRICheckDataVerifier* aSRIDataVerifier,
+ uint32_t* sriLength) const;
+
+ void ReportErrorToConsole(ScriptLoadRequest* aRequest,
+ nsresult aResult) const;
+ void ReportPreloadErrorsToConsole(ScriptLoadRequest* aRequest);
+
+ nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
+ bool* aCouldCompileOut);
+ nsresult ProcessRequest(ScriptLoadRequest* aRequest);
+ void ProcessDynamicImport(ModuleLoadRequest* aRequest);
+ nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest);
+ void FireScriptAvailable(nsresult aResult, ScriptLoadRequest* aRequest);
+ void FireScriptEvaluated(nsresult aResult, ScriptLoadRequest* aRequest);
+ nsresult EvaluateScript(ScriptLoadRequest* aRequest);
+
+ /**
+ * Queue the current script load request to be saved, when the page
+ * initialization ends. The page initialization end is defined as being the
+ * time when the load event got received, and when no more scripts are waiting
+ * to be executed.
+ */
+ void RegisterForBytecodeEncoding(ScriptLoadRequest* aRequest);
+
+ /**
+ * Check if all conditions are met, i-e that the onLoad event fired and that
+ * no more script have to be processed. If all conditions are met, queue an
+ * event to encode all the bytecode and save them on the cache.
+ */
+ void MaybeTriggerBytecodeEncoding();
+
+ /**
+ * Iterate over all script load request and save the bytecode of executed
+ * functions on the cache provided by the channel.
+ */
+ void EncodeBytecode();
+ void EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest);
+
+ void GiveUpBytecodeEncoding();
+
+ already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject();
+ nsresult FillCompileOptionsForRequest(const mozilla::dom::AutoJSAPI& jsapi,
+ ScriptLoadRequest* aRequest,
+ JS::Handle<JSObject*> aScopeChain,
+ JS::CompileOptions* aOptions);
+
+ uint32_t NumberOfProcessors();
+ nsresult PrepareLoadedRequest(ScriptLoadRequest* aRequest,
+ nsIIncrementalStreamLoader* aLoader,
+ nsresult aStatus);
+
+ void AddDeferRequest(ScriptLoadRequest* aRequest);
+ void AddAsyncRequest(ScriptLoadRequest* aRequest);
+ bool MaybeRemovedDeferRequests();
+
+ bool ShouldCompileOffThread(ScriptLoadRequest* aRequest);
+
+ void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
+
+ using MaybeSourceText =
+ mozilla::MaybeOneOf<JS::SourceText<char16_t>, JS::SourceText<Utf8Unit>>;
+
+ // Get source text. On success |aMaybeSource| will contain either UTF-8 or
+ // UTF-16 source; on failure it will remain in its initial state.
+ MOZ_MUST_USE nsresult GetScriptSource(JSContext* aCx,
+ ScriptLoadRequest* aRequest,
+ MaybeSourceText* aMaybeSource);
+
+ void SetModuleFetchStarted(ModuleLoadRequest* aRequest);
+ void SetModuleFetchFinishedAndResumeWaitingRequests(
+ ModuleLoadRequest* aRequest, nsresult aResult);
+
+ bool IsFetchingModule(ModuleLoadRequest* aRequest) const;
+
+ bool ModuleMapContainsURL(nsIURI* aURL) const;
+ RefPtr<mozilla::GenericNonExclusivePromise> WaitForModuleFetch(nsIURI* aURL);
+ ModuleScript* GetFetchedModule(nsIURI* aURL) const;
+
+ friend JSObject* HostResolveImportedModule(
+ JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
+ JS::Handle<JSString*> aSpecifier);
+
+ // Returns wether we should save the bytecode of this script after the
+ // execution of the script.
+ static bool ShouldCacheBytecode(ScriptLoadRequest* aRequest);
+
+ nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
+ nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
+ void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest);
+ void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
+ bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
+ JS::Value FindFirstParseError(ModuleLoadRequest* aRequest);
+ void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
+
+ RefPtr<mozilla::GenericPromise> StartFetchingModuleAndDependencies(
+ ModuleLoadRequest* aParent, nsIURI* aURI);
+
+ nsresult InitDebuggerDataForModuleTree(JSContext* aCx,
+ ModuleLoadRequest* aRequest);
+
+ void RunScriptWhenSafe(ScriptLoadRequest* aRequest);
+
+ /**
+ * Wait for any unused off thread compilations to finish and then
+ * cancel them.
+ */
+ void CancelScriptLoadRequests();
+
+ Document* mDocument; // [WEAK]
+ nsCOMArray<nsIScriptLoaderObserver> mObservers;
+ ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests;
+ // mLoadingAsyncRequests holds async requests while they're loading; when they
+ // have been loaded they are moved to mLoadedAsyncRequests.
+ ScriptLoadRequestList mLoadingAsyncRequests;
+ ScriptLoadRequestList mLoadedAsyncRequests;
+ ScriptLoadRequestList mDeferRequests;
+ ScriptLoadRequestList mXSLTRequests;
+ ScriptLoadRequestList mDynamicImportRequests;
+ RefPtr<ScriptLoadRequest> mParserBlockingRequest;
+
+ // List of script load request that are holding a buffer which has to be saved
+ // on the cache.
+ ScriptLoadRequestList mBytecodeEncodingQueue;
+
+ // In mRequests, the additional information here is stored by the element.
+ struct PreloadInfo {
+ RefPtr<ScriptLoadRequest> mRequest;
+ nsString mCharset;
+ };
+
+ friend void ImplCycleCollectionUnlink(ScriptLoader::PreloadInfo& aField);
+ friend void ImplCycleCollectionTraverse(
+ nsCycleCollectionTraversalCallback& aCallback,
+ ScriptLoader::PreloadInfo& aField, const char* aName, uint32_t aFlags);
+
+ struct PreloadRequestComparator {
+ bool Equals(const PreloadInfo& aPi,
+ ScriptLoadRequest* const& aRequest) const {
+ return aRequest == aPi.mRequest;
+ }
+ };
+
+ struct PreloadURIComparator {
+ bool Equals(const PreloadInfo& aPi, nsIURI* const& aURI) const;
+ };
+
+ nsTArray<PreloadInfo> mPreloads;
+
+ nsCOMPtr<nsIScriptElement> mCurrentScript;
+ nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
+ nsTArray<RefPtr<ScriptLoader>> mPendingChildLoaders;
+ uint32_t mParserBlockingBlockerCount;
+ uint32_t mBlockerCount;
+ uint32_t mNumberOfProcessors;
+ bool mEnabled;
+ bool mDeferEnabled;
+ bool mSpeculativeOMTParsingEnabled;
+ bool mDeferCheckpointReached;
+ bool mBlockingDOMContentLoaded;
+ bool mLoadEventFired;
+ bool mGiveUpEncoding;
+
+ // Module map
+ nsRefPtrHashtable<nsURIHashKey, mozilla::GenericNonExclusivePromise::Private>
+ mFetchingModules;
+ nsRefPtrHashtable<nsURIHashKey, ModuleScript> mFetchedModules;
+
+ nsCOMPtr<nsIConsoleReportCollector> mReporter;
+
+ // ShutdownObserver for off thread compilations
+ RefPtr<AsyncCompileShutdownObserver> mShutdownObserver;
+
+ // Logging
+ public:
+ static LazyLogModule gCspPRLog;
+ static LazyLogModule gScriptLoaderLog;
+};
+
+class nsAutoScriptLoaderDisabler {
+ public:
+ explicit nsAutoScriptLoaderDisabler(Document* aDoc);
+
+ ~nsAutoScriptLoaderDisabler();
+
+ bool mWasEnabled;
+ RefPtr<ScriptLoader> mLoader;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ScriptLoader_h