Bug 1404897: Allow storing Servo selector lists in the document's selector cache. r=heycam

MozReview-Commit-ID: GtIWGN2zEGT

--HG--
extra : rebase_source : 90d4a61bcc65995ca8a130cd24582e4f20d52276
This commit is contained in:
Emilio Cobos Álvarez 2017-10-02 15:32:07 +02:00
Родитель 76571cb8eb
Коммит c3d21f55ab
3 изменённых файлов: 122 добавлений и 14 удалений

Просмотреть файл

@ -1406,13 +1406,39 @@ nsIDocument::SelectorCache::~SelectorCache()
AgeAllGenerations();
}
void
nsIDocument::SelectorCache::SelectorList::Reset()
{
if (mIsServo) {
if (mServo) {
Servo_SelectorList_Drop(mServo);
mServo = nullptr;
}
} else {
if (mGecko) {
delete mGecko;
mGecko = nullptr;
}
}
}
// CacheList takes ownership of aSelectorList.
void nsIDocument::SelectorCache::CacheList(const nsAString& aSelector,
nsCSSSelectorList* aSelectorList)
mozilla::UniquePtr<nsCSSSelectorList>&& aSelectorList)
{
MOZ_ASSERT(NS_IsMainThread());
SelectorCacheKey* key = new SelectorCacheKey(aSelector);
mTable.Put(key->mKey, aSelectorList);
mTable.Put(key->mKey, SelectorList(Move(aSelectorList)));
AddObject(key);
}
void nsIDocument::SelectorCache::CacheList(
const nsAString& aSelector,
UniquePtr<RawServoSelectorList>&& aSelectorList)
{
MOZ_ASSERT(NS_IsMainThread());
SelectorCacheKey* key = new SelectorCacheKey(aSelector);
mTable.Put(key->mKey, SelectorList(Move(aSelectorList)));
AddObject(key);
}

Просмотреть файл

@ -37,6 +37,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/NotNull.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/StyleBackendType.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/TimeStamp.h"
@ -1148,27 +1149,106 @@ public:
: public nsExpirationTracker<SelectorCacheKey, 4>
{
public:
class SelectorList
{
public:
SelectorList()
: mIsServo(false)
, mGecko(nullptr)
{}
SelectorList(SelectorList&& aOther)
{
*this = mozilla::Move(aOther);
}
SelectorList& operator=(SelectorList&& aOther)
{
Reset();
mIsServo = aOther.mIsServo;
if (mIsServo) {
mServo = aOther.mServo;
aOther.mServo = nullptr;
} else {
mGecko = aOther.mGecko;
aOther.mGecko = nullptr;
}
return *this;
}
SelectorList(const SelectorList& aOther) = delete;
explicit SelectorList(mozilla::UniquePtr<RawServoSelectorList>&& aList)
: mIsServo(true)
, mServo(aList.release())
{}
explicit SelectorList(mozilla::UniquePtr<nsCSSSelectorList>&& aList)
: mIsServo(false)
, mGecko(aList.release())
{}
~SelectorList() {
Reset();
}
bool IsServo() const { return mIsServo; }
bool IsGecko() const { return !IsServo(); }
explicit operator bool() const
{
return IsServo() ? !!AsServo() : !!AsGecko();
}
nsCSSSelectorList* AsGecko() const
{
MOZ_ASSERT(IsGecko());
return mGecko;
}
RawServoSelectorList* AsServo() const
{
MOZ_ASSERT(IsServo());
return mServo;
}
private:
void Reset();
bool mIsServo;
union {
nsCSSSelectorList* mGecko;
RawServoSelectorList* mServo;
};
};
explicit SelectorCache(nsIEventTarget* aEventTarget);
// CacheList takes ownership of aSelectorList.
void CacheList(const nsAString& aSelector, nsCSSSelectorList* aSelectorList);
void CacheList(const nsAString& aSelector,
mozilla::UniquePtr<nsCSSSelectorList>&& aSelectorList);
void CacheList(const nsAString& aSelector,
mozilla::UniquePtr<RawServoSelectorList>&& aSelectorList);
virtual void NotifyExpired(SelectorCacheKey* aSelector) override;
// We do not call MarkUsed because it would just slow down lookups and
// because we're OK expiring things after a few seconds even if they're
// being used. Returns whether we actually had an entry for aSelector.
// If we have an entry and *aList is null, that indicates that aSelector
//
// If we have an entry and the selector list returned has a null
// nsCSSSelectorList*/RawServoSelectorList*, that indicates that aSelector
// has already been parsed and is not a syntactically valid selector.
bool GetList(const nsAString& aSelector, nsCSSSelectorList** aList)
SelectorList* GetList(const nsAString& aSelector)
{
return mTable.Get(aSelector, aList);
return mTable.GetValue(aSelector);
}
~SelectorCache();
private:
nsClassHashtable<nsStringHashKey, nsCSSSelectorList> mTable;
nsDataHashtable<nsStringHashKey, SelectorList> mTable;
};
SelectorCache& GetSelectorCache() {

Просмотреть файл

@ -2682,21 +2682,23 @@ nsINode::ParseSelectorList(const nsAString& aSelectorString,
{
nsIDocument* doc = OwnerDoc();
nsIDocument::SelectorCache& cache = doc->GetSelectorCache();
nsCSSSelectorList* selectorList = nullptr;
bool haveCachedList = cache.GetList(aSelectorString, &selectorList);
if (haveCachedList) {
if (!selectorList) {
nsIDocument::SelectorCache::SelectorList* list =
cache.GetList(aSelectorString);
if (list) {
if (!*list) {
// Invalid selector.
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
NS_LITERAL_CSTRING("'") + NS_ConvertUTF16toUTF8(aSelectorString) +
NS_LITERAL_CSTRING("' is not a valid selector")
);
}
return selectorList;
MOZ_ASSERT(list->IsGecko(), "We haven't done anything with Servo yet");
return list->AsGecko();
}
nsCSSParser parser(doc->CSSLoader());
nsCSSSelectorList* selectorList = nullptr;
aRv = parser.ParseSelectorString(aSelectorString,
doc->GetDocumentURI(),
0, // XXXbz get the line number!
@ -2714,7 +2716,7 @@ nsINode::ParseSelectorList(const nsAString& aSelectorString,
NS_LITERAL_CSTRING("' is not a valid selector")
);
cache.CacheList(aSelectorString, nullptr);
cache.CacheList(aSelectorString, UniquePtr<nsCSSSelectorList>());
return nullptr;
}
@ -2734,7 +2736,7 @@ nsINode::ParseSelectorList(const nsAString& aSelectorString,
if (selectorList) {
NS_ASSERTION(selectorList->mSelectors,
"How can we not have any selectors?");
cache.CacheList(aSelectorString, selectorList);
cache.CacheList(aSelectorString, UniquePtr<nsCSSSelectorList>(selectorList));
} else {
// This is the "only pseudo-element selectors" case, which is
// not common, so just don't worry about caching it. That way a