Complete implement module type scripting.

master
Fedor 2020-09-17 08:54:29 +03:00
parent a9f2350492
commit f99c131db1
15 changed files with 879 additions and 755 deletions

View File

@ -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

View File

@ -56,7 +56,7 @@ public:
ModuleLoadRequest(nsIURI* aURI,
ModuleLoadRequest* aParent);
bool IsTopLevel() const {
bool IsTopLevel() const override {
return mIsTopLevel;
}

View File

@ -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> 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<JS::Value> 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<JS::Value> 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<ScriptLoadRequest> 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<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);
@ -2576,13 +2625,15 @@ ScriptLoader::ParsingComplete(bool aTerminated)
}
void
ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
ScriptLoader::PreloadURI(nsIURI *aURI,
const nsAString &aCharset,
const nsAString &aType,
const nsAString &aCrossOrigin,
const nsAString& aIntegrity,
bool aScriptFromHead,
bool aAsync,
bool aDefer,
bool aNoModule,
const mozilla::net::ReferrerPolicy aReferrerPolicy)
{
NS_ENSURE_TRUE_VOID(mDocument);
@ -2591,8 +2642,28 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
return;
}
// TODO: Preload module scripts.
if (mDocument->ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) {
ScriptKind scriptKind = ScriptKind::Classic;
if (mDocument->ModuleScriptsEnabled()) {
// Don't load nomodule scripts.
if (aNoModule) {
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;
}
@ -2609,7 +2680,7 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
}
RefPtr<ScriptLoadRequest> request =
CreateLoadRequest(ScriptKind::Classic, aURI, nullptr, 0,
CreateLoadRequest(scriptKind, aURI, nullptr, 0,
Element::StringToCORSMode(aCrossOrigin), sriMetadata,
aReferrerPolicy);
request->mIsInline = false;

View File

@ -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;
@ -479,13 +485,15 @@ public:
* @param aIntegrity The expect hash url, if avail, of the request
* @param aScriptFromHead Whether or not the script was a child of head
*/
virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
virtual void PreloadURI(nsIURI *aURI,
const nsAString &aCharset,
const nsAString &aType,
const nsAString &aCrossOrigin,
const nsAString& aIntegrity,
bool aScriptFromHead,
bool aAsync,
bool aDefer,
bool aNoModule,
const mozilla::net::ReferrerPolicy aReferrerPolicy);
/**
@ -498,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();

View File

@ -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<ModuleObject>());
}
@ -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<ModuleObject>());
}
@ -6204,7 +6204,7 @@ JS_SetPendingException(JSContext* cx, HandleValue value)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, value);
releaseAssertSameCompartment(cx, value);
cx->setPendingException(value);
}

View File

@ -446,6 +446,7 @@ HTML5_ATOM(lquote, "lquote")
HTML5_ATOM(panose_1, "panose-1")
HTML5_ATOM(numoctaves, "numoctaves")
HTML5_ATOM(numOctaves, "numOctaves")
HTML5_ATOM(nomodule, "nomodule")
HTML5_ATOM(onload, "onload")
HTML5_ATOM(onbounce, "onbounce")
HTML5_ATOM(oncontrolselect, "oncontrolselect")

File diff suppressed because one or more lines are too long

View File

@ -563,6 +563,7 @@ class nsHtml5AttributeName
static nsHtml5AttributeName* ATTR_LQUOTE;
static nsHtml5AttributeName* ATTR_PANOSE_1;
static nsHtml5AttributeName* ATTR_NUMOCTAVES;
static nsHtml5AttributeName* ATTR_NOMODULE;
static nsHtml5AttributeName* ATTR_ONLOAD;
static nsHtml5AttributeName* ATTR_ONBOUNCE;
static nsHtml5AttributeName* ATTR_ONCONTROLSELECT;

View File

@ -52,17 +52,27 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
case eSpeculativeLoadScript:
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode,
mCrossOrigin, mIntegrity, false,
mIsAsync, mIsDefer);
mIsAsync, mIsDefer, false);
break;
case eSpeculativeLoadScriptFromHead:
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode,
mCrossOrigin, mIntegrity, true,
mIsAsync, mIsDefer);
mIsAsync, mIsDefer, false);
break;
case eSpeculativeLoadNoModuleScript:
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode,
mCrossOrigin, mIntegrity, false,
mIsAsync, mIsDefer, true);
break;
case eSpeculativeLoadNoModuleScriptFromHead:
aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode,
mCrossOrigin, mIntegrity, true,
mIsAsync, mIsDefer, true);
break;
case eSpeculativeLoadStyle:
aExecutor->PreloadStyle(mUrl, mCharset, mCrossOrigin, mIntegrity);
break;
case eSpeculativeLoadManifest:
case eSpeculativeLoadManifest:
aExecutor->ProcessOfflineManifest(mUrl);
break;
case eSpeculativeLoadSetDocumentCharset: {

View File

@ -10,7 +10,8 @@
class nsHtml5TreeOpExecutor;
enum eHtml5SpeculativeLoad {
enum eHtml5SpeculativeLoad
{
#ifdef DEBUG
eSpeculativeLoadUninitialized,
#endif
@ -23,6 +24,8 @@ enum eHtml5SpeculativeLoad {
eSpeculativeLoadPictureSource,
eSpeculativeLoadScript,
eSpeculativeLoadScriptFromHead,
eSpeculativeLoadNoModuleScript,
eSpeculativeLoadNoModuleScriptFromHead,
eSpeculativeLoadStyle,
eSpeculativeLoadManifest,
eSpeculativeLoadSetDocumentCharset,
@ -130,12 +133,18 @@ class nsHtml5SpeculativeLoad {
nsHtml5String aIntegrity,
bool aParserInHead,
bool aAsync,
bool aDefer)
bool aDefer,
bool aNoModule)
{
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
"Trying to reinitialize a speculative load!");
mOpCode = aParserInHead ?
eSpeculativeLoadScriptFromHead : eSpeculativeLoadScript;
if (aNoModule) {
mOpCode = aParserInHead ? eSpeculativeLoadNoModuleScriptFromHead
: eSpeculativeLoadNoModuleScript;
} else {
mOpCode = aParserInHead ? eSpeculativeLoadScriptFromHead
: eSpeculativeLoadScript;
}
aUrl.ToString(mUrl);
aCharset.ToString(mCharset);
aType.ToString(mTypeOrCharsetSourceOrDocumentMode);

View File

@ -189,6 +189,8 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace,
aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC);
bool defer =
aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
bool noModule =
aAttributes->contains(nsHtml5AttributeName::ATTR_NOMODULE);
mSpeculativeLoadQueue.AppendElement()->InitScript(
url,
charset,
@ -197,7 +199,8 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace,
integrity,
mode == nsHtml5TreeBuilder::IN_HEAD,
async,
defer);
defer,
noModule);
mCurrentHtmlScriptIsAsyncOrDefer = async || defer;
}
} else if (nsHtml5Atoms::link == aName) {
@ -303,7 +306,8 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace,
integrity,
mode == nsHtml5TreeBuilder::IN_HEAD,
false /* async */,
false /* defer */);
false /* defer */,
false /* noModule */);
}
} else if (nsHtml5Atoms::style == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();

View File

@ -923,14 +923,16 @@ nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL,
const nsAString& aIntegrity,
bool aScriptFromHead,
bool aAsync,
bool aDefer)
bool aDefer,
bool aNoModule)
{
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
if (!uri) {
return;
}
mDocument->ScriptLoader()->PreloadURI(uri, aCharset, aType, aCrossOrigin,
aIntegrity, aScriptFromHead, aAsync, aDefer,
aIntegrity, aScriptFromHead, aAsync,
aDefer, aNoModule,
mSpeculationReferrerPolicy);
}

View File

@ -251,7 +251,8 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder,
const nsAString& aIntegrity,
bool aScriptFromHead,
bool aAsync,
bool aDefer);
bool aDefer,
bool aNoModule);
void PreloadStyle(const nsAString& aURL, const nsAString& aCharset,
const nsAString& aCrossOrigin,

View File

@ -59,6 +59,7 @@ public:
typedef nsBaseHashtableET<KeyClass, DataType> EntryType;
using nsTHashtable<EntryType>::Contains;
using nsTHashtable<EntryType>::IsEmpty;
nsBaseHashtable() {}
explicit nsBaseHashtable(uint32_t aInitLength)