diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index f3cb096b9a..9d0b2c9bb8 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1471,6 +1471,9 @@ nsHTMLDocument::Open(JSContext* cx, // document again otherwise the document could have a non-zero onload block // count without the onload blocker request being in the loadgroup. EnsureOnloadBlocker(); + + // Throw away loaded modules created for the previous global. + ScriptLoader()->ClearModuleMap(); } // Step 8 - Clear all event listeners out of our DOM tree diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h index eefb7dad5f..4eac65090c 100644 --- a/dom/script/ModuleLoadRequest.h +++ b/dom/script/ModuleLoadRequest.h @@ -56,7 +56,7 @@ public: ModuleLoadRequest(nsIURI* aURI, ModuleLoadRequest* aParent); - bool IsTopLevel() const { + bool IsTopLevel() const override { return mIsTopLevel; } diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index 0052c72fe4..362c27f3e0 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -477,6 +477,11 @@ ScriptLoader::GetFetchedModule(nsIURI* aURL) const return ms; } +void ScriptLoader::ClearModuleMap() { + MOZ_ASSERT(mFetchingModules.IsEmpty()); + mFetchedModules.Clear(); +} + nsresult ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest) { @@ -559,7 +564,9 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest) rv = nsJSUtils::CompileModule(cx, srcBuf, global, options, &module); } } + MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr)); + RefPtr moduleScript = new ModuleScript(this, aRequest->mBaseURL); aRequest->mModuleScript = moduleScript; @@ -979,7 +986,7 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType, if (aRequest->IsModuleRequest()) { // Check whether the module has been fetched or is currently being fetched, - // and if so wait for it. + // and if so wait for it rather than starting a new fetch. ModuleLoadRequest* request = aRequest->AsModuleRequest(); if (ModuleMapContainsURL(request->mURI)) { WaitForModuleFetch(request->mURI) @@ -988,9 +995,6 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType, &ModuleLoadRequest::LoadFailed); return NS_OK; } - - // Otherwise put the URL in the module map and mark it as fetching. - SetModuleFetchStarted(request); } nsContentPolicyType contentPolicyType = aRequest->IsPreload() @@ -1103,7 +1107,16 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType, rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), handler); NS_ENSURE_SUCCESS(rv, rv); - return channel->AsyncOpen2(loader); + rv = channel->AsyncOpen2(loader); + NS_ENSURE_SUCCESS(rv, rv); + + if (aRequest->IsModuleRequest()) { + // We successfully started fetching a module so put its URL in the module + // map and mark it as fetching. + SetModuleFetchStarted(aRequest->AsModuleRequest()); + } + + return NS_OK; } bool @@ -1355,8 +1368,8 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) } } - // Should still be in loading stage of script. - NS_ASSERTION(!request->InCompilingStage(), + // Should still be in loading stage of script unless we're loading a module. + NS_ASSERTION(!request->InCompilingStage() || request->IsModuleRequest(), "Request should not yet be in compiling stage."); request->mJSVersion = version; @@ -1904,14 +1917,17 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, aOptions->setMutedErrors(!subsumes); } - JSContext* cx = jsapi.cx(); - JS::Rooted elementVal(cx); - MOZ_ASSERT(aRequest->mElement); - if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aRequest->mElement, - &elementVal, - /* aAllowWrapping = */ true))) { - MOZ_ASSERT(elementVal.isObject()); - aOptions->setElement(&elementVal.toObject()); + if (!aRequest->IsModuleRequest()) { + // Only do this for classic scripts. + JSContext* cx = jsapi.cx(); + JS::Rooted elementVal(cx); + MOZ_ASSERT(aRequest->mElement); + if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aRequest->mElement, + &elementVal, + /* aAllowWrapping = */ true))) { + MOZ_ASSERT(elementVal.isObject()); + aOptions->setElement(&elementVal.toObject()); + } } return NS_OK; @@ -2373,7 +2389,7 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) { RefPtr req = mXSLTRequests.Steal(aRequest); FireScriptAvailable(aResult, req); } - } else if (aRequest->IsModuleRequest()) { + } else if (aRequest->IsModuleRequest() && !aRequest->IsPreload()) { ModuleLoadRequest* modReq = aRequest->AsModuleRequest(); MOZ_ASSERT(!modReq->IsTopLevel()); MOZ_ASSERT(!modReq->isInList()); @@ -2394,8 +2410,19 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) { FireScriptAvailable(aResult, aRequest); ContinueParserAsync(aRequest); mCurrentParserInsertedScript = oldParserInsertedScript; + } else if (aRequest->IsPreload()) { + if (aRequest->IsModuleRequest()) { + // If there is an error preloading modules, cancel the load request. + aRequest->Cancel(); + } + if (aRequest->IsTopLevel()) { + MOZ_ALWAYS_TRUE(mPreloads.RemoveElement(aRequest, PreloadRequestComparator())); + } + MOZ_ASSERT(!aRequest->isInList()); } else { - mPreloads.RemoveElement(aRequest, PreloadRequestComparator()); + // This happens for blocking requests cancelled by ParsingComplete(). + MOZ_ASSERT(aRequest->IsCanceled()); + MOZ_ASSERT(!aRequest->isInList()); } } @@ -2424,6 +2451,18 @@ ScriptLoader::NumberOfProcessors() return mNumberOfProcessors; } +static bool +IsInternalURIScheme(nsIURI* uri) +{ + // Note: Extend this if other schemes need to be included. + bool isResource; + if (NS_SUCCEEDED(uri->SchemeIs("resource", &isResource)) && isResource) { + return true; + } + + return false; +} + nsresult ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest, nsIIncrementalStreamLoader* aLoader, @@ -2511,7 +2550,17 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest, return NS_ERROR_FAILURE; } - channel->GetURI(getter_AddRefs(request->mBaseURL)); + nsCOMPtr 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); @@ -2593,18 +2642,31 @@ ScriptLoader::PreloadURI(nsIURI *aURI, return; } + ScriptKind scriptKind = ScriptKind::Classic; + if (mDocument->ModuleScriptsEnabled()) { // Don't load nomodule scripts. if (aNoModule) { return; } - // TODO: Preload module scripts. - if (aType.LowerCaseEqualsASCII("module")) { - return; + // Preload module scripts. + static const char kASCIIWhitespace[] = "\t\n\f\r "; + + nsAutoString type(aType); + type.Trim(kASCIIWhitespace); + if (type.LowerCaseEqualsASCII("module")) { + scriptKind = ScriptKind::Module; } } + if (scriptKind == ScriptKind::Classic && + !aType.IsEmpty() && !nsContentUtils::IsJavascriptMIMEType(aType)) { + // Unknown type (not type = module and not type = JS MIME type). + // Don't load it. + return; + } + SRIMetadata sriMetadata; if (!aIntegrity.IsEmpty()) { MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, @@ -2618,7 +2680,7 @@ ScriptLoader::PreloadURI(nsIURI *aURI, } RefPtr request = - CreateLoadRequest(ScriptKind::Classic, aURI, nullptr, 0, + CreateLoadRequest(scriptKind, aURI, nullptr, 0, Element::StringToCORSMode(aCrossOrigin), sriMetadata, aReferrerPolicy); request->mIsInline = false; diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h index 20e76970f4..73f2a92589 100644 --- a/dom/script/ScriptLoader.h +++ b/dom/script/ScriptLoader.h @@ -173,6 +173,12 @@ public: return mScriptMode == ScriptMode::eAsync; } + virtual bool IsTopLevel() const + { + // Classic scripts are always top level. + return true; + } + void MaybeCancelOffThreadScript(); using super::getNext; @@ -500,6 +506,12 @@ public: return mPendingChildLoaders.AppendElement(aChild) != nullptr; } + /* + * Clear the map of loaded modules. Called when a Document object is reused + * for a different global. + */ + void ClearModuleMap(); + private: virtual ~ScriptLoader(); diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index bfcc8d20ef..d3001b69e4 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -1239,6 +1239,7 @@ static const JSFunctionSpec object_static_methods[] = { JS_FN("isFrozen", obj_isFrozen, 1, 0), JS_FN("seal", obj_seal, 1, 0), JS_FN("isSealed", obj_isSealed, 1, 0), + JS_SELF_HOSTED_FN("fromEntries", "ObjectFromEntries", 1, 0), JS_FS_END }; diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index 9ed1be0e12..c4739037e3 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -202,3 +202,21 @@ function ObjectLookupGetter(name) { // Step 3.d. (implicit) } + +// Stage 4 draft 2020-09-06 https://tc39.github.io/proposal-object-from-entries/ +// Object.fromEntries (iterable) +function ObjectFromEntries(iter) { + // We omit the usual step number comments here because they don't help. + // This implementation inlines AddEntriesFromIterator and + // CreateDataPropertyOnObject, so it looks more like the polyfill + // than the step-by-step spec algorithm. + const obj = {}; + + for (const pair of allowContentIter(iter)) { + if (!IsObject(pair)) + ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Object.fromEntries"); + _DefineDataProperty(obj, pair[0], pair[1]); + } + + return obj; +} diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 69a3ba2ac2..c0f0e61cc6 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4708,7 +4708,7 @@ JS::ModuleInstantiate(JSContext* cx, JS::HandleObject moduleArg) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, moduleArg); + releaseAssertSameCompartment(cx, moduleArg); return ModuleObject::Instantiate(cx, moduleArg.as()); } @@ -4717,7 +4717,7 @@ JS::ModuleEvaluate(JSContext* cx, JS::HandleObject moduleArg) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, moduleArg); + releaseAssertSameCompartment(cx, moduleArg); return ModuleObject::Evaluate(cx, moduleArg.as()); } @@ -6204,7 +6204,7 @@ JS_SetPendingException(JSContext* cx, HandleValue value) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, value); + releaseAssertSameCompartment(cx, value); cx->setPendingException(value); } diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index 38f3f447d8..d1cc3e26c5 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -190,9 +190,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 constructorProps(["setPrototypeOf", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "keys", "is", "defineProperty", "defineProperties", "create", "getOwnPropertyNames", "getOwnPropertySymbols", - "preventExtensions", "freeze", "isFrozen", "seal", + "preventExtensions", "freeze", "fromEntries", "isFrozen", "seal", "isSealed", "assign", "getPrototypeOf", "values", - "entries", "isExtensible"]) + "entries", "isExtensible"]); gPrototypeProperties['Array'] = ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push", "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf", diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd index b5086032c1..cd2ff803f8 100644 --- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd @@ -40,10 +40,6 @@ - - - - diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index 9576e9a3b4..2ca3898f17 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -809,15 +809,6 @@ var gViewController = { } }, -/* Plugincheck service is currently N/A for Pale Moon - cmd_pluginCheck: { - isEnabled: function cmd_pluginCheck_isEnabled() true, - doCommand: function cmd_pluginCheck_doCommand() { - openURL(Services.urlFormatter.formatURLPref("plugins.update.url")); - } - }, -*/ - cmd_toggleAutoUpdateDefault: { isEnabled: function cmd_toggleAutoUpdateDefault_isEnabled() true, doCommand: function cmd_toggleAutoUpdateDefault_doCommand() { @@ -3028,10 +3019,7 @@ var gDetailView = { "details.notification.outdated", [this._addon.name], 1 ); - var warningLink = document.getElementById("detail-warning-link"); - warningLink.value = gStrings.ext.GetStringFromName("details.notification.outdated.link"); - warningLink.href = Services.urlFormatter.formatURLPref("plugins.update.url"); - warningLink.hidden = false; + document.getElementById("detail-warning-link").hidden = true; } else if (this._addon.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) { this.node.setAttribute("notification", "error"); document.getElementById("detail-error").textContent = gStrings.ext.formatStringFromName( diff --git a/toolkit/mozapps/extensions/content/extensions.xml b/toolkit/mozapps/extensions/content/extensions.xml index 7c8fab723f..f74289a3d4 100644 --- a/toolkit/mozapps/extensions/content/extensions.xml +++ b/toolkit/mozapps/extensions/content/extensions.xml @@ -1329,9 +1329,7 @@ "notification.outdated", [this.mAddon.name], 1 ); - this._warningLink.value = gStrings.ext.GetStringFromName("notification.outdated.link"); - this._warningLink.href = Services.urlFormatter.formatURLPref("plugins.update.url"); - this._warningLink.hidden = false; + this._warningLink.hidden = true; this._warningBtn.hidden = true; } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) { this.setAttribute("notification", "error"); diff --git a/toolkit/mozapps/extensions/content/extensions.xul b/toolkit/mozapps/extensions/content/extensions.xul index 292ecf8d37..70ce55fa26 100644 --- a/toolkit/mozapps/extensions/content/extensions.xul +++ b/toolkit/mozapps/extensions/content/extensions.xul @@ -88,7 +88,6 @@ - @@ -355,15 +354,6 @@ -