mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	Add nsMainThreadPtrHandle to delegate WorkletFetchHandler. Add WorkletLoadContext to wrap nsMainThreadPtrHandle. Depends on D166541 Differential Revision: https://phabricator.services.mozilla.com/D166542
		
			
				
	
	
		
			282 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
	
		
			8.3 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/WorkerLoadContext.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)
 | 
						|
 | 
						|
ScriptFetchOptions::ScriptFetchOptions(
 | 
						|
    mozilla::CORSMode aCORSMode, mozilla::dom::ReferrerPolicy aReferrerPolicy,
 | 
						|
    nsIPrincipal* aTriggeringPrincipal, mozilla::dom::Element* aElement)
 | 
						|
    : mCORSMode(aCORSMode),
 | 
						|
      mReferrerPolicy(aReferrerPolicy),
 | 
						|
      mTriggeringPrincipal(aTriggeringPrincipal),
 | 
						|
      mElement(aElement) {}
 | 
						|
 | 
						|
ScriptFetchOptions::~ScriptFetchOptions() = default;
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////
 | 
						|
// ScriptLoadRequest
 | 
						|
//////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadRequest)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsISupports)
 | 
						|
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() { DropJSObjects(this); }
 | 
						|
 | 
						|
void ScriptLoadRequest::SetReady() {
 | 
						|
  MOZ_ASSERT(!IsReadyToRun());
 | 
						|
  mState = State::Ready;
 | 
						|
}
 | 
						|
 | 
						|
void ScriptLoadRequest::Cancel() {
 | 
						|
  mState = State::Canceled;
 | 
						|
  if (HasScriptLoadContext()) {
 | 
						|
    GetScriptLoadContext()->MaybeCancelOffThreadScript();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ScriptLoadRequest::DropBytecodeCacheReferences() {
 | 
						|
  mCacheInfo = nullptr;
 | 
						|
  DropJSObjects(this);
 | 
						|
}
 | 
						|
 | 
						|
bool ScriptLoadRequest::HasScriptLoadContext() const {
 | 
						|
  return HasLoadContext() && mLoadContext->IsWindowContext();
 | 
						|
}
 | 
						|
 | 
						|
bool ScriptLoadRequest::HasWorkerLoadContext() const {
 | 
						|
  return HasLoadContext() && mLoadContext->IsWorkerContext();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::dom::ScriptLoadContext* ScriptLoadRequest::GetScriptLoadContext() {
 | 
						|
  MOZ_ASSERT(mLoadContext);
 | 
						|
  return mLoadContext->AsWindowContext();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::loader::ComponentLoadContext*
 | 
						|
ScriptLoadRequest::GetComponentLoadContext() {
 | 
						|
  MOZ_ASSERT(mLoadContext);
 | 
						|
  return mLoadContext->AsComponentContext();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::dom::WorkerLoadContext* ScriptLoadRequest::GetWorkerLoadContext() {
 | 
						|
  MOZ_ASSERT(mLoadContext);
 | 
						|
  return mLoadContext->AsWorkerContext();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::dom::WorkletLoadContext* ScriptLoadRequest::GetWorkletLoadContext() {
 | 
						|
  MOZ_ASSERT(mLoadContext);
 | 
						|
  return mLoadContext->AsWorkletContext();
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
bool ScriptLoadRequest::IsUTF8ParsingEnabled() {
 | 
						|
  if (HasLoadContext()) {
 | 
						|
    if (mLoadContext->IsWindowContext()) {
 | 
						|
      return mozilla::StaticPrefs::
 | 
						|
          dom_script_loader_external_scripts_utf8_parsing_enabled();
 | 
						|
    }
 | 
						|
    if (mLoadContext->IsWorkerContext()) {
 | 
						|
      return mozilla::StaticPrefs::
 | 
						|
          dom_worker_script_loader_utf8_parsing_enabled();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
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 (HasScriptLoadContext() && 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
 |