forked from mirrors/gecko-dev
		
	 a996a1aca2
			
		
	
	
		a996a1aca2
		
	
	
	
	
		
			
			Depends on D143068 Differential Revision: https://phabricator.services.mozilla.com/D143037
		
			
				
	
	
		
			253 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
	
		
			7.4 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 "ScriptLoadRequest.h"
 | |
| #include "GeckoProfiler.h"
 | |
| 
 | |
| #include "mozilla/dom/Document.h"
 | |
| #include "mozilla/dom/ScriptLoadContext.h"
 | |
| #include "mozilla/dom/ScriptSettings.h"
 | |
| #include "mozilla/HoldDropJSObjects.h"
 | |
| #include "mozilla/StaticPrefs_dom.h"
 | |
| #include "mozilla/Unused.h"
 | |
| #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
 | |
| 
 | |
| #include "js/OffThreadScriptCompilation.h"
 | |
| #include "js/SourceText.h"
 | |
| 
 | |
| #include "ModuleLoadRequest.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsICacheInfoChannel.h"
 | |
| #include "nsIClassOfService.h"
 | |
| #include "nsISupportsPriority.h"
 | |
| 
 | |
| using JS::SourceText;
 | |
| 
 | |
| namespace JS::loader {
 | |
| 
 | |
| //////////////////////////////////////////////////////////////
 | |
| // ScriptFetchOptions
 | |
| //////////////////////////////////////////////////////////////
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions, mTriggeringPrincipal, mElement)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ScriptFetchOptions, AddRef)
 | |
| NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ScriptFetchOptions, Release)
 | |
| 
 | |
| ScriptFetchOptions::ScriptFetchOptions(
 | |
|     mozilla::CORSMode aCORSMode, mozilla::dom::ReferrerPolicy aReferrerPolicy,
 | |
|     nsIPrincipal* aTriggeringPrincipal, mozilla::dom::Element* aElement)
 | |
|     : mCORSMode(aCORSMode),
 | |
|       mReferrerPolicy(aReferrerPolicy),
 | |
|       mTriggeringPrincipal(aTriggeringPrincipal),
 | |
|       mElement(aElement) {
 | |
|   MOZ_ASSERT(mTriggeringPrincipal);
 | |
| }
 | |
| 
 | |
| ScriptFetchOptions::~ScriptFetchOptions() = default;
 | |
| 
 | |
| //////////////////////////////////////////////////////////////
 | |
| // ScriptLoadRequest
 | |
| //////////////////////////////////////////////////////////////
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadRequest)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoadRequest)
 | |
| NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions, mCacheInfo, mLoadContext)
 | |
|   tmp->mScriptForBytecodeEncoding = nullptr;
 | |
|   tmp->DropBytecodeCacheReferences();
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions, mCacheInfo, mLoadContext)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptForBytecodeEncoding)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_END
 | |
| 
 | |
| ScriptLoadRequest::ScriptLoadRequest(ScriptKind aKind, nsIURI* aURI,
 | |
|                                      ScriptFetchOptions* aFetchOptions,
 | |
|                                      const SRIMetadata& aIntegrity,
 | |
|                                      nsIURI* aReferrer,
 | |
|                                      LoadContextBase* aContext)
 | |
|     : mKind(aKind),
 | |
|       mState(State::Fetching),
 | |
|       mFetchSourceOnly(false),
 | |
|       mDataType(DataType::eUnknown),
 | |
|       mFetchOptions(aFetchOptions),
 | |
|       mIntegrity(aIntegrity),
 | |
|       mReferrer(aReferrer),
 | |
|       mScriptTextLength(0),
 | |
|       mScriptBytecode(),
 | |
|       mBytecodeOffset(0),
 | |
|       mURI(aURI),
 | |
|       mLoadContext(aContext) {
 | |
|   MOZ_ASSERT(mFetchOptions);
 | |
|   if (mLoadContext) {
 | |
|     mLoadContext->SetRequest(this);
 | |
|   }
 | |
| }
 | |
| 
 | |
| ScriptLoadRequest::~ScriptLoadRequest() {
 | |
|   if (IsMarkedForBytecodeEncoding()) {
 | |
|     DropBytecodeCacheReferences();
 | |
|   }
 | |
|   mLoadContext = nullptr;
 | |
|   DropJSObjects(this);
 | |
| }
 | |
| 
 | |
| void ScriptLoadRequest::SetReady() {
 | |
|   MOZ_ASSERT(!IsReadyToRun());
 | |
|   mState = State::Ready;
 | |
| }
 | |
| 
 | |
| void ScriptLoadRequest::Cancel() {
 | |
|   mState = State::Canceled;
 | |
|   if (HasLoadContext()) {
 | |
|     GetScriptLoadContext()->MaybeCancelOffThreadScript();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ScriptLoadRequest::DropBytecodeCacheReferences() {
 | |
|   mCacheInfo = nullptr;
 | |
|   DropJSObjects(this);
 | |
| }
 | |
| 
 | |
| mozilla::dom::ScriptLoadContext* ScriptLoadRequest::GetScriptLoadContext() {
 | |
|   MOZ_ASSERT(mLoadContext);
 | |
|   return mLoadContext->AsWindowContext();
 | |
| }
 | |
| 
 | |
| ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() {
 | |
|   MOZ_ASSERT(IsModuleRequest());
 | |
|   return static_cast<ModuleLoadRequest*>(this);
 | |
| }
 | |
| 
 | |
| const ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() const {
 | |
|   MOZ_ASSERT(IsModuleRequest());
 | |
|   return static_cast<const ModuleLoadRequest*>(this);
 | |
| }
 | |
| 
 | |
| void ScriptLoadRequest::SetBytecode() {
 | |
|   MOZ_ASSERT(IsUnknownDataType());
 | |
|   mDataType = DataType::eBytecode;
 | |
| }
 | |
| 
 | |
| void ScriptLoadRequest::ClearScriptSource() {
 | |
|   if (IsTextSource()) {
 | |
|     ClearScriptText();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ScriptLoadRequest::MarkForBytecodeEncoding(JSScript* aScript) {
 | |
|   MOZ_ASSERT(!IsModuleRequest());
 | |
|   MOZ_ASSERT(!IsMarkedForBytecodeEncoding());
 | |
|   mScriptForBytecodeEncoding = aScript;
 | |
|   HoldJSObjects(this);
 | |
| }
 | |
| 
 | |
| bool ScriptLoadRequest::IsMarkedForBytecodeEncoding() const {
 | |
|   if (IsModuleRequest()) {
 | |
|     return AsModuleRequest()->IsModuleMarkedForBytecodeEncoding();
 | |
|   }
 | |
| 
 | |
|   return !!mScriptForBytecodeEncoding;
 | |
| }
 | |
| 
 | |
| nsresult ScriptLoadRequest::GetScriptSource(JSContext* aCx,
 | |
|                                             MaybeSourceText* aMaybeSource) {
 | |
|   // If there's no script text, we try to get it from the element
 | |
|   if (HasLoadContext() && GetScriptLoadContext()->mIsInline) {
 | |
|     nsAutoString inlineData;
 | |
|     GetScriptLoadContext()->GetScriptElement()->GetScriptText(inlineData);
 | |
| 
 | |
|     size_t nbytes = inlineData.Length() * sizeof(char16_t);
 | |
|     JS::UniqueTwoByteChars chars(
 | |
|         static_cast<char16_t*>(JS_malloc(aCx, nbytes)));
 | |
|     if (!chars) {
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
| 
 | |
|     memcpy(chars.get(), inlineData.get(), nbytes);
 | |
| 
 | |
|     SourceText<char16_t> srcBuf;
 | |
|     if (!srcBuf.init(aCx, std::move(chars), inlineData.Length())) {
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
| 
 | |
|     aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   size_t length = ScriptTextLength();
 | |
|   if (IsUTF16Text()) {
 | |
|     JS::UniqueTwoByteChars chars;
 | |
|     chars.reset(ScriptText<char16_t>().extractOrCopyRawBuffer());
 | |
|     if (!chars) {
 | |
|       JS_ReportOutOfMemory(aCx);
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
| 
 | |
|     SourceText<char16_t> srcBuf;
 | |
|     if (!srcBuf.init(aCx, std::move(chars), length)) {
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
|     }
 | |
| 
 | |
|     aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(IsUTF8Text());
 | |
|   UniquePtr<Utf8Unit[], JS::FreePolicy> chars;
 | |
|   chars.reset(ScriptText<Utf8Unit>().extractOrCopyRawBuffer());
 | |
|   if (!chars) {
 | |
|     JS_ReportOutOfMemory(aCx);
 | |
|     return NS_ERROR_OUT_OF_MEMORY;
 | |
|   }
 | |
| 
 | |
|   SourceText<Utf8Unit> srcBuf;
 | |
|   if (!srcBuf.init(aCx, std::move(chars), length)) {
 | |
|     return NS_ERROR_OUT_OF_MEMORY;
 | |
|   }
 | |
| 
 | |
|   aMaybeSource->construct<SourceText<Utf8Unit>>(std::move(srcBuf));
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////
 | |
| // ScriptLoadRequestList
 | |
| //////////////////////////////////////////////////////////////
 | |
| 
 | |
| ScriptLoadRequestList::~ScriptLoadRequestList() { CancelRequestsAndClear(); }
 | |
| 
 | |
| void ScriptLoadRequestList::CancelRequestsAndClear() {
 | |
|   while (!isEmpty()) {
 | |
|     RefPtr<ScriptLoadRequest> first = StealFirst();
 | |
|     first->Cancel();
 | |
|     // And just let it go out of scope and die.
 | |
|   }
 | |
| }
 | |
| 
 | |
| #ifdef DEBUG
 | |
| bool ScriptLoadRequestList::Contains(ScriptLoadRequest* aElem) const {
 | |
|   for (const ScriptLoadRequest* req = getFirst(); req; req = req->getNext()) {
 | |
|     if (req == aElem) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| #endif  // DEBUG
 | |
| 
 | |
| }  // namespace JS::loader
 |