зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1149235 part 2. Switch to using linked lists for nsScriptLoadRequest. r=sicking
This commit is contained in:
Родитель
10ff4f3739
Коммит
c932d1e3d9
|
@ -66,6 +66,35 @@ using namespace mozilla::dom;
|
|||
// context, but it will AddRef and Release it on other threads.
|
||||
NS_IMPL_ISUPPORTS0(nsScriptLoadRequest)
|
||||
|
||||
nsScriptLoadRequestList::~nsScriptLoadRequestList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsScriptLoadRequestList::Clear()
|
||||
{
|
||||
while (!isEmpty()) {
|
||||
nsRefPtr<nsScriptLoadRequest> first = StealFirst();
|
||||
// And just let it go out of scope and die.
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
nsScriptLoadRequestList::Contains(nsScriptLoadRequest* aElem)
|
||||
{
|
||||
for (nsScriptLoadRequest* req = getFirst();
|
||||
req; req = req->getNext()) {
|
||||
if (req == aElem) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
@ -93,20 +122,25 @@ nsScriptLoader::~nsScriptLoader()
|
|||
mParserBlockingRequest->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mXSLTRequests.Length(); i++) {
|
||||
mXSLTRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
for (nsScriptLoadRequest* req = mXSLTRequests.getFirst(); req;
|
||||
req = req->getNext()) {
|
||||
req->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mDeferRequests.Length(); i++) {
|
||||
mDeferRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
for (nsScriptLoadRequest* req = mDeferRequests.getFirst(); req;
|
||||
req = req->getNext()) {
|
||||
req->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mAsyncRequests.Length(); i++) {
|
||||
mAsyncRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
for (nsScriptLoadRequest* req = mAsyncRequests.getFirst(); req;
|
||||
req = req->getNext()) {
|
||||
req->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mNonAsyncExternalScriptInsertedRequests.Length(); i++) {
|
||||
mNonAsyncExternalScriptInsertedRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
for(nsScriptLoadRequest* req = mNonAsyncExternalScriptInsertedRequests.getFirst();
|
||||
req;
|
||||
req = req->getNext()) {
|
||||
req->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
// Unblock the kids, in case any of them moved to a different document
|
||||
|
@ -591,6 +625,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
request->mJSVersion = version;
|
||||
|
||||
if (aElement->GetScriptAsync()) {
|
||||
request->mIsAsync = true;
|
||||
mAsyncRequests.AppendElement(request);
|
||||
if (!request->mLoading) {
|
||||
// The script is available already. Run it ASAP when the event
|
||||
|
@ -603,6 +638,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
// Violate the HTML5 spec in order to make LABjs and the "order" plug-in
|
||||
// for RequireJS work with their Gecko-sniffed code path. See
|
||||
// http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
|
||||
request->mIsNonAsyncScriptInserted = true;
|
||||
mNonAsyncExternalScriptInsertedRequests.AppendElement(request);
|
||||
if (!request->mLoading) {
|
||||
// The script is available already. Run it ASAP when the event
|
||||
|
@ -631,6 +667,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
// Need to maintain order for XSLT-inserted scripts
|
||||
NS_ASSERTION(!mParserBlockingRequest,
|
||||
"Parser-blocking scripts and XSLT scripts in the same doc!");
|
||||
request->mIsXSLT = true;
|
||||
mXSLTRequests.AppendElement(request);
|
||||
if (!request->mLoading) {
|
||||
// The script is available already. Run it ASAP when the event
|
||||
|
@ -651,7 +688,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
// Web page.
|
||||
NS_ASSERTION(!mParserBlockingRequest,
|
||||
"There can be only one parser-blocking script at a time");
|
||||
NS_ASSERTION(mXSLTRequests.IsEmpty(),
|
||||
NS_ASSERTION(mXSLTRequests.isEmpty(),
|
||||
"Parser-blocking scripts and XSLT scripts in the same doc!");
|
||||
mParserBlockingRequest = request;
|
||||
ProcessPendingRequestsAsync();
|
||||
|
@ -661,7 +698,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
// The script will be run when it loads or the style sheet loads.
|
||||
NS_ASSERTION(!mParserBlockingRequest,
|
||||
"There can be only one parser-blocking script at a time");
|
||||
NS_ASSERTION(mXSLTRequests.IsEmpty(),
|
||||
NS_ASSERTION(mXSLTRequests.isEmpty(),
|
||||
"Parser-blocking scripts and XSLT scripts in the same doc!");
|
||||
mParserBlockingRequest = request;
|
||||
return true;
|
||||
|
@ -687,7 +724,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
request->mLineNo = aElement->GetScriptLineNumber();
|
||||
|
||||
if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
|
||||
(!ReadyToExecuteScripts() || !mXSLTRequests.IsEmpty())) {
|
||||
(!ReadyToExecuteScripts() || !mXSLTRequests.isEmpty())) {
|
||||
// Need to maintain order for XSLT-inserted scripts
|
||||
NS_ASSERTION(!mParserBlockingRequest,
|
||||
"Parser-blocking scripts and XSLT scripts in the same doc!");
|
||||
|
@ -706,7 +743,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
NS_ASSERTION(!mParserBlockingRequest,
|
||||
"There can be only one parser-blocking script at a time");
|
||||
mParserBlockingRequest = request;
|
||||
NS_ASSERTION(mXSLTRequests.IsEmpty(),
|
||||
NS_ASSERTION(mXSLTRequests.isEmpty(),
|
||||
"Parser-blocking scripts and XSLT scripts in the same doc!");
|
||||
return true;
|
||||
}
|
||||
|
@ -1134,39 +1171,39 @@ nsScriptLoader::ProcessPendingRequests()
|
|||
}
|
||||
|
||||
while (ReadyToExecuteScripts() &&
|
||||
!mXSLTRequests.IsEmpty() &&
|
||||
!mXSLTRequests[0]->mLoading) {
|
||||
request.swap(mXSLTRequests[0]);
|
||||
mXSLTRequests.RemoveElementAt(0);
|
||||
!mXSLTRequests.isEmpty() &&
|
||||
!mXSLTRequests.getFirst()->mLoading) {
|
||||
request = mXSLTRequests.StealFirst();
|
||||
ProcessRequest(request);
|
||||
}
|
||||
|
||||
uint32_t i = 0;
|
||||
while (mEnabled && i < mAsyncRequests.Length()) {
|
||||
if (!mAsyncRequests[i]->mLoading) {
|
||||
request.swap(mAsyncRequests[i]);
|
||||
mAsyncRequests.RemoveElementAt(i);
|
||||
// The refcounting here is dumb, but it's going away in the next
|
||||
// patch in the queue.
|
||||
nsRefPtr<nsScriptLoadRequest> req = mAsyncRequests.getFirst();
|
||||
while (mEnabled && req && req->isInList()) {
|
||||
if (!req->mLoading) {
|
||||
nsRefPtr<nsScriptLoadRequest> next = req->getNext();
|
||||
request = mAsyncRequests.Steal(req);
|
||||
ProcessRequest(request);
|
||||
req.swap(next);
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
req = req->getNext();
|
||||
}
|
||||
|
||||
while (mEnabled && !mNonAsyncExternalScriptInsertedRequests.IsEmpty() &&
|
||||
!mNonAsyncExternalScriptInsertedRequests[0]->mLoading) {
|
||||
while (mEnabled && !mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
|
||||
!mNonAsyncExternalScriptInsertedRequests.getFirst()->mLoading) {
|
||||
// Violate the HTML5 spec and execute these in the insertion order in
|
||||
// order to make LABjs and the "order" plug-in for RequireJS work with
|
||||
// their Gecko-sniffed code path. See
|
||||
// http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
|
||||
request.swap(mNonAsyncExternalScriptInsertedRequests[0]);
|
||||
mNonAsyncExternalScriptInsertedRequests.RemoveElementAt(0);
|
||||
request = mNonAsyncExternalScriptInsertedRequests.StealFirst();
|
||||
ProcessRequest(request);
|
||||
}
|
||||
|
||||
if (mDocumentParsingDone && mXSLTRequests.IsEmpty()) {
|
||||
while (!mDeferRequests.IsEmpty() && !mDeferRequests[0]->mLoading) {
|
||||
request.swap(mDeferRequests[0]);
|
||||
mDeferRequests.RemoveElementAt(0);
|
||||
if (mDocumentParsingDone && mXSLTRequests.isEmpty()) {
|
||||
while (!mDeferRequests.isEmpty() && !mDeferRequests.getFirst()->mLoading) {
|
||||
request = mDeferRequests.StealFirst();
|
||||
ProcessRequest(request);
|
||||
}
|
||||
}
|
||||
|
@ -1178,9 +1215,9 @@ nsScriptLoader::ProcessPendingRequests()
|
|||
}
|
||||
|
||||
if (mDocumentParsingDone && mDocument &&
|
||||
!mParserBlockingRequest && mAsyncRequests.IsEmpty() &&
|
||||
mNonAsyncExternalScriptInsertedRequests.IsEmpty() &&
|
||||
mXSLTRequests.IsEmpty() && mDeferRequests.IsEmpty()) {
|
||||
!mParserBlockingRequest && mAsyncRequests.isEmpty() &&
|
||||
mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
|
||||
mXSLTRequests.isEmpty() && mDeferRequests.isEmpty()) {
|
||||
if (MaybeRemovedDeferRequests()) {
|
||||
return ProcessPendingRequests();
|
||||
}
|
||||
|
@ -1386,11 +1423,27 @@ nsScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
|
|||
mDocument->AddBlockedTrackingNode(cont);
|
||||
}
|
||||
|
||||
if (mDeferRequests.RemoveElement(request) ||
|
||||
mAsyncRequests.RemoveElement(request) ||
|
||||
mNonAsyncExternalScriptInsertedRequests.RemoveElement(request) ||
|
||||
mXSLTRequests.RemoveElement(request)) {
|
||||
FireScriptAvailable(rv, request);
|
||||
if (request->mIsDefer) {
|
||||
if (request->isInList()) {
|
||||
nsRefPtr<nsScriptLoadRequest> req = mDeferRequests.Steal(request);
|
||||
FireScriptAvailable(rv, req);
|
||||
}
|
||||
} else if (request->mIsAsync) {
|
||||
if (request->isInList()) {
|
||||
nsRefPtr<nsScriptLoadRequest> req = mAsyncRequests.Steal(request);
|
||||
FireScriptAvailable(rv, req);
|
||||
}
|
||||
} else if (request->mIsNonAsyncScriptInserted) {
|
||||
if (request->isInList()) {
|
||||
nsRefPtr<nsScriptLoadRequest> req =
|
||||
mNonAsyncExternalScriptInsertedRequests.Steal(request);
|
||||
FireScriptAvailable(rv, req);
|
||||
}
|
||||
} else if (request->mIsXSLT) {
|
||||
if (request->isInList()) {
|
||||
nsRefPtr<nsScriptLoadRequest> req = mXSLTRequests.Steal(request);
|
||||
FireScriptAvailable(rv, req);
|
||||
}
|
||||
} else if (mParserBlockingRequest == request) {
|
||||
mParserBlockingRequest = nullptr;
|
||||
UnblockParser(request);
|
||||
|
@ -1562,9 +1615,10 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
|||
void
|
||||
nsScriptLoader::AddDeferRequest(nsScriptLoadRequest* aRequest)
|
||||
{
|
||||
aRequest->mIsDefer = true;
|
||||
mDeferRequests.AppendElement(aRequest);
|
||||
if (mDeferEnabled && mDeferRequests.Length() == 1 && mDocument &&
|
||||
!mBlockingDOMContentLoaded) {
|
||||
if (mDeferEnabled && aRequest == mDeferRequests.getFirst() &&
|
||||
mDocument && !mBlockingDOMContentLoaded) {
|
||||
MOZ_ASSERT(mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_LOADING);
|
||||
mBlockingDOMContentLoaded = true;
|
||||
mDocument->BlockDOMContentLoaded();
|
||||
|
@ -1574,7 +1628,7 @@ nsScriptLoader::AddDeferRequest(nsScriptLoadRequest* aRequest)
|
|||
bool
|
||||
nsScriptLoader::MaybeRemovedDeferRequests()
|
||||
{
|
||||
if (mDeferRequests.Length() == 0 && mDocument &&
|
||||
if (mDeferRequests.isEmpty() && mDocument &&
|
||||
mBlockingDOMContentLoaded) {
|
||||
mBlockingDOMContentLoaded = false;
|
||||
mDocument->UnblockDOMContentLoaded();
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
#include "nsIDocument.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
|
||||
class nsScriptLoadRequest;
|
||||
class nsScriptLoadRequestList;
|
||||
class nsIURI;
|
||||
|
||||
namespace JS {
|
||||
|
@ -37,12 +38,20 @@ class AutoJSAPI;
|
|||
// Per-request data structure
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class nsScriptLoadRequest final : public nsISupports {
|
||||
class nsScriptLoadRequest final : public nsISupports,
|
||||
private mozilla::LinkedListElement<nsScriptLoadRequest>
|
||||
{
|
||||
~nsScriptLoadRequest()
|
||||
{
|
||||
js_free(mScriptTextBuf);
|
||||
}
|
||||
|
||||
typedef LinkedListElement<nsScriptLoadRequest> super;
|
||||
|
||||
// Allow LinkedListElement<nsScriptLoadRequest> to cast us to itself as needed.
|
||||
friend class mozilla::LinkedListElement<nsScriptLoadRequest>;
|
||||
friend class nsScriptLoadRequestList;
|
||||
|
||||
public:
|
||||
nsScriptLoadRequest(nsIScriptElement* aElement,
|
||||
uint32_t aVersion,
|
||||
|
@ -51,6 +60,10 @@ public:
|
|||
mLoading(true),
|
||||
mIsInline(true),
|
||||
mHasSourceMapURL(false),
|
||||
mIsDefer(false),
|
||||
mIsAsync(false),
|
||||
mIsNonAsyncScriptInserted(false),
|
||||
mIsXSLT(false),
|
||||
mScriptTextBuf(nullptr),
|
||||
mScriptTextLength(0),
|
||||
mJSVersion(aVersion),
|
||||
|
@ -76,10 +89,17 @@ public:
|
|||
return mElement == nullptr;
|
||||
}
|
||||
|
||||
using super::getNext;
|
||||
using super::isInList;
|
||||
|
||||
nsCOMPtr<nsIScriptElement> mElement;
|
||||
bool mLoading; // Are we still waiting for a load to complete?
|
||||
bool mIsInline; // Is the script inline or loaded?
|
||||
bool mHasSourceMapURL; // Does the HTTP header have a source map url?
|
||||
bool mIsDefer; // True if we live in mDeferRequests.
|
||||
bool mIsAsync; // True if we live in mAsyncRequests.
|
||||
bool mIsNonAsyncScriptInserted; // True if we live in mNonAsyncExternalScriptInsertedRequests
|
||||
bool mIsXSLT; // True if we live in mXSLTRequests.
|
||||
nsString mSourceMapURL; // Holds source map url for loaded scripts
|
||||
char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
|
||||
size_t mScriptTextLength; // use nsString so we can give ownership to jsapi.
|
||||
|
@ -92,6 +112,44 @@ public:
|
|||
mozilla::net::ReferrerPolicy mReferrerPolicy;
|
||||
};
|
||||
|
||||
class nsScriptLoadRequestList : private mozilla::LinkedList<nsScriptLoadRequest>
|
||||
{
|
||||
typedef mozilla::LinkedList<nsScriptLoadRequest> super;
|
||||
|
||||
public:
|
||||
~nsScriptLoadRequestList();
|
||||
|
||||
void Clear();
|
||||
|
||||
#ifdef DEBUG
|
||||
bool Contains(nsScriptLoadRequest* aElem);
|
||||
#endif // DEBUG
|
||||
|
||||
using super::getFirst;
|
||||
using super::isEmpty;
|
||||
|
||||
void AppendElement(nsScriptLoadRequest* aElem)
|
||||
{
|
||||
MOZ_ASSERT(!aElem->isInList());
|
||||
NS_ADDREF(aElem);
|
||||
insertBack(aElem);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
already_AddRefed<nsScriptLoadRequest> Steal(nsScriptLoadRequest* aElem)
|
||||
{
|
||||
aElem->removeFrom(*this);
|
||||
return dont_AddRef(aElem);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
already_AddRefed<nsScriptLoadRequest> StealFirst()
|
||||
{
|
||||
MOZ_ASSERT(!isEmpty());
|
||||
return Steal(getFirst());
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Script loader implementation
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
@ -396,10 +454,10 @@ private:
|
|||
|
||||
nsIDocument* mDocument; // [WEAK]
|
||||
nsCOMArray<nsIScriptLoaderObserver> mObservers;
|
||||
nsTArray<nsRefPtr<nsScriptLoadRequest> > mNonAsyncExternalScriptInsertedRequests;
|
||||
nsTArray<nsRefPtr<nsScriptLoadRequest> > mAsyncRequests;
|
||||
nsTArray<nsRefPtr<nsScriptLoadRequest> > mDeferRequests;
|
||||
nsTArray<nsRefPtr<nsScriptLoadRequest> > mXSLTRequests;
|
||||
nsScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests;
|
||||
nsScriptLoadRequestList mAsyncRequests;
|
||||
nsScriptLoadRequestList mDeferRequests;
|
||||
nsScriptLoadRequestList mXSLTRequests;
|
||||
nsRefPtr<nsScriptLoadRequest> mParserBlockingRequest;
|
||||
|
||||
// In mRequests, the additional information here is stored by the element.
|
||||
|
|
Загрузка…
Ссылка в новой задаче