зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1519100 - Implement module promises in html r=emilio,jonco
Differential Revision: https://phabricator.services.mozilla.com/D95885
This commit is contained in:
Родитель
ecd3ed9ff7
Коммит
21104289bb
|
@ -173,7 +173,7 @@ nsresult nsJSUtils::ModuleInstantiate(JSContext* aCx,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ModuleEvaluate(JSContext* aCx,
|
||||
JSObject* nsJSUtils::ModuleEvaluate(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aModule) {
|
||||
AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluate", JS);
|
||||
|
||||
|
@ -182,13 +182,9 @@ nsresult nsJSUtils::ModuleEvaluate(JSContext* aCx,
|
|||
MOZ_ASSERT(CycleCollectedJSContext::Get() &&
|
||||
CycleCollectedJSContext::Get()->MicroTaskLevel());
|
||||
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), nullptr);
|
||||
|
||||
if (!JS::ModuleEvaluate(aCx, aModule)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return JS::ModuleEvaluate(aCx, aModule);
|
||||
}
|
||||
|
||||
static bool AddScopeChainItem(JSContext* aCx, nsINode* aNode,
|
||||
|
|
|
@ -80,7 +80,18 @@ class nsJSUtils {
|
|||
static nsresult ModuleInstantiate(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aModule);
|
||||
|
||||
static nsresult ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule);
|
||||
/*
|
||||
* Wrapper for JSAPI ModuleEvaluate function.
|
||||
*
|
||||
* @param JSContext aCx
|
||||
* The JSContext where this is executed.
|
||||
* @param JS::Handle<JSObject*> aModule
|
||||
* The module to be evaluated.
|
||||
* @returns JS::MutableHandle<JSObject*> aEvaluationPromise
|
||||
* The evaluaation promise returned from evaluating the module.
|
||||
*/
|
||||
static JSObject* ModuleEvaluate(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aModule);
|
||||
|
||||
// Returns false if an exception got thrown on aCx. Passing a null
|
||||
// aElement is allowed; that wil produce an empty aScopeChain.
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "jsfriendapi.h"
|
||||
#include "js/Array.h" // JS::GetArrayLength
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/ContextOptions.h" // JS::ContextOptionsRef
|
||||
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
|
||||
#include "js/MemoryFunctions.h"
|
||||
#include "js/Modules.h" // JS::FinishDynamicModuleImport, JS::{G,S}etModuleResolveHook, JS::Get{ModulePrivate,ModuleScript,RequestedModule{s,Specifier,SourcePos}}, JS::SetModule{DynamicImport,Metadata}Hook
|
||||
|
@ -219,7 +220,7 @@ ScriptLoader::~ScriptLoader() {
|
|||
|
||||
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
|
||||
req = req->getNext()) {
|
||||
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
|
||||
FinishDynamicImportAndReject(req->AsModuleRequest(), NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
for (ScriptLoadRequest* req =
|
||||
|
@ -1052,31 +1053,31 @@ void ScriptLoader::StartDynamicImport(ModuleLoadRequest* aRequest) {
|
|||
|
||||
nsresult rv = StartLoad(aRequest);
|
||||
if (NS_FAILED(rv)) {
|
||||
FinishDynamicImport(aRequest, rv);
|
||||
FinishDynamicImportAndReject(aRequest, rv);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptLoader::FinishDynamicImport(ModuleLoadRequest* aRequest,
|
||||
void ScriptLoader::FinishDynamicImportAndReject(ModuleLoadRequest* aRequest,
|
||||
nsresult aResult) {
|
||||
AutoJSAPI jsapi;
|
||||
MOZ_ASSERT(NS_FAILED(aResult));
|
||||
MOZ_ALWAYS_TRUE(jsapi.Init(aRequest->mDynamicPromise));
|
||||
FinishDynamicImport(jsapi.cx(), aRequest, aResult);
|
||||
FinishDynamicImport(jsapi.cx(), aRequest, aResult, nullptr);
|
||||
}
|
||||
|
||||
void ScriptLoader::FinishDynamicImport(JSContext* aCx,
|
||||
ModuleLoadRequest* aRequest,
|
||||
nsresult aResult) {
|
||||
void ScriptLoader::FinishDynamicImport(
|
||||
JSContext* aCx, ModuleLoadRequest* aRequest, nsresult aResult,
|
||||
JS::Handle<JSObject*> aEvaluationPromise) {
|
||||
// If aResult is a failed result, we don't have an EvaluationPromise. If it
|
||||
// succeeded, evaluationPromise may still be null, but in this case it will
|
||||
// be handled by rejecting the dynamic module import promise in the JSAPI.
|
||||
MOZ_ASSERT_IF(NS_FAILED(aResult), !aEvaluationPromise);
|
||||
LOG(("ScriptLoadRequest (%p): Finish dynamic import %x %d", aRequest,
|
||||
unsigned(aResult), JS_IsExceptionPending(aCx)));
|
||||
|
||||
// Complete the dynamic import, report failures indicated by aResult or as a
|
||||
// pending exception on the context.
|
||||
|
||||
JS::DynamicImportStatus status =
|
||||
(NS_FAILED(aResult) || JS_IsExceptionPending(aCx))
|
||||
? JS::DynamicImportStatus::Failed
|
||||
: JS::DynamicImportStatus::Ok;
|
||||
|
||||
if (NS_FAILED(aResult) &&
|
||||
aResult != NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
|
||||
|
@ -1089,8 +1090,8 @@ void ScriptLoader::FinishDynamicImport(JSContext* aCx,
|
|||
JS::Rooted<JSString*> specifier(aCx, aRequest->mDynamicSpecifier);
|
||||
JS::Rooted<JSObject*> promise(aCx, aRequest->mDynamicPromise);
|
||||
|
||||
JS::FinishDynamicModuleImport(aCx, status, referencingScript, specifier,
|
||||
promise);
|
||||
JS::FinishDynamicModuleImport(aCx, aEvaluationPromise, referencingScript,
|
||||
specifier, promise);
|
||||
|
||||
// FinishDynamicModuleImport clears any pending exception.
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
|
||||
|
@ -2642,7 +2643,7 @@ void ScriptLoader::ProcessDynamicImport(ModuleLoadRequest* aRequest) {
|
|||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
FinishDynamicImport(aRequest, rv);
|
||||
FinishDynamicImportAndReject(aRequest, rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2941,7 +2942,7 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
|||
// For a dynamic import, the promise is rejected. Otherwise an error is
|
||||
// either reported by AutoEntryScript.
|
||||
if (request->IsDynamicImport()) {
|
||||
FinishDynamicImport(cx, request, NS_OK);
|
||||
FinishDynamicImport(cx, request, NS_OK, nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2954,18 +2955,20 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
|||
|
||||
TRACE_FOR_TEST(aRequest->GetScriptElement(),
|
||||
"scriptloader_evaluate_module");
|
||||
rv = nsJSUtils::ModuleEvaluate(cx, module);
|
||||
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("ScriptLoadRequest (%p): evaluation failed", aRequest));
|
||||
// For a dynamic import, the promise is rejected. Otherwise an error is
|
||||
// either reported by AutoEntryScript.
|
||||
rv = NS_OK;
|
||||
}
|
||||
JS::Rooted<JSObject*> aEvaluationPromise(
|
||||
cx, nsJSUtils::ModuleEvaluate(cx, module));
|
||||
|
||||
if (request->IsDynamicImport()) {
|
||||
FinishDynamicImport(cx, request, rv);
|
||||
FinishDynamicImport(cx, request, rv, aEvaluationPromise);
|
||||
} else {
|
||||
// If this is not a dynamic import, and if the promise is rejected, the
|
||||
// value is unwrapped from the promise value.
|
||||
if (!JS::ThrowOnModuleEvaluationFailure(cx, aEvaluationPromise)) {
|
||||
LOG(("ScriptLoadRequest (%p): evaluation failed", aRequest));
|
||||
// For a dynamic import, the promise is rejected. Otherwise an error
|
||||
// is either reported by AutoEntryScript.
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_FOR_TEST_NONE(aRequest->GetScriptElement(),
|
||||
|
@ -3780,7 +3783,7 @@ void ScriptLoader::HandleLoadError(ScriptLoadRequest* aRequest,
|
|||
// FinishDynamicImport must happen exactly once for each dynamic import
|
||||
// request. If the load is aborted we do it when we remove the request
|
||||
// from mDynamicImportRequests.
|
||||
FinishDynamicImport(modReq, aResult);
|
||||
FinishDynamicImportAndReject(modReq, aResult);
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(!modReq->IsTopLevel());
|
||||
|
@ -4028,7 +4031,7 @@ void ScriptLoader::ParsingComplete(bool aTerminated) {
|
|||
// FinishDynamicImport must happen exactly once for each dynamic import
|
||||
// request. If the load is aborted we do it when we remove the request
|
||||
// from mDynamicImportRequests.
|
||||
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
|
||||
FinishDynamicImportAndReject(req->AsModuleRequest(), NS_ERROR_ABORT);
|
||||
}
|
||||
mDynamicImportRequests.Clear();
|
||||
|
||||
|
|
|
@ -411,10 +411,41 @@ class ScriptLoader final : public nsISupports {
|
|||
JS::MutableHandle<JSObject*> aModuleOut);
|
||||
|
||||
void StartDynamicImport(ModuleLoadRequest* aRequest);
|
||||
void FinishDynamicImport(ModuleLoadRequest* aRequest, nsresult aResult);
|
||||
void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest,
|
||||
|
||||
/**
|
||||
* Shorthand Wrapper for JSAPI FinishDynamicImport function for the reject
|
||||
* case where we do not have `aEvaluationPromise`. As there is no evaluation
|
||||
* Promise, JS::FinishDynamicImport will always reject.
|
||||
*
|
||||
* @param aRequest
|
||||
* The module load request for the dynamic module.
|
||||
* @param aResult
|
||||
* The result of running ModuleEvaluate -- If this is successful, then
|
||||
* we can await the associated EvaluationPromise.
|
||||
*/
|
||||
void FinishDynamicImportAndReject(ModuleLoadRequest* aRequest,
|
||||
nsresult aResult);
|
||||
|
||||
/**
|
||||
* Wrapper for JSAPI FinishDynamicImport function. Takes an optional argument
|
||||
* `aEvaluationPromise` which, if null, exits early.
|
||||
*
|
||||
* @param aCX
|
||||
* The JSContext for the module.
|
||||
* @param aRequest
|
||||
* The module load request for the dynamic module.
|
||||
* @param aResult
|
||||
* The result of running ModuleEvaluate -- If this is successful, then
|
||||
* we can await the associated EvaluationPromise.
|
||||
* @param aEvaluationPromise
|
||||
* The evaluation promise returned from evaluating the module. If this
|
||||
* is null, JS::FinishDynamicImport will reject the dynamic import
|
||||
* module promise.
|
||||
*/
|
||||
void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest,
|
||||
nsresult aResult,
|
||||
JS::Handle<JSObject*> aEvaluationPromise);
|
||||
|
||||
/*
|
||||
* Get the currently active script. This is used as the initiating script when
|
||||
* executing timeout handler scripts.
|
||||
|
|
|
@ -405,7 +405,12 @@ void ExecutionRunnable::RunOnWorkletThread() {
|
|||
// https://html.spec.whatwg.org/multipage/webappapis.html#run-a-module-script
|
||||
// without /rethrow errors/ and so unhandled exceptions do not cause the
|
||||
// promise to be rejected.
|
||||
JS::ModuleEvaluate(cx, module);
|
||||
JS::Rooted<JSObject*> evaluationPromise(cx, JS::ModuleEvaluate(cx, module));
|
||||
|
||||
if (!JS::ThrowOnModuleEvaluationFailure(cx, evaluationPromise)) {
|
||||
mResult = NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// All done.
|
||||
mResult = NS_OK;
|
||||
|
|
Загрузка…
Ссылка в новой задаче