From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- dom/script/ScriptLoader.cpp | 4343 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4343 insertions(+) create mode 100644 dom/script/ScriptLoader.cpp (limited to 'dom/script/ScriptLoader.cpp') diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp new file mode 100644 index 0000000000..501c953e92 --- /dev/null +++ b/dom/script/ScriptLoader.cpp @@ -0,0 +1,4343 @@ +/* -*- 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/. */ + +#include "ScriptLoader.h" +#include "ScriptLoadHandler.h" +#include "ScriptLoadRequest.h" +#include "ScriptTrace.h" +#include "LoadedScript.h" +#include "ModuleLoadRequest.h" + +#include "prsystem.h" +#include "jsapi.h" +#include "jsfriendapi.h" +#include "js/Array.h" // JS::GetArrayLength +#include "js/CompilationAndEvaluation.h" +#include "js/ContextOptions.h" // JS::ContextOptionsRef +#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* +#include "js/MemoryFunctions.h" +#include "js/Modules.h" // JS::FinishDynamicModuleImport, JS::{G,S}etModuleResolveHook, JS::Get{ModulePrivate,ModuleScript,RequestedModule{s,Specifier,SourcePos}}, JS::SetModule{DynamicImport,Metadata}Hook +#include "js/OffThreadScriptCompilation.h" +#include "js/Realm.h" +#include "js/SourceText.h" +#include "js/Utility.h" +#include "xpcpublic.h" +#include "GeckoProfiler.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIContent.h" +#include "nsJSUtils.h" +#include "mozilla/dom/DocGroup.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/JSExecutionContext.h" +#include "mozilla/dom/ScriptDecoding.h" // mozilla::dom::ScriptDecoding +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/SRILogHelper.h" +#include "mozilla/dom/WindowContext.h" +#include "mozilla/net/UrlClassifierFeatureFactory.h" +#include "mozilla/Preferences.h" +#include "mozilla/StaticPrefs_dom.h" +#include "mozilla/StaticPrefs_network.h" +#include "nsAboutProtocolUtils.h" +#include "nsGkAtoms.h" +#include "nsNetUtil.h" +#include "nsGlobalWindowInner.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptContext.h" +#include "nsIPrincipal.h" +#include "nsJSPrincipals.h" +#include "nsContentPolicyUtils.h" +#include "nsIClassifiedChannel.h" +#include "nsIHttpChannel.h" +#include "nsIHttpChannelInternal.h" +#include "nsIClassOfService.h" +#include "nsICacheInfoChannel.h" +#include "nsITimedChannel.h" +#include "nsIScriptElement.h" +#include "nsISupportsPriority.h" +#include "nsIDocShell.h" +#include "nsContentUtils.h" +#include "nsUnicharUtils.h" +#include "nsError.h" +#include "nsThreadUtils.h" +#include "nsDocShellCID.h" +#include "nsIContentSecurityPolicy.h" +#include "mozilla/Logging.h" +#include "nsCRT.h" +#include "nsContentCreatorFunctions.h" +#include "nsProxyRelease.h" +#include "nsSandboxFlags.h" +#include "nsContentTypeParser.h" +#include "nsINetworkPredictor.h" +#include "nsMimeTypes.h" +#include "mozilla/ConsoleReportCollector.h" +#include "mozilla/CycleCollectedJSContext.h" +#include "mozilla/LoadInfo.h" +#include "ReferrerInfo.h" + +#include "mozilla/AsyncEventDispatcher.h" +#include "mozilla/Attributes.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Telemetry.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Unused.h" +#include "mozilla/Utf8.h" // mozilla::Utf8Unit +#include "nsIScriptError.h" +#include "nsIAsyncOutputStream.h" + +using JS::SourceText; + +using mozilla::Telemetry::LABELS_DOM_SCRIPT_PRELOAD_RESULT; + +namespace mozilla { +namespace dom { + +LazyLogModule ScriptLoader::gCspPRLog("CSP"); +LazyLogModule ScriptLoader::gScriptLoaderLog("ScriptLoader"); + +#undef LOG +#define LOG(args) \ + MOZ_LOG(ScriptLoader::gScriptLoaderLog, mozilla::LogLevel::Debug, args) + +#define LOG_ENABLED() \ + MOZ_LOG_TEST(ScriptLoader::gScriptLoaderLog, mozilla::LogLevel::Debug) + +// Alternate Data MIME type used by the ScriptLoader to register that we want to +// store bytecode without reading it. +static constexpr auto kNullMimeType = "javascript/null"_ns; + +///////////////////////////////////////////////////////////// +// AsyncCompileShutdownObserver +///////////////////////////////////////////////////////////// + +NS_IMPL_ISUPPORTS(AsyncCompileShutdownObserver, nsIObserver) + +void AsyncCompileShutdownObserver::OnShutdown() { + if (mScriptLoader) { + mScriptLoader->Shutdown(); + Unregister(); + } +} + +void AsyncCompileShutdownObserver::Unregister() { + if (mScriptLoader) { + mScriptLoader = nullptr; + nsContentUtils::UnregisterShutdownObserver(this); + } +} + +NS_IMETHODIMP +AsyncCompileShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) { + OnShutdown(); + return NS_OK; +} + +////////////////////////////////////////////////////////////// +// ScriptLoader::PreloadInfo +////////////////////////////////////////////////////////////// + +inline void ImplCycleCollectionUnlink(ScriptLoader::PreloadInfo& aField) { + ImplCycleCollectionUnlink(aField.mRequest); +} + +inline void ImplCycleCollectionTraverse( + nsCycleCollectionTraversalCallback& aCallback, + ScriptLoader::PreloadInfo& aField, const char* aName, uint32_t aFlags = 0) { + ImplCycleCollectionTraverse(aCallback, aField.mRequest, aName, aFlags); +} + +////////////////////////////////////////////////////////////// +// ScriptLoader +////////////////////////////////////////////////////////////// + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoader) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION(ScriptLoader, mNonAsyncExternalScriptInsertedRequests, + mLoadingAsyncRequests, mLoadedAsyncRequests, + mDeferRequests, mXSLTRequests, mDynamicImportRequests, + mParserBlockingRequest, mBytecodeEncodingQueue, + mPreloads, mPendingChildLoaders, mFetchedModules) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoader) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoader) + +ScriptLoader::ScriptLoader(Document* aDocument) + : mDocument(aDocument), + mParserBlockingBlockerCount(0), + mBlockerCount(0), + mNumberOfProcessors(0), + mEnabled(true), + mDeferEnabled(false), + mSpeculativeOMTParsingEnabled(false), + mDeferCheckpointReached(false), + mBlockingDOMContentLoaded(false), + mLoadEventFired(false), + mGiveUpEncoding(false), + mReporter(new ConsoleReportCollector()) { + LOG(("ScriptLoader::ScriptLoader %p", this)); + EnsureModuleHooksInitialized(); + + mSpeculativeOMTParsingEnabled = StaticPrefs:: + dom_script_loader_external_scripts_speculative_omt_parse_enabled(); + + mShutdownObserver = new AsyncCompileShutdownObserver(this); + nsContentUtils::RegisterShutdownObserver(mShutdownObserver); +} + +ScriptLoader::~ScriptLoader() { + LOG(("ScriptLoader::~ScriptLoader %p", this)); + + mObservers.Clear(); + + if (mParserBlockingRequest) { + mParserBlockingRequest->FireScriptAvailable(NS_ERROR_ABORT); + } + + for (ScriptLoadRequest* req = mXSLTRequests.getFirst(); req; + req = req->getNext()) { + req->FireScriptAvailable(NS_ERROR_ABORT); + } + + for (ScriptLoadRequest* req = mDeferRequests.getFirst(); req; + req = req->getNext()) { + req->FireScriptAvailable(NS_ERROR_ABORT); + } + + for (ScriptLoadRequest* req = mLoadingAsyncRequests.getFirst(); req; + req = req->getNext()) { + req->FireScriptAvailable(NS_ERROR_ABORT); + } + + for (ScriptLoadRequest* req = mLoadedAsyncRequests.getFirst(); req; + req = req->getNext()) { + req->FireScriptAvailable(NS_ERROR_ABORT); + } + + for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req; + req = req->getNext()) { + FinishDynamicImportAndReject(req->AsModuleRequest(), NS_ERROR_ABORT); + } + + for (ScriptLoadRequest* req = + mNonAsyncExternalScriptInsertedRequests.getFirst(); + req; req = req->getNext()) { + req->FireScriptAvailable(NS_ERROR_ABORT); + } + + // Unblock the kids, in case any of them moved to a different document + // subtree in the meantime and therefore aren't actually going away. + for (uint32_t j = 0; j < mPendingChildLoaders.Length(); ++j) { + mPendingChildLoaders[j]->RemoveParserBlockingScriptExecutionBlocker(); + } + + for (size_t i = 0; i < mPreloads.Length(); i++) { + AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::NotUsed); + } + + if (mShutdownObserver) { + mShutdownObserver->Unregister(); + mShutdownObserver = nullptr; + } +} + +// Collect telemtry data about the cache information, and the kind of source +// which are being loaded, and where it is being loaded from. +static void CollectScriptTelemetry(ScriptLoadRequest* aRequest) { + using namespace mozilla::Telemetry; + + // Skip this function if we are not running telemetry. + if (!CanRecordExtended()) { + return; + } + + // Report the script kind. + if (aRequest->IsModuleRequest()) { + AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ModuleScript); + } else { + AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ClassicScript); + } + + // Report the type of source. This is used to monitor the status of the + // JavaScript Start-up Bytecode Cache, with the expectation of an almost zero + // source-fallback and alternate-data being roughtly equal to source loads. + if (aRequest->IsLoadingSource()) { + if (aRequest->mIsInline) { + AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline); + } else if (aRequest->IsTextSource()) { + AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::SourceFallback); + } + // TODO: Add telemetry for BinAST encoded source. + } else { + MOZ_ASSERT(aRequest->IsLoading()); + if (aRequest->IsTextSource()) { + AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Source); + } else if (aRequest->IsBytecode()) { + AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::AltData); + } + // TODO: Add telemetry for BinAST encoded source. + } +} + +// Helper method for checking if the script element is an event-handler +// This means that it has both a for-attribute and a event-attribute. +// Also, if the for-attribute has a value that matches "\s*window\s*", +// and the event-attribute matches "\s*onload([ \(].*)?" then it isn't an +// eventhandler. (both matches are case insensitive). +// This is how IE seems to filter out a window's onload handler from a +//