Issue #1691 - Part 7d: Allow dynamic import in cases where there's no referencing script or module. Support dynamic import from classic scripts by creating ClassicScript objects and associating them with the compiled. https://bugzilla.mozilla.org/show_bug.cgi?id=1342012 This patch is incomplete, some code in ScriptLoader::EvaluateScript() could not be applied for missing dependencies. Part 7e will apply the missing dependencies and finish the patch.

(cherry picked from commit ce31a906e801b72f06385b0755710317ccf3658b)
This commit is contained in:
Brian Smith
2023-04-19 01:59:14 -05:00
committed by roytam1
parent 41eda05e57
commit d5d7bb5e47
6 changed files with 190 additions and 90 deletions
+120 -51
View File
@@ -20,6 +20,7 @@
#include "mozilla/dom/SRILogHelper.h"
#include "nsGkAtoms.h"
#include "nsNetUtil.h"
#include "nsGlobalWindow.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsIScriptSecurityManager.h"
@@ -638,7 +639,7 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
RefPtr<ModuleScript> moduleScript =
new ModuleScript(this, aRequest->mFetchOptions, aRequest->mBaseURL);
new ModuleScript(aRequest->mFetchOptions, aRequest->mBaseURL);
aRequest->mModuleScript = moduleScript;
if (!module) {
@@ -711,8 +712,7 @@ HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
}
static already_AddRefed<nsIURI>
ResolveModuleSpecifier(ModuleScript* aScript,
const nsAString& aSpecifier)
ResolveModuleSpecifier(ScriptLoader* aLoader, LoadedScript* aScript, const nsAString& aSpecifier)
{
// The following module specifiers are allowed by the spec:
// - a valid absolute URL
@@ -737,7 +737,15 @@ ResolveModuleSpecifier(ModuleScript* aScript,
return nullptr;
}
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier, nullptr, aScript->BaseURL());
// Get the document's base URL if we don't have a referencing script here.
nsCOMPtr<nsIURI> baseURL;
if (aScript) {
baseURL = aScript->BaseURL();
} else {
baseURL = aLoader->GetDocument()->GetDocBaseURI();
}
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier, nullptr, baseURL);
if (NS_SUCCEEDED(rv)) {
return uri.forget();
}
@@ -776,7 +784,8 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOu
}
// Let url be the result of resolving a module specifier given module script and requested.
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier);
nsCOMPtr<nsIURI> uri =
ResolveModuleSpecifier(aRequest->mLoader, ms, specifier);
if (!uri) {
nsresult rv = HandleResolveFailure(cx, ms, specifier);
NS_ENSURE_SUCCESS(rv, rv);
@@ -869,34 +878,83 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent,
return ready;
}
static ScriptLoader* GetCurrentScriptLoader(JSContext* aCx) {
JSObject* object = JS::CurrentGlobalOrNull(aCx);
if (!object) {
return nullptr;
}
nsIGlobalObject* global = xpc::NativeGlobal(object);
if (!global) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global);
nsGlobalWindow* window = nsGlobalWindow::Cast(win);
if (!window) {
return nullptr;
}
nsIDocument* document = window->GetDocument();
if (!document) {
return nullptr;
}
ScriptLoader* loader = document->ScriptLoader();
if (!loader) {
return nullptr;
}
return loader;
}
static LoadedScript* GetLoadedScriptOrNull(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate) {
if (aReferencingPrivate.isUndefined()) {
return nullptr;
}
auto script = static_cast<LoadedScript*>(aReferencingPrivate.toPrivate());
MOZ_ASSERT_IF(
script->IsModuleScript(),
JS::GetModulePrivate(script->AsModuleScript()->ModuleRecord()) ==
aReferencingPrivate);
return script;
}
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
JSObject*
HostResolveImportedModule(JSContext* aCx,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier)
{
// Let referencing module script be referencingModule.[[HostDefined]].
if (aReferencingPrivate.isUndefined()) {
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_IMPORT_SCRIPT_NOT_FOUND);
return nullptr;
}
JS::Rooted<JSObject*> module(aCx);
ScriptLoader::ResolveImportedModule(aCx, aReferencingPrivate, aSpecifier,
&module);
return module;
}
auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) == aReferencingPrivate);
/* static */ void ScriptLoader::ResolveImportedModule(
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier, JS::MutableHandle<JSObject*> aModuleOut) {
MOZ_ASSERT(!aModuleOut);
RefPtr<LoadedScript> script(GetLoadedScriptOrNull(aCx, aReferencingPrivate));
// Let url be the result of resolving a module specifier given referencing
// module script and specifier.
nsAutoJSString string;
if (!string.init(aCx, aSpecifier)) {
return nullptr;
}
if (!script || !aCx) {
// Our module context was ripped out from under us...
return nullptr;
return;
}
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
RefPtr<ScriptLoader> loader = GetCurrentScriptLoader(aCx);
if (!loader) {
return;
}
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(loader, script, string);
// This cannot fail because resolving a module specifier must have been
// previously successful with these same two arguments.
@@ -905,17 +963,13 @@ HostResolveImportedModule(JSContext* aCx,
// 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 = loader->GetFetchedModule(uri);
MOZ_ASSERT(ms, "Resolved module not found in module map");
if (!ms) {
// Already-resolved module has been removed from the map/unloaded...
return nullptr;
}
MOZ_ASSERT(!ms->HasParseError());
MOZ_ASSERT(ms->ModuleRecord());
return ms->ModuleRecord();
aModuleOut.set(ms->ModuleRecord());
}
bool
@@ -950,15 +1004,7 @@ bool HostImportModuleDynamically(JSContext* aCx,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier,
JS::Handle<JSObject*> aPromise) {
if (aReferencingPrivate.isUndefined()) {
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_IMPORT_SCRIPT_NOT_FOUND);
return false;
}
auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) ==
aReferencingPrivate);
RefPtr<LoadedScript> script(GetLoadedScriptOrNull(aCx, aReferencingPrivate));
// Attempt to resolve the module specifier.
nsAutoJSString string;
@@ -966,7 +1012,12 @@ bool HostImportModuleDynamically(JSContext* aCx,
return false;
}
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
RefPtr<ScriptLoader> loader = GetCurrentScriptLoader(aCx);
if (!loader) {
return false;
}
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(loader, script, string);
if (!uri) {
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_BAD_MODULE_SPECIFIER, string.get());
@@ -974,10 +1025,27 @@ bool HostImportModuleDynamically(JSContext* aCx,
}
// Create a new top-level load request.
RefPtr<ModuleLoadRequest> request = ModuleLoadRequest::CreateDynamicImport(
uri, script, aReferencingPrivate, aSpecifier, aPromise);
ScriptFetchOptions* options;
nsIURI* baseURL;
if (script) {
options = script->FetchOptions();
baseURL = script->BaseURL();
} else {
// We don't have a referencing script so fall back on using
// options from the document. This can happen when the user
// triggers an inline event handler, as there is no active script
// there.
nsIDocument* document = loader->GetDocument();
options = new ScriptFetchOptions(mozilla::CORS_NONE,
document->GetReferrerPolicy(), nullptr,
document->NodePrincipal());
baseURL = document->GetDocBaseURI();
}
script->Loader()->StartDynamicImport(request);
RefPtr<ModuleLoadRequest> request = ModuleLoadRequest::CreateDynamicImport(
uri, options, baseURL, loader, aReferencingPrivate, aSpecifier, aPromise);
loader->StartDynamicImport(request);
return true;
}
@@ -1700,7 +1768,8 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
if (request->IsModuleRequest()) {
ModuleLoadRequest* modReq = request->AsModuleRequest();
modReq->mBaseURL = mDocument->GetDocBaseURI();
request->mBaseURL = mDocument->GetDocBaseURI();
if (aElement->GetScriptAsync()) {
AddAsyncRequest(modReq);
@@ -2801,6 +2870,18 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
mParserBlockingRequest == aRequest,
"aRequest should be pending!");
nsCOMPtr<nsIURI> uri;
rv = channel->GetOriginalURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
// Fixup moz-extension: and resource: URIs, because the channel URI will
// point to file:, which won't be allowed to load.
if (uri && IsInternalURIScheme(uri)) {
aRequest->mBaseURL = uri;
} else {
channel->GetURI(getter_AddRefs(aRequest->mBaseURL));
}
if (aRequest->IsModuleRequest()) {
ModuleLoadRequest* request = aRequest->AsModuleRequest();
@@ -2813,18 +2894,6 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> uri;
rv = channel->GetOriginalURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
// Fixup internal scheme URIs like resource:, because the channel URI
// will point to file: which won't be allowed to load.
if (uri && IsInternalURIScheme(uri)) {
request->mBaseURL = uri;
} else {
channel->GetURI(getter_AddRefs(request->mBaseURL));
}
// Attempt to compile off main thread.
rv = AttemptAsyncScriptCompile(request);
if (NS_SUCCEEDED(rv)) {