mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-07 07:47:30 +09:00
Issue #618 - Further align error handling for module scripts with the spec
Ref: BZ 1388728
This commit is contained in:
parent
c65ca2ca58
commit
743bdc04fb
6 changed files with 280 additions and 89 deletions
|
|
@ -43,10 +43,16 @@ void ModuleLoadRequest::Cancel()
|
||||||
ScriptLoadRequest::Cancel();
|
ScriptLoadRequest::Cancel();
|
||||||
mModuleScript = nullptr;
|
mModuleScript = nullptr;
|
||||||
mProgress = ScriptLoadRequest::Progress::Ready;
|
mProgress = ScriptLoadRequest::Progress::Ready;
|
||||||
|
CancelImports();
|
||||||
|
mReady.RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleLoadRequest::CancelImports()
|
||||||
|
{
|
||||||
for (size_t i = 0; i < mImports.Length(); i++) {
|
for (size_t i = 0; i < mImports.Length(); i++) {
|
||||||
mImports[i]->Cancel();
|
mImports[i]->Cancel();
|
||||||
}
|
}
|
||||||
mReady.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -77,25 +83,53 @@ ModuleLoadRequest::ModuleLoaded()
|
||||||
// been loaded.
|
// been loaded.
|
||||||
|
|
||||||
mModuleScript = mLoader->GetFetchedModule(mURI);
|
mModuleScript = mLoader->GetFetchedModule(mURI);
|
||||||
|
if (!mModuleScript || mModuleScript->IsErrored()) {
|
||||||
|
ModuleErrored();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mLoader->StartFetchingModuleDependencies(this);
|
mLoader->StartFetchingModuleDependencies(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleLoadRequest::ModuleErrored()
|
||||||
|
{
|
||||||
|
mLoader->CheckModuleDependenciesLoaded(this);
|
||||||
|
MOZ_ASSERT(!mModuleScript || mModuleScript->IsErrored());
|
||||||
|
|
||||||
|
CancelImports();
|
||||||
|
SetReady();
|
||||||
|
LoadFinished();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModuleLoadRequest::DependenciesLoaded()
|
ModuleLoadRequest::DependenciesLoaded()
|
||||||
{
|
{
|
||||||
// The module and all of its dependencies have been successfully fetched and
|
// The module and all of its dependencies have been successfully fetched and
|
||||||
// compiled.
|
// compiled.
|
||||||
|
|
||||||
|
MOZ_ASSERT(mModuleScript);
|
||||||
|
|
||||||
|
mLoader->CheckModuleDependenciesLoaded(this);
|
||||||
SetReady();
|
SetReady();
|
||||||
mLoader->ProcessLoadedModuleTree(this);
|
LoadFinished();
|
||||||
mLoader = nullptr;
|
|
||||||
mParent = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModuleLoadRequest::LoadFailed()
|
ModuleLoadRequest::LoadFailed()
|
||||||
{
|
{
|
||||||
|
// We failed to load the source text or an error occurred unrelated to the
|
||||||
|
// content of the module (e.g. OOM).
|
||||||
|
|
||||||
|
MOZ_ASSERT(!mModuleScript);
|
||||||
|
|
||||||
Cancel();
|
Cancel();
|
||||||
|
LoadFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleLoadRequest::LoadFinished()
|
||||||
|
{
|
||||||
mLoader->ProcessLoadedModuleTree(this);
|
mLoader->ProcessLoadedModuleTree(this);
|
||||||
mLoader = nullptr;
|
mLoader = nullptr;
|
||||||
mParent = nullptr;
|
mParent = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,15 @@ public:
|
||||||
void Cancel() override;
|
void Cancel() override;
|
||||||
|
|
||||||
void ModuleLoaded();
|
void ModuleLoaded();
|
||||||
|
void ModuleErrored();
|
||||||
void DependenciesLoaded();
|
void DependenciesLoaded();
|
||||||
void LoadFailed();
|
void LoadFailed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void LoadFinished();
|
||||||
|
void CancelImports();
|
||||||
|
|
||||||
|
public:
|
||||||
// Is this a request for a top level module script or an import?
|
// Is this a request for a top level module script or an import?
|
||||||
bool mIsTopLevel;
|
bool mIsTopLevel;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
||||||
tmp->UnlinkModuleRecord();
|
tmp->UnlinkModuleRecord();
|
||||||
|
tmp->mError.setUndefined();
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
||||||
|
|
@ -34,25 +35,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mError)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
|
||||||
|
|
||||||
ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL,
|
ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL)
|
||||||
JS::Handle<JSObject*> aModuleRecord)
|
|
||||||
: mLoader(aLoader),
|
: mLoader(aLoader),
|
||||||
mBaseURL(aBaseURL),
|
mBaseURL(aBaseURL)
|
||||||
mModuleRecord(aModuleRecord)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mLoader);
|
MOZ_ASSERT(mLoader);
|
||||||
MOZ_ASSERT(mBaseURL);
|
MOZ_ASSERT(mBaseURL);
|
||||||
MOZ_ASSERT(mModuleRecord);
|
MOZ_ASSERT(!mModuleRecord);
|
||||||
|
MOZ_ASSERT(mError.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
|
void
|
||||||
|
|
@ -63,18 +59,64 @@ ModuleScript::UnlinkModuleRecord()
|
||||||
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
|
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
|
||||||
this);
|
this);
|
||||||
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
|
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
|
||||||
}
|
|
||||||
mModuleRecord = nullptr;
|
mModuleRecord = nullptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ModuleScript::~ModuleScript()
|
ModuleScript::~ModuleScript()
|
||||||
{
|
{
|
||||||
if (mModuleRecord) {
|
|
||||||
// The object may be destroyed without being unlinked first.
|
// The object may be destroyed without being unlinked first.
|
||||||
UnlinkModuleRecord();
|
UnlinkModuleRecord();
|
||||||
}
|
|
||||||
DropJSObjects(this);
|
DropJSObjects(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mModuleRecord);
|
||||||
|
MOZ_ASSERT(mError.isUndefined());
|
||||||
|
|
||||||
|
mModuleRecord = aModuleRecord;
|
||||||
|
|
||||||
|
// 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::SetPreInstantiationError(const JS::Value& aError)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!aError.isUndefined());
|
||||||
|
|
||||||
|
UnlinkModuleRecord();
|
||||||
|
mError = aError;
|
||||||
|
|
||||||
|
HoldJSObjects(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ModuleScript::IsErrored() const
|
||||||
|
{
|
||||||
|
if (!mModuleRecord) {
|
||||||
|
MOZ_ASSERT(!mError.isUndefined());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JS::IsModuleErrored(mModuleRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Value
|
||||||
|
ModuleScript::Error() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsErrored());
|
||||||
|
|
||||||
|
if (!mModuleRecord) {
|
||||||
|
return mError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JS::GetModuleError(mModuleRecord);
|
||||||
|
}
|
||||||
|
|
||||||
} // dom namespace
|
} // dom namespace
|
||||||
} // mozilla namespace
|
} // mozilla namespace
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ class ModuleScript final : public nsISupports
|
||||||
RefPtr<ScriptLoader> mLoader;
|
RefPtr<ScriptLoader> mLoader;
|
||||||
nsCOMPtr<nsIURI> mBaseURL;
|
nsCOMPtr<nsIURI> mBaseURL;
|
||||||
JS::Heap<JSObject*> mModuleRecord;
|
JS::Heap<JSObject*> mModuleRecord;
|
||||||
|
JS::Heap<JS::Value> mError;
|
||||||
|
|
||||||
~ModuleScript();
|
~ModuleScript();
|
||||||
|
|
||||||
|
|
@ -31,13 +32,18 @@ public:
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
|
||||||
|
|
||||||
ModuleScript(ScriptLoader* aLoader,
|
ModuleScript(ScriptLoader* aLoader,
|
||||||
nsIURI* aBaseURL,
|
nsIURI* aBaseURL);
|
||||||
JS::Handle<JSObject*> aModuleRecord);
|
|
||||||
|
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||||
|
void SetPreInstantiationError(const JS::Value& aError);
|
||||||
|
|
||||||
ScriptLoader* Loader() const { return mLoader; }
|
ScriptLoader* Loader() const { return mLoader; }
|
||||||
JSObject* ModuleRecord() const { return mModuleRecord; }
|
JSObject* ModuleRecord() const { return mModuleRecord; }
|
||||||
nsIURI* BaseURL() const { return mBaseURL; }
|
nsIURI* BaseURL() const { return mBaseURL; }
|
||||||
|
|
||||||
|
bool IsErrored() const;
|
||||||
|
JS::Value Error() const;
|
||||||
|
|
||||||
void UnlinkModuleRecord();
|
void UnlinkModuleRecord();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -418,25 +418,23 @@ void
|
||||||
ScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest,
|
ScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest,
|
||||||
nsresult aResult)
|
nsresult aResult)
|
||||||
{
|
{
|
||||||
// Update module map with the result of fetching a single module script. The
|
// Update module map with the result of fetching a single module script.
|
||||||
// module script pointer is nullptr on error.
|
|
||||||
//
|
//
|
||||||
// If any requests for the same URL are waiting on this one to complete, they
|
// If any requests for the same URL are waiting on this one to complete, they
|
||||||
// will have ModuleLoaded or LoadFailed on them when the promise is
|
// will have ModuleLoaded or LoadFailed on them when the promise is
|
||||||
// resolved/rejected. This is set up in StartLoad.
|
// resolved/rejected. This is set up in StartLoad.
|
||||||
|
|
||||||
MOZ_ASSERT(!aRequest->IsReadyToRun());
|
|
||||||
|
|
||||||
RefPtr<GenericPromise::Private> promise;
|
RefPtr<GenericPromise::Private> promise;
|
||||||
MOZ_ALWAYS_TRUE(mFetchingModules.Get(aRequest->mURI, getter_AddRefs(promise)));
|
MOZ_ALWAYS_TRUE(mFetchingModules.Get(aRequest->mURI, getter_AddRefs(promise)));
|
||||||
mFetchingModules.Remove(aRequest->mURI);
|
mFetchingModules.Remove(aRequest->mURI);
|
||||||
|
|
||||||
RefPtr<ModuleScript> ms(aRequest->mModuleScript);
|
RefPtr<ModuleScript> moduleScript(aRequest->mModuleScript);
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(aResult) == (ms != nullptr));
|
MOZ_ASSERT(NS_FAILED(aResult) == !moduleScript);
|
||||||
mFetchedModules.Put(aRequest->mURI, ms);
|
|
||||||
|
mFetchedModules.Put(aRequest->mURI, moduleScript);
|
||||||
|
|
||||||
if (promise) {
|
if (promise) {
|
||||||
if (ms) {
|
if (moduleScript) {
|
||||||
promise->Resolve(true, __func__);
|
promise->Resolve(true, __func__);
|
||||||
} else {
|
} else {
|
||||||
promise->Reject(aResult, __func__);
|
promise->Reject(aResult, __func__);
|
||||||
|
|
@ -482,19 +480,29 @@ ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest)
|
||||||
MOZ_ASSERT(!aRequest->mModuleScript);
|
MOZ_ASSERT(!aRequest->mModuleScript);
|
||||||
|
|
||||||
nsresult rv = CreateModuleScript(aRequest);
|
nsresult rv = CreateModuleScript(aRequest);
|
||||||
|
MOZ_ASSERT(NS_FAILED(rv) == !aRequest->mModuleScript);
|
||||||
|
|
||||||
SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv);
|
SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv);
|
||||||
|
|
||||||
free(aRequest->mScriptTextBuf);
|
free(aRequest->mScriptTextBuf);
|
||||||
aRequest->mScriptTextBuf = nullptr;
|
aRequest->mScriptTextBuf = nullptr;
|
||||||
aRequest->mScriptTextLength = 0;
|
aRequest->mScriptTextLength = 0;
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
aRequest->LoadFailed();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aRequest->mModuleScript->IsErrored()) {
|
||||||
StartFetchingModuleDependencies(aRequest);
|
StartFetchingModuleDependencies(aRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nsresult
|
||||||
|
ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>& aUrls);
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
|
|
@ -548,9 +556,34 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
|
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
|
||||||
if (module) {
|
RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL);
|
||||||
aRequest->mModuleScript =
|
aRequest->mModuleScript = moduleScript;
|
||||||
new ModuleScript(this, aRequest->mBaseURL, module);
|
|
||||||
|
if (!module) {
|
||||||
|
// Compilation failed
|
||||||
|
MOZ_ASSERT(aes.HasException());
|
||||||
|
JS::Rooted<JS::Value> error(cx);
|
||||||
|
if (!aes.StealException(&error)) {
|
||||||
|
aRequest->mModuleScript = nullptr;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleScript->SetPreInstantiationError(error);
|
||||||
|
aRequest->ModuleErrored();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleScript->SetModuleRecord(module);
|
||||||
|
|
||||||
|
// Validate requested modules and treat failure to resolve module specifiers
|
||||||
|
// the same as a parse error.
|
||||||
|
nsCOMArray<nsIURI> urls;
|
||||||
|
rv = ResolveRequestedModules(aRequest, urls);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// ResolveRequestedModules sets pre-instanitation error on failure.
|
||||||
|
MOZ_ASSERT(moduleScript->IsErrored());
|
||||||
|
aRequest->ModuleErrored();
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -560,8 +593,8 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ThrowTypeError(JSContext* aCx, ModuleScript* aScript,
|
CreateTypeError(JSContext* aCx, ModuleScript* aScript, const nsString& aMessage,
|
||||||
const nsString& aMessage)
|
JS::MutableHandle<JS::Value> aError)
|
||||||
{
|
{
|
||||||
JS::Rooted<JSObject*> module(aCx, aScript->ModuleRecord());
|
JS::Rooted<JSObject*> module(aCx, aScript->ModuleRecord());
|
||||||
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module));
|
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module));
|
||||||
|
|
@ -576,17 +609,11 @@ ThrowTypeError(JSContext* aCx, ModuleScript* aScript,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<JS::Value> error(aCx);
|
return JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr,
|
||||||
if (!JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr,
|
message, aError);
|
||||||
message, &error)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_SetPendingException(aCx, error);
|
static nsresult
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
||||||
const nsAString& aSpecifier)
|
const nsAString& aSpecifier)
|
||||||
{
|
{
|
||||||
|
|
@ -595,19 +622,13 @@ HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
||||||
nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: "));
|
nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: "));
|
||||||
message.Append(aSpecifier);
|
message.Append(aSpecifier);
|
||||||
|
|
||||||
return ThrowTypeError(aCx, aScript, message);
|
JS::Rooted<JS::Value> error(aCx);
|
||||||
|
if (!CreateTypeError(aCx, aScript, message, &error)) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
aScript->SetPreInstantiationError(error);
|
||||||
HandleModuleNotFound(JSContext* aCx, ModuleScript* aScript,
|
return NS_OK;
|
||||||
const nsAString& aSpecifier)
|
|
||||||
{
|
|
||||||
// TODO: How can we get the line number of the failed import?
|
|
||||||
|
|
||||||
nsAutoString message(NS_LITERAL_STRING("Resolved module not found in map: "));
|
|
||||||
message.Append(aSpecifier);
|
|
||||||
|
|
||||||
return ThrowTypeError(aCx, aScript, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static already_AddRefed<nsIURI>
|
static already_AddRefed<nsIURI>
|
||||||
|
|
@ -705,7 +726,8 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls)
|
||||||
ModuleScript* ms = aRequest->mModuleScript;
|
ModuleScript* ms = aRequest->mModuleScript;
|
||||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier);
|
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier);
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
HandleResolveFailure(cx, ms, specifier);
|
nsresult rv = HandleResolveFailure(cx, ms, specifier);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -724,6 +746,7 @@ void
|
||||||
ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
|
ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aRequest->mModuleScript);
|
MOZ_ASSERT(aRequest->mModuleScript);
|
||||||
|
MOZ_ASSERT(!aRequest->mModuleScript->IsErrored());
|
||||||
MOZ_ASSERT(!aRequest->IsReadyToRun());
|
MOZ_ASSERT(!aRequest->IsReadyToRun());
|
||||||
|
|
||||||
aRequest->mProgress = ModuleLoadRequest::Progress::FetchingImports;
|
aRequest->mProgress = ModuleLoadRequest::Progress::FetchingImports;
|
||||||
|
|
@ -731,7 +754,7 @@ ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
|
||||||
nsCOMArray<nsIURI> urls;
|
nsCOMArray<nsIURI> urls;
|
||||||
nsresult rv = ResolveRequestedModules(aRequest, urls);
|
nsresult rv = ResolveRequestedModules(aRequest, urls);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
aRequest->LoadFailed();
|
aRequest->ModuleErrored();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -755,7 +778,7 @@ ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
|
||||||
GenericPromise::All(AbstractThread::GetCurrent(), importsReady);
|
GenericPromise::All(AbstractThread::GetCurrent(), importsReady);
|
||||||
allReady->Then(AbstractThread::GetCurrent(), __func__, aRequest,
|
allReady->Then(AbstractThread::GetCurrent(), __func__, aRequest,
|
||||||
&ModuleLoadRequest::DependenciesLoaded,
|
&ModuleLoadRequest::DependenciesLoaded,
|
||||||
&ModuleLoadRequest::LoadFailed);
|
&ModuleLoadRequest::ModuleErrored);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<GenericPromise>
|
RefPtr<GenericPromise>
|
||||||
|
|
@ -778,6 +801,7 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest,
|
||||||
|
|
||||||
nsresult rv = StartLoad(childRequest, NS_LITERAL_STRING("module"), false);
|
nsresult rv = StartLoad(childRequest, NS_LITERAL_STRING("module"), false);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
MOZ_ASSERT(!childRequest->mModuleScript);
|
||||||
childRequest->mReady.Reject(rv, __func__);
|
childRequest->mReady.Reject(rv, __func__);
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
|
@ -786,6 +810,7 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest,
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
|
||||||
bool
|
bool
|
||||||
HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
|
HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
|
||||||
{
|
{
|
||||||
|
|
@ -800,25 +825,25 @@ HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
|
||||||
MOZ_ASSERT(script->ModuleRecord() == module);
|
MOZ_ASSERT(script->ModuleRecord() == module);
|
||||||
|
|
||||||
// Let url be the result of resolving a module specifier given referencing
|
// Let url be the result of resolving a module specifier given referencing
|
||||||
// module script and specifier. If the result is failure, throw a TypeError
|
// module script and specifier.
|
||||||
// exception and abort these steps.
|
|
||||||
nsAutoJSString string;
|
nsAutoJSString string;
|
||||||
if (!string.init(aCx, specifier)) {
|
if (!string.init(aCx, specifier)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
|
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
|
||||||
if (!uri) {
|
|
||||||
return HandleResolveFailure(aCx, script, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let resolved module script be the value of the entry in module map whose
|
// This cannot fail because resolving a module specifier must have been
|
||||||
// key is url. If no such entry exists, throw a TypeError exception and abort
|
// previously successful with these same two arguments.
|
||||||
// these steps.
|
MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier");
|
||||||
|
|
||||||
|
// Let resolved module script be moduleMap[url]. (This entry must exist for us
|
||||||
|
// to have gotten to this point.)
|
||||||
|
|
||||||
ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
|
ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
|
||||||
if (!ms) {
|
MOZ_ASSERT(ms, "Resolved module not found in module map");
|
||||||
return HandleModuleNotFound(aCx, script, string);
|
|
||||||
}
|
MOZ_ASSERT(!ms->IsErrored());
|
||||||
|
|
||||||
*vp = JS::ObjectValue(*ms->ModuleRecord());
|
*vp = JS::ObjectValue(*ms->ModuleRecord());
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -842,10 +867,36 @@ EnsureModuleResolveHook(JSContext* aCx)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ScriptLoader::CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest)
|
||||||
|
{
|
||||||
|
RefPtr<ModuleScript> moduleScript = aRequest->mModuleScript;
|
||||||
|
if (moduleScript && !moduleScript->IsErrored()) {
|
||||||
|
for (auto childRequest : aRequest->mImports) {
|
||||||
|
ModuleScript* childScript = childRequest->mModuleScript;
|
||||||
|
if (!childScript) {
|
||||||
|
// Load error
|
||||||
|
aRequest->mModuleScript = nullptr;
|
||||||
|
return;
|
||||||
|
} else if (childScript->IsErrored()) {
|
||||||
|
// Script error
|
||||||
|
moduleScript->SetPreInstantiationError(childScript->Error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
|
ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
if (aRequest->IsTopLevel()) {
|
if (aRequest->IsTopLevel()) {
|
||||||
|
ModuleScript* moduleScript = aRequest->mModuleScript;
|
||||||
|
if (moduleScript && !moduleScript->IsErrored()) {
|
||||||
|
if (!InstantiateModuleTree(aRequest)) {
|
||||||
|
aRequest->mModuleScript = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
MaybeMoveToLoadedList(aRequest);
|
MaybeMoveToLoadedList(aRequest);
|
||||||
ProcessPendingRequests();
|
ProcessPendingRequests();
|
||||||
}
|
}
|
||||||
|
|
@ -855,6 +906,43 @@ ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
|
||||||
|
{
|
||||||
|
// Instantiate a top-level module and record any error.
|
||||||
|
|
||||||
|
MOZ_ASSERT(aRequest);
|
||||||
|
MOZ_ASSERT(aRequest->IsTopLevel());
|
||||||
|
|
||||||
|
ModuleScript* moduleScript = aRequest->mModuleScript;
|
||||||
|
MOZ_ASSERT(moduleScript);
|
||||||
|
MOZ_ASSERT(moduleScript->ModuleRecord());
|
||||||
|
|
||||||
|
nsAutoMicroTask mt;
|
||||||
|
AutoJSAPI jsapi;
|
||||||
|
if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv = EnsureModuleResolveHook(jsapi.cx());
|
||||||
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
|
||||||
|
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
MOZ_ASSERT(jsapi.HasException());
|
||||||
|
JS::RootedValue exception(jsapi.cx());
|
||||||
|
if (!jsapi.StealException(&exception)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(!exception.isUndefined());
|
||||||
|
// Ignore the exception. It will be recorded in the module record.
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
|
ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
|
||||||
bool aScriptFromHead)
|
bool aScriptFromHead)
|
||||||
|
|
@ -1364,13 +1452,19 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||||
ModuleLoadRequest* modReq = request->AsModuleRequest();
|
ModuleLoadRequest* modReq = request->AsModuleRequest();
|
||||||
modReq->mBaseURL = mDocument->GetDocBaseURI();
|
modReq->mBaseURL = mDocument->GetDocBaseURI();
|
||||||
rv = CreateModuleScript(modReq);
|
rv = CreateModuleScript(modReq);
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
MOZ_ASSERT(NS_FAILED(rv) == !modReq->mModuleScript);
|
||||||
StartFetchingModuleDependencies(modReq);
|
if (NS_FAILED(rv)) {
|
||||||
|
modReq->LoadFailed();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (aElement->GetScriptAsync()) {
|
if (aElement->GetScriptAsync()) {
|
||||||
mLoadingAsyncRequests.AppendElement(request);
|
mLoadingAsyncRequests.AppendElement(request);
|
||||||
} else {
|
} else {
|
||||||
AddDeferRequest(request);
|
AddDeferRequest(request);
|
||||||
}
|
}
|
||||||
|
if (!modReq->mModuleScript->IsErrored()) {
|
||||||
|
StartFetchingModuleDependencies(modReq);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
request->mProgress = ScriptLoadRequest::Progress::Ready;
|
request->mProgress = ScriptLoadRequest::Progress::Ready;
|
||||||
|
|
@ -1448,11 +1542,7 @@ ScriptLoader::ProcessOffThreadRequest(ScriptLoadRequest* aRequest)
|
||||||
if (aRequest->IsModuleRequest()) {
|
if (aRequest->IsModuleRequest()) {
|
||||||
MOZ_ASSERT(aRequest->mOffThreadToken);
|
MOZ_ASSERT(aRequest->mOffThreadToken);
|
||||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||||
nsresult rv = ProcessFetchedModuleSource(request);
|
return ProcessFetchedModuleSource(request);
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
request->LoadFailed();
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aRequest->SetReady();
|
aRequest->SetReady();
|
||||||
|
|
@ -1624,7 +1714,7 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
|
||||||
if (aRequest->IsModuleRequest() &&
|
if (aRequest->IsModuleRequest() &&
|
||||||
!aRequest->AsModuleRequest()->mModuleScript)
|
!aRequest->AsModuleRequest()->mModuleScript)
|
||||||
{
|
{
|
||||||
// There was an error parsing a module script. Nothing to do here.
|
// There was an error fetching a module script. Nothing to do here.
|
||||||
FireScriptAvailable(NS_ERROR_FAILURE, aRequest);
|
FireScriptAvailable(NS_ERROR_FAILURE, aRequest);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -1846,8 +1936,8 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
||||||
nsAutoMicroTask mt;
|
nsAutoMicroTask mt;
|
||||||
AutoEntryScript aes(globalObject, "<script> element", true);
|
AutoEntryScript aes(globalObject, "<script> element", true);
|
||||||
JS::Rooted<JSObject*> global(aes.cx(),
|
JSContext* cx = aes.cx();
|
||||||
globalObject->GetGlobalJSObject());
|
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||||
|
|
||||||
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
|
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
|
||||||
context->SetProcessingScriptTag(true);
|
context->SetProcessingScriptTag(true);
|
||||||
|
|
@ -1868,27 +1958,38 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aRequest->IsModuleRequest()) {
|
if (aRequest->IsModuleRequest()) {
|
||||||
rv = EnsureModuleResolveHook(aes.cx());
|
rv = EnsureModuleResolveHook(cx);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||||
MOZ_ASSERT(request->mModuleScript);
|
MOZ_ASSERT(request->mModuleScript);
|
||||||
MOZ_ASSERT(!request->mOffThreadToken);
|
MOZ_ASSERT(!request->mOffThreadToken);
|
||||||
JS::Rooted<JSObject*> module(aes.cx(),
|
|
||||||
request->mModuleScript->ModuleRecord());
|
ModuleScript* moduleScript = request->mModuleScript;
|
||||||
|
if (moduleScript->IsErrored()) {
|
||||||
|
// Module has an error status
|
||||||
|
JS::Rooted<JS::Value> error(cx, moduleScript->Error());
|
||||||
|
JS_SetPendingException(cx, error);
|
||||||
|
return NS_OK; // An error is reported by AutoEntryScript.
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
|
||||||
MOZ_ASSERT(module);
|
MOZ_ASSERT(module);
|
||||||
rv = nsJSUtils::ModuleInstantiate(aes.cx(), module);
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
rv = nsJSUtils::ModuleEvaluate(cx, module);
|
||||||
rv = nsJSUtils::ModuleEvaluate(aes.cx(), module);
|
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// Evaluation failed
|
||||||
|
rv = NS_OK; // An error is reported by AutoEntryScript.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JS::CompileOptions options(aes.cx());
|
JS::CompileOptions options(cx);
|
||||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
nsAutoString inlineData;
|
nsAutoString inlineData;
|
||||||
SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
|
SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
|
||||||
rv = nsJSUtils::EvaluateString(aes.cx(), srcBuf, global, options,
|
rv = nsJSUtils::EvaluateString(cx, srcBuf, global, options,
|
||||||
aRequest->OffThreadTokenPtr());
|
aRequest->OffThreadTokenPtr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -580,7 +580,9 @@ private:
|
||||||
|
|
||||||
nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
|
nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
|
||||||
nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
|
nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
|
||||||
|
void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest);
|
||||||
void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
|
void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
|
||||||
|
bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
|
||||||
void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
|
void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
|
||||||
|
|
||||||
RefPtr<mozilla::GenericPromise>
|
RefPtr<mozilla::GenericPromise>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue