mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-27 03:09:37 +00:00
import from UXP: Issue #1603 - Part 2: Split some classes out of ScriptLoader.cpp (c04b682a)
This commit is contained in:
+4
-482
@@ -4,11 +4,10 @@
|
||||
* 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/. */
|
||||
|
||||
/*
|
||||
* A class that handles loading and evaluation of <script> elements.
|
||||
*/
|
||||
|
||||
#include "ScriptLoader.h"
|
||||
#include "ScriptLoadHandler.h"
|
||||
#include "ModuleLoadRequest.h"
|
||||
#include "ModuleScript.h"
|
||||
|
||||
#include "prsystem.h"
|
||||
#include "jsapi.h"
|
||||
@@ -135,96 +134,6 @@ ScriptLoadRequest::MaybeCancelOffThreadScript()
|
||||
mOffThreadToken = nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ModuleLoadRequest
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// A load request for a module, created for every top level module script and
|
||||
// every module import. Load request can share a ModuleScript if there are
|
||||
// multiple imports of the same module.
|
||||
|
||||
class ModuleLoadRequest final : public ScriptLoadRequest
|
||||
{
|
||||
~ModuleLoadRequest() {}
|
||||
|
||||
ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete;
|
||||
ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
|
||||
|
||||
ModuleLoadRequest(nsIScriptElement* aElement,
|
||||
uint32_t aVersion,
|
||||
CORSMode aCORSMode,
|
||||
const SRIMetadata& aIntegrity,
|
||||
ScriptLoader* aLoader);
|
||||
|
||||
bool IsTopLevel() const {
|
||||
return mIsTopLevel;
|
||||
}
|
||||
|
||||
void SetReady() override;
|
||||
void Cancel() override;
|
||||
|
||||
void ModuleLoaded();
|
||||
void DependenciesLoaded();
|
||||
void LoadFailed();
|
||||
|
||||
// Is this a request for a top level module script or an import?
|
||||
bool mIsTopLevel;
|
||||
|
||||
// The base URL used for resolving relative module imports.
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
|
||||
// Pointer to the script loader, used to trigger actions when the module load
|
||||
// finishes.
|
||||
RefPtr<ScriptLoader> mLoader;
|
||||
|
||||
// The importing module, or nullptr for top level module scripts. Used to
|
||||
// implement the ancestor list checked when fetching module dependencies.
|
||||
RefPtr<ModuleLoadRequest> mParent;
|
||||
|
||||
// Set to a module script object after a successful load or nullptr on
|
||||
// failure.
|
||||
RefPtr<ModuleScript> mModuleScript;
|
||||
|
||||
// A promise that is completed on successful load of this module and all of
|
||||
// its dependencies, indicating that the module is ready for instantiation and
|
||||
// evaluation.
|
||||
MozPromiseHolder<GenericPromise> mReady;
|
||||
|
||||
// Array of imported modules.
|
||||
nsTArray<RefPtr<ModuleLoadRequest>> mImports;
|
||||
};
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest)
|
||||
NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest,
|
||||
mBaseURL,
|
||||
mLoader,
|
||||
mParent,
|
||||
mModuleScript,
|
||||
mImports)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
|
||||
NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
|
||||
|
||||
ModuleLoadRequest::ModuleLoadRequest(nsIScriptElement* aElement,
|
||||
uint32_t aVersion,
|
||||
CORSMode aCORSMode,
|
||||
const SRIMetadata &aIntegrity,
|
||||
ScriptLoader* aLoader)
|
||||
: ScriptLoadRequest(ScriptKind::Module,
|
||||
aElement,
|
||||
aVersion,
|
||||
aCORSMode,
|
||||
aIntegrity),
|
||||
mIsTopLevel(true),
|
||||
mLoader(aLoader)
|
||||
{}
|
||||
|
||||
inline ModuleLoadRequest*
|
||||
ScriptLoadRequest::AsModuleRequest()
|
||||
{
|
||||
@@ -232,194 +141,6 @@ ScriptLoadRequest::AsModuleRequest()
|
||||
return static_cast<ModuleLoadRequest*>(this);
|
||||
}
|
||||
|
||||
void ModuleLoadRequest::Cancel()
|
||||
{
|
||||
ScriptLoadRequest::Cancel();
|
||||
mModuleScript = nullptr;
|
||||
mProgress = ScriptLoadRequest::Progress::Ready;
|
||||
for (size_t i = 0; i < mImports.Length(); i++) {
|
||||
mImports[i]->Cancel();
|
||||
}
|
||||
mReady.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
ModuleLoadRequest::SetReady()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i < mImports.Length(); i++) {
|
||||
MOZ_ASSERT(mImports[i]->IsReadyToRun());
|
||||
}
|
||||
#endif
|
||||
|
||||
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.
|
||||
|
||||
mModuleScript = mLoader->GetFetchedModule(mURI);
|
||||
mLoader->StartFetchingModuleDependencies(this);
|
||||
}
|
||||
|
||||
void
|
||||
ModuleLoadRequest::DependenciesLoaded()
|
||||
{
|
||||
// The module and all of its dependencies have been successfully fetched and
|
||||
// compiled.
|
||||
|
||||
if (!mLoader->InstantiateModuleTree(this)) {
|
||||
LoadFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
SetReady();
|
||||
mLoader->ProcessLoadedModuleTree(this);
|
||||
mLoader = nullptr;
|
||||
mParent = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ModuleLoadRequest::LoadFailed()
|
||||
{
|
||||
Cancel();
|
||||
mLoader->ProcessLoadedModuleTree(this);
|
||||
mLoader = nullptr;
|
||||
mParent = nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ModuleScript
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// A single module script. May be used to satisfy multiple load requests.
|
||||
|
||||
class ModuleScript final : public nsISupports
|
||||
{
|
||||
enum InstantiationState {
|
||||
Uninstantiated,
|
||||
Instantiated,
|
||||
Errored
|
||||
};
|
||||
|
||||
RefPtr<ScriptLoader> mLoader;
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
JS::Heap<JSObject*> mModuleRecord;
|
||||
JS::Heap<JS::Value> mException;
|
||||
InstantiationState mInstantiationState;
|
||||
|
||||
~ModuleScript();
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
|
||||
|
||||
ModuleScript(ScriptLoader* aLoader,
|
||||
nsIURI* aBaseURL,
|
||||
JS::Handle<JSObject*> aModuleRecord);
|
||||
|
||||
ScriptLoader* Loader() const { return mLoader; }
|
||||
JSObject* ModuleRecord() const { return mModuleRecord; }
|
||||
JS::Value Exception() const { return mException; }
|
||||
nsIURI* BaseURL() const { return mBaseURL; }
|
||||
|
||||
void SetInstantiationResult(JS::Handle<JS::Value> aMaybeException);
|
||||
bool IsUninstantiated() const {
|
||||
return mInstantiationState == Uninstantiated;
|
||||
}
|
||||
bool IsInstantiated() const {
|
||||
return mInstantiationState == Instantiated;
|
||||
}
|
||||
bool InstantiationFailed() const {
|
||||
return mInstantiationState == Errored;
|
||||
}
|
||||
|
||||
void UnlinkModuleRecord();
|
||||
};
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
||||
tmp->UnlinkModuleRecord();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mException)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
|
||||
|
||||
ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL,
|
||||
JS::Handle<JSObject*> aModuleRecord)
|
||||
: mLoader(aLoader),
|
||||
mBaseURL(aBaseURL),
|
||||
mModuleRecord(aModuleRecord),
|
||||
mInstantiationState(Uninstantiated)
|
||||
{
|
||||
MOZ_ASSERT(mLoader);
|
||||
MOZ_ASSERT(mBaseURL);
|
||||
MOZ_ASSERT(mModuleRecord);
|
||||
MOZ_ASSERT(mException.isUndefined());
|
||||
|
||||
// Make module's host defined field point to this module script object.
|
||||
// This is cleared in the UnlinkModuleRecord().
|
||||
JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this));
|
||||
HoldJSObjects(this);
|
||||
}
|
||||
|
||||
void
|
||||
ModuleScript::UnlinkModuleRecord()
|
||||
{
|
||||
// Remove module's back reference to this object request if present.
|
||||
if (mModuleRecord) {
|
||||
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
|
||||
this);
|
||||
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
|
||||
}
|
||||
mModuleRecord = nullptr;
|
||||
mException.setUndefined();
|
||||
}
|
||||
|
||||
ModuleScript::~ModuleScript()
|
||||
{
|
||||
if (mModuleRecord) {
|
||||
// The object may be destroyed without being unlinked first.
|
||||
UnlinkModuleRecord();
|
||||
}
|
||||
DropJSObjects(this);
|
||||
}
|
||||
|
||||
void
|
||||
ModuleScript::SetInstantiationResult(JS::Handle<JS::Value> aMaybeException)
|
||||
{
|
||||
MOZ_ASSERT(mInstantiationState == Uninstantiated);
|
||||
MOZ_ASSERT(mModuleRecord);
|
||||
MOZ_ASSERT(mException.isUndefined());
|
||||
|
||||
if (aMaybeException.isUndefined()) {
|
||||
mInstantiationState = Instantiated;
|
||||
} else {
|
||||
mModuleRecord = nullptr;
|
||||
mException = aMaybeException;
|
||||
mInstantiationState = Errored;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// ScriptLoadRequestList
|
||||
@@ -2886,204 +2607,5 @@ ScriptLoader::MaybeRemovedDeferRequests()
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ScriptLoadHandler
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
ScriptLoadHandler::ScriptLoadHandler(ScriptLoader *aScriptLoader,
|
||||
ScriptLoadRequest *aRequest,
|
||||
mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier)
|
||||
: mScriptLoader(aScriptLoader),
|
||||
mRequest(aRequest),
|
||||
mSRIDataVerifier(aSRIDataVerifier),
|
||||
mSRIStatus(NS_OK),
|
||||
mDecoder(),
|
||||
mBuffer()
|
||||
{}
|
||||
|
||||
ScriptLoadHandler::~ScriptLoadHandler()
|
||||
{}
|
||||
|
||||
NS_IMPL_ISUPPORTS(ScriptLoadHandler, nsIIncrementalStreamLoaderObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
uint32_t aDataLength,
|
||||
const uint8_t* aData,
|
||||
uint32_t *aConsumedLength)
|
||||
{
|
||||
if (mRequest->IsCanceled()) {
|
||||
// If request cancelled, ignore any incoming data.
|
||||
*aConsumedLength = aDataLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!EnsureDecoder(aLoader, aData, aDataLength,
|
||||
/* aEndOfStream = */ false)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Below we will/shall consume entire data chunk.
|
||||
*aConsumedLength = aDataLength;
|
||||
|
||||
// Decoder has already been initialized. -- trying to decode all loaded bytes.
|
||||
nsresult rv = TryDecodeRawData(aData, aDataLength,
|
||||
/* aEndOfStream = */ false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If SRI is required for this load, appending new bytes to the hash.
|
||||
if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) {
|
||||
mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ScriptLoadHandler::TryDecodeRawData(const uint8_t* aData,
|
||||
uint32_t aDataLength,
|
||||
bool aEndOfStream)
|
||||
{
|
||||
int32_t srcLen = aDataLength;
|
||||
const char* src = reinterpret_cast<const char *>(aData);
|
||||
int32_t dstLen;
|
||||
nsresult rv =
|
||||
mDecoder->GetMaxLength(src, srcLen, &dstLen);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t haveRead = mBuffer.length();
|
||||
|
||||
CheckedInt<uint32_t> capacity = haveRead;
|
||||
capacity += dstLen;
|
||||
|
||||
if (!capacity.isValid() || !mBuffer.reserve(capacity.value())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = mDecoder->Convert(src,
|
||||
&srcLen,
|
||||
mBuffer.begin() + haveRead,
|
||||
&dstLen);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
haveRead += dstLen;
|
||||
MOZ_ASSERT(haveRead <= capacity.value(), "mDecoder produced more data than expected");
|
||||
MOZ_ALWAYS_TRUE(mBuffer.resizeUninitialized(haveRead));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptLoadHandler::EnsureDecoder(nsIIncrementalStreamLoader *aLoader,
|
||||
const uint8_t* aData,
|
||||
uint32_t aDataLength,
|
||||
bool aEndOfStream)
|
||||
{
|
||||
// Check if decoder has already been created.
|
||||
if (mDecoder) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoCString charset;
|
||||
|
||||
// JavaScript modules are always UTF-8.
|
||||
if (mRequest->IsModuleRequest()) {
|
||||
charset = "UTF-8";
|
||||
mDecoder = EncodingUtils::DecoderForEncoding(charset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine if BOM check should be done. This occurs either
|
||||
// if end-of-stream has been reached, or at least 3 bytes have
|
||||
// been read from input.
|
||||
if (!aEndOfStream && (aDataLength < 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do BOM detection.
|
||||
if (nsContentUtils::CheckForBOM(aData, aDataLength, charset)) {
|
||||
mDecoder = EncodingUtils::DecoderForEncoding(charset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// BOM detection failed, check content stream for charset.
|
||||
nsCOMPtr<nsIRequest> req;
|
||||
nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
|
||||
NS_ASSERTION(req, "StreamLoader's request went away prematurely");
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
|
||||
|
||||
if (channel &&
|
||||
NS_SUCCEEDED(channel->GetContentCharset(charset)) &&
|
||||
EncodingUtils::FindEncodingForLabel(charset, charset)) {
|
||||
mDecoder = EncodingUtils::DecoderForEncoding(charset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the hint charset from the script element or preload
|
||||
// request.
|
||||
nsAutoString hintCharset;
|
||||
if (!mRequest->IsPreload()) {
|
||||
mRequest->mElement->GetScriptCharset(hintCharset);
|
||||
} else {
|
||||
nsTArray<ScriptLoader::PreloadInfo>::index_type i =
|
||||
mScriptLoader->mPreloads.IndexOf(mRequest, 0,
|
||||
ScriptLoader::PreloadRequestComparator());
|
||||
|
||||
NS_ASSERTION(i != mScriptLoader->mPreloads.NoIndex,
|
||||
"Incorrect preload bookkeeping");
|
||||
hintCharset = mScriptLoader->mPreloads[i].mCharset;
|
||||
}
|
||||
|
||||
if (EncodingUtils::FindEncodingForLabel(hintCharset, charset)) {
|
||||
mDecoder = EncodingUtils::DecoderForEncoding(charset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the charset from the charset of the document.
|
||||
if (mScriptLoader->mDocument) {
|
||||
charset = mScriptLoader->mDocument->GetDocumentCharacterSet();
|
||||
mDecoder = EncodingUtils::DecoderForEncoding(charset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Curiously, there are various callers that don't pass aDocument. The
|
||||
// fallback in the old code was ISO-8859-1, which behaved like
|
||||
// windows-1252. Saying windows-1252 for clarity and for compliance
|
||||
// with the Encoding Standard.
|
||||
charset = "windows-1252";
|
||||
mDecoder = EncodingUtils::DecoderForEncoding(charset);
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus,
|
||||
uint32_t aDataLength,
|
||||
const uint8_t* aData)
|
||||
{
|
||||
if (!mRequest->IsCanceled()) {
|
||||
DebugOnly<bool> encoderSet =
|
||||
EnsureDecoder(aLoader, aData, aDataLength, /* aEndOfStream = */ true);
|
||||
MOZ_ASSERT(encoderSet);
|
||||
DebugOnly<nsresult> rv = TryDecodeRawData(aData, aDataLength,
|
||||
/* aEndOfStream = */ true);
|
||||
|
||||
// If SRI is required for this load, appending new bytes to the hash.
|
||||
if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) {
|
||||
mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData);
|
||||
}
|
||||
}
|
||||
|
||||
// we have to mediate and use mRequest.
|
||||
return mScriptLoader->OnStreamComplete(aLoader, mRequest, aStatus, mSRIStatus,
|
||||
mBuffer, mSRIDataVerifier);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
} // mozilla namespace
|
||||
|
||||
Reference in New Issue
Block a user