forked from mirrors/gecko-dev
		
	 f8267f1612
			
		
	
	
		f8267f1612
		
	
	
	
	
		
			
			We should check for previous cancellation on all path where a module load request's state can be changed by an asynchronous action. Also add assertions about the expected previous state where possible. Differential Revision: https://phabricator.services.mozilla.com/D168233
		
			
				
	
	
		
			238 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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 "ModuleLoadRequest.h"
 | |
| 
 | |
| #include "mozilla/HoldDropJSObjects.h"
 | |
| #include "mozilla/dom/ScriptLoadContext.h"
 | |
| 
 | |
| #include "LoadedScript.h"
 | |
| #include "LoadContextBase.h"
 | |
| #include "ModuleLoaderBase.h"
 | |
| 
 | |
| namespace JS::loader {
 | |
| 
 | |
| #undef LOG
 | |
| #define LOG(args)                                                           \
 | |
|   MOZ_LOG(ModuleLoaderBase::gModuleLoaderBaseLog, mozilla::LogLevel::Debug, \
 | |
|           args)
 | |
| 
 | |
| NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(ModuleLoadRequest,
 | |
|                                                ScriptLoadRequest)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleLoadRequest)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest,
 | |
|                                                 ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader, mModuleScript, mImports, mRootModule)
 | |
|   tmp->ClearDynamicImport();
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleLoadRequest,
 | |
|                                                   ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader, mModuleScript, mImports,
 | |
|                                     mRootModule)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleLoadRequest,
 | |
|                                                ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicReferencingPrivate)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicSpecifier)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicPromise)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_END
 | |
| 
 | |
| /* static */
 | |
| VisitedURLSet* ModuleLoadRequest::NewVisitedSetForTopLevelImport(nsIURI* aURI) {
 | |
|   auto set = new VisitedURLSet();
 | |
|   set->PutEntry(aURI);
 | |
|   return set;
 | |
| }
 | |
| 
 | |
| ModuleLoadRequest::ModuleLoadRequest(
 | |
|     nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
 | |
|     const mozilla::dom::SRIMetadata& aIntegrity, nsIURI* aReferrer,
 | |
|     LoadContextBase* aContext, bool aIsTopLevel, bool aIsDynamicImport,
 | |
|     ModuleLoaderBase* aLoader, VisitedURLSet* aVisitedSet,
 | |
|     ModuleLoadRequest* aRootModule)
 | |
|     : ScriptLoadRequest(ScriptKind::eModule, aURI, aFetchOptions, aIntegrity,
 | |
|                         aReferrer, aContext),
 | |
|       mIsTopLevel(aIsTopLevel),
 | |
|       mIsDynamicImport(aIsDynamicImport),
 | |
|       mLoader(aLoader),
 | |
|       mRootModule(aRootModule),
 | |
|       mVisitedSet(aVisitedSet) {
 | |
|   MOZ_ASSERT(mLoader);
 | |
| }
 | |
| 
 | |
| nsIGlobalObject* ModuleLoadRequest::GetGlobalObject() {
 | |
|   return mLoader->GetGlobalObject();
 | |
| }
 | |
| 
 | |
| bool ModuleLoadRequest::IsErrored() const {
 | |
|   return !mModuleScript || mModuleScript->HasParseError();
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::Cancel() {
 | |
|   if (IsCanceled()) {
 | |
|     AssertAllImportsCancelled();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ScriptLoadRequest::Cancel();
 | |
|   mModuleScript = nullptr;
 | |
|   CancelImports();
 | |
|   mReady.RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__);
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::SetReady() {
 | |
|   // Mark a module as ready to execute. This means that this module and all it
 | |
|   // dependencies have had their source loaded, parsed as a module and the
 | |
|   // modules instantiated.
 | |
|   //
 | |
|   // The mReady promise is used to ensure that when all dependencies of a module
 | |
|   // have become ready, DependenciesLoaded is called on that module
 | |
|   // request. This is set up in StartFetchingModuleDependencies.
 | |
| 
 | |
|   AssertAllImportsReady();
 | |
| 
 | |
|   ScriptLoadRequest::SetReady();
 | |
|   mReady.ResolveIfExists(true, __func__);
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::ModuleLoaded() {
 | |
|   // A module that was found to be marked as fetching in the module map has now
 | |
|   // been loaded.
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module loaded", this));
 | |
| 
 | |
|   if (IsCanceled()) {
 | |
|     AssertAllImportsCancelled();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(IsFetching());
 | |
| 
 | |
|   mModuleScript = mLoader->GetFetchedModule(mURI);
 | |
|   if (IsErrored()) {
 | |
|     ModuleErrored();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   mLoader->StartFetchingModuleDependencies(this);
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::LoadFailed() {
 | |
|   // We failed to load the source text or an error occurred unrelated to the
 | |
|   // content of the module (e.g. OOM).
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module load failed", this));
 | |
| 
 | |
|   if (IsCanceled()) {
 | |
|     AssertAllImportsCancelled();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(IsFetching());
 | |
|   MOZ_ASSERT(!mModuleScript);
 | |
| 
 | |
|   Cancel();
 | |
|   LoadFinished();
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::ModuleErrored() {
 | |
|   // Parse error, failure to resolve imported modules or error loading import.
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module errored", this));
 | |
| 
 | |
|   if (IsCanceled()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(IsFetching() || IsLoadingImports());
 | |
| 
 | |
|   CheckModuleDependenciesLoaded();
 | |
|   MOZ_ASSERT(IsErrored());
 | |
| 
 | |
|   CancelImports();
 | |
|   SetReady();
 | |
|   LoadFinished();
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::DependenciesLoaded() {
 | |
|   // The module and all of its dependencies have been successfully fetched and
 | |
|   // compiled.
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module dependencies loaded", this));
 | |
| 
 | |
|   if (IsCanceled()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(IsLoadingImports());
 | |
|   MOZ_ASSERT(!IsErrored());
 | |
| 
 | |
|   CheckModuleDependenciesLoaded();
 | |
|   SetReady();
 | |
|   LoadFinished();
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::CheckModuleDependenciesLoaded() {
 | |
|   LOG(("ScriptLoadRequest (%p): Check dependencies loaded", this));
 | |
| 
 | |
|   if (!mModuleScript || mModuleScript->HasParseError()) {
 | |
|     return;
 | |
|   }
 | |
|   for (const auto& childRequest : mImports) {
 | |
|     ModuleScript* childScript = childRequest->mModuleScript;
 | |
|     if (!childScript) {
 | |
|       mModuleScript = nullptr;
 | |
|       LOG(("ScriptLoadRequest (%p):   %p failed (load error)", this,
 | |
|            childRequest.get()));
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p):   all ok", this));
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::CancelImports() {
 | |
|   for (size_t i = 0; i < mImports.Length(); i++) {
 | |
|     mImports[i]->Cancel();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::LoadFinished() {
 | |
|   RefPtr<ModuleLoadRequest> request(this);
 | |
|   if (IsTopLevel() && IsDynamicImport()) {
 | |
|     mLoader->RemoveDynamicImport(request);
 | |
|   }
 | |
| 
 | |
|   mLoader->OnModuleLoadComplete(request);
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::ClearDynamicImport() {
 | |
|   mDynamicReferencingPrivate = JS::UndefinedValue();
 | |
|   mDynamicSpecifier = nullptr;
 | |
|   mDynamicPromise = nullptr;
 | |
| }
 | |
| 
 | |
| inline void ModuleLoadRequest::AssertAllImportsReady() const {
 | |
| #ifdef DEBUG
 | |
|   for (const auto& request : mImports) {
 | |
|     MOZ_ASSERT(request->IsReadyToRun());
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| inline void ModuleLoadRequest::AssertAllImportsCancelled() const {
 | |
| #ifdef DEBUG
 | |
|   for (const auto& request : mImports) {
 | |
|     MOZ_ASSERT(request->IsCanceled());
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| }  // namespace JS::loader
 |