Bug 1807017 - Consider to reuse the memory when nsHtml5Tokenizer::end() is called, r=hsivonen

Differential Revision: https://phabricator.services.mozilla.com/D201982
This commit is contained in:
Henri Sivonen 2024-03-27 21:56:22 +00:00
parent a38bf0da3c
commit 6d652d37f5
9 changed files with 138 additions and 9 deletions

View File

@ -511,6 +511,8 @@ public class Tokenizer implements Locator, Locator2 {
private boolean shouldSuspend;
private boolean keepBuffer;
protected boolean confident;
private int line;
@ -570,6 +572,7 @@ public class Tokenizer implements Locator, Locator2 {
this.systemIdentifier = null;
this.attributes = null;
this.shouldSuspend = false;
this.keepBuffer = false;
this.confident = false;
this.line = 0;
// CPPONLY: this.attributeLine = 0;
@ -632,6 +635,7 @@ public class Tokenizer implements Locator, Locator2 {
// CPPONLY: this.attributes = tokenHandler.HasBuilder() ? new HtmlAttributes(mappingLangToXmlLang) : null;
// CPPONLY: this.newAttributesEachTime = !tokenHandler.HasBuilder();
this.shouldSuspend = false;
this.keepBuffer = false;
this.confident = false;
this.line = 0;
// CPPONLY: this.attributeLine = 0;
@ -653,6 +657,18 @@ public class Tokenizer implements Locator, Locator2 {
// CPPONLY: return viewingXmlSource;
// CPPONLY: }
public void setKeepBuffer(boolean keepBuffer) {
this.keepBuffer = keepBuffer;
}
public boolean dropBufferIfLongerThan(int length) {
if (strBuf.length > length) {
strBuf = null;
return true;
}
return false;
}
// [NOCPP[
/**
@ -7225,7 +7241,9 @@ public class Tokenizer implements Locator, Locator2 {
}
public void end() throws SAXException {
strBuf = null;
if (!keepBuffer) {
strBuf = null;
}
doctypeName = null;
if (systemIdentifier != null) {
Portability.releaseString(systemIdentifier);
@ -7415,7 +7433,9 @@ public class Tokenizer implements Locator, Locator2 {
public void initializeWithoutStarting() throws SAXException {
confident = false;
strBuf = null;
if (!keepBuffer) {
strBuf = null;
}
line = 1;
// CPPONLY: attributeLine = 1;
// [NOCPP[

View File

@ -436,6 +436,8 @@ public abstract class TreeBuilder<T> implements TokenHandler,
private boolean allowDeclarativeShadowRoots = false;
private boolean keepBuffer = false;
// [NOCPP[
private boolean reportingDoctype = true;
@ -577,6 +579,18 @@ public abstract class TreeBuilder<T> implements TokenHandler,
// ]NOCPP]
public void setKeepBuffer(boolean keepBuffer) {
this.keepBuffer = keepBuffer;
}
public boolean dropBufferIfLongerThan(int length) {
if (charBuffer.length > length) {
charBuffer = null;
return true;
}
return false;
}
@SuppressWarnings("unchecked") public final void startTokenization(Tokenizer self) throws SAXException {
tokenizer = self;
stackNodes = new StackNode[64];
@ -598,7 +612,9 @@ public abstract class TreeBuilder<T> implements TokenHandler,
// ]NOCPP]
start(fragment);
charBufferLen = 0;
charBuffer = null;
if (!keepBuffer) {
charBuffer = null;
}
framesetOk = true;
if (fragment) {
T elt;
@ -1451,7 +1467,10 @@ public abstract class TreeBuilder<T> implements TokenHandler,
// [NOCPP[
idLocations.clear();
// ]NOCPP]
charBuffer = null;
if (!keepBuffer) {
charBuffer = null;
}
end();
}

View File

@ -20,9 +20,11 @@ nsHtml5StringParser::nsHtml5StringParser()
mTreeBuilder(new nsHtml5TreeBuilder(mBuilder)),
mTokenizer(new nsHtml5Tokenizer(mTreeBuilder.get(), false)) {
mTokenizer->setInterner(&mAtomTable);
mTokenizer->setKeepBuffer(true);
mTreeBuilder->setKeepBuffer(true);
}
nsHtml5StringParser::~nsHtml5StringParser() {}
nsHtml5StringParser::~nsHtml5StringParser() { ClearCaches(); }
nsresult nsHtml5StringParser::ParseFragment(
const nsAString& aSourceBuffer, nsIContent* aTargetNode,
@ -69,6 +71,31 @@ nsresult nsHtml5StringParser::ParseDocument(
aTargetDoc->AllowsDeclarativeShadowRoots());
}
void nsHtml5StringParser::ClearCaches() {
mTokenizer->dropBufferIfLongerThan(0);
mTreeBuilder->dropBufferIfLongerThan(0);
if (mCacheClearer) {
mCacheClearer->Disconnect();
mCacheClearer = nullptr;
}
}
void nsHtml5StringParser::TryCache() {
const int32_t kMaxBuffer = 1024 * 1024;
bool didDrop = mTokenizer->dropBufferIfLongerThan(kMaxBuffer);
didDrop |= mTreeBuilder->dropBufferIfLongerThan(kMaxBuffer);
if (didDrop) {
return;
}
if (!mCacheClearer) {
mCacheClearer = new CacheClearer(this);
nsCOMPtr<nsIRunnable> runnable = mCacheClearer.get();
NS_DispatchToMainThreadQueue(runnable.forget(),
mozilla::EventQueuePriority::Idle);
}
}
nsresult nsHtml5StringParser::Tokenize(const nsAString& aSourceBuffer,
Document* aDocument,
bool aScriptingEnabledForNoscriptParsing,
@ -109,8 +136,10 @@ nsresult nsHtml5StringParser::Tokenize(const nsAString& aSourceBuffer,
if (NS_SUCCEEDED(rv)) {
mTokenizer->eof();
}
mTokenizer->end();
mBuilder->Finish();
mAtomTable.Clear();
TryCache();
return rv;
}

View File

@ -67,6 +67,9 @@ class nsHtml5StringParser : public nsParserBase {
bool aScriptingEnabledForNoscriptParsing,
bool aDeclarativeShadowRootsAllowed);
void TryCache();
void ClearCaches();
/**
* The tree operation executor
*/
@ -86,6 +89,24 @@ class nsHtml5StringParser : public nsParserBase {
* The scoped atom table
*/
nsHtml5AtomTable mAtomTable;
class CacheClearer : public mozilla::Runnable {
public:
explicit CacheClearer(nsHtml5StringParser* aParser)
: Runnable("CacheClearer"), mParser(aParser) {}
NS_IMETHOD Run() {
if (mParser) {
mParser->ClearCaches();
}
return NS_OK;
}
void Disconnect() { mParser = nullptr; }
private:
nsHtml5StringParser* mParser;
};
RefPtr<CacheClearer> mCacheClearer;
};
#endif // nsHtml5StringParser_h

View File

@ -126,6 +126,7 @@ nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler,
: nullptr),
newAttributesEachTime(!tokenHandler->HasBuilder()),
shouldSuspend(false),
keepBuffer(false),
confident(false),
line(0),
attributeLine(0),
@ -146,6 +147,18 @@ void nsHtml5Tokenizer::initLocation(nsHtml5String newPublicId,
bool nsHtml5Tokenizer::isViewingXmlSource() { return viewingXmlSource; }
void nsHtml5Tokenizer::setKeepBuffer(bool keepBuffer) {
this->keepBuffer = keepBuffer;
}
bool nsHtml5Tokenizer::dropBufferIfLongerThan(int32_t length) {
if (strBuf.length > length) {
strBuf = nullptr;
return true;
}
return false;
}
void nsHtml5Tokenizer::setState(int32_t specialTokenizerState) {
this->stateSave = specialTokenizerState;
this->endTagExpectation = nullptr;
@ -5022,7 +5035,9 @@ void nsHtml5Tokenizer::emitOrAppendOne(const char16_t* val,
}
void nsHtml5Tokenizer::end() {
strBuf = nullptr;
if (!keepBuffer) {
strBuf = nullptr;
}
doctypeName = nullptr;
if (systemIdentifier) {
systemIdentifier.Release();
@ -5148,7 +5163,9 @@ void nsHtml5Tokenizer::loadState(nsHtml5Tokenizer* other) {
void nsHtml5Tokenizer::initializeWithoutStarting() {
confident = false;
strBuf = nullptr;
if (!keepBuffer) {
strBuf = nullptr;
}
line = 1;
attributeLine = 1;
resetToDataState();

View File

@ -308,6 +308,7 @@ class nsHtml5Tokenizer {
nsHtml5HtmlAttributes* attributes;
bool newAttributesEachTime;
bool shouldSuspend;
bool keepBuffer;
protected:
bool confident;
@ -323,6 +324,8 @@ class nsHtml5Tokenizer {
void setInterner(nsHtml5AtomTable* interner);
void initLocation(nsHtml5String newPublicId, nsHtml5String newSystemId);
bool isViewingXmlSource();
void setKeepBuffer(bool keepBuffer);
bool dropBufferIfLongerThan(int32_t length);
void setState(int32_t specialTokenizerState);
void setStateAndEndTagExpectation(int32_t specialTokenizerState,
nsHtml5ElementName* endTagExpectation);

View File

@ -100,6 +100,18 @@ static const char* const QUIRKY_PUBLIC_IDS_DATA[] = {
"-//webtechs//dtd mozilla html//"};
staticJArray<const char*, int32_t> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = {
QUIRKY_PUBLIC_IDS_DATA, MOZ_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA)};
void nsHtml5TreeBuilder::setKeepBuffer(bool keepBuffer) {
this->keepBuffer = keepBuffer;
}
bool nsHtml5TreeBuilder::dropBufferIfLongerThan(int32_t length) {
if (charBuffer.length > length) {
charBuffer = nullptr;
return true;
}
return false;
}
void nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) {
tokenizer = self;
stackNodes = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
@ -118,7 +130,9 @@ void nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) {
headPointer = nullptr;
start(fragment);
charBufferLen = 0;
charBuffer = nullptr;
if (!keepBuffer) {
charBuffer = nullptr;
}
framesetOk = true;
if (fragment) {
nsIContentHandle* elt;
@ -652,7 +666,9 @@ void nsHtml5TreeBuilder::endTokenization() {
stackNodesIdx = 0;
stackNodes = nullptr;
}
charBuffer = nullptr;
if (!keepBuffer) {
charBuffer = nullptr;
}
end();
}

View File

@ -315,6 +315,7 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState {
bool quirks;
bool forceNoQuirks;
bool allowDeclarativeShadowRoots;
bool keepBuffer;
inline nsHtml5ContentCreatorFunction htmlCreator(
mozilla::dom::HTMLContentCreatorFunction htmlCreator) {
nsHtml5ContentCreatorFunction creator;
@ -330,6 +331,8 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState {
}
public:
void setKeepBuffer(bool keepBuffer);
bool dropBufferIfLongerThan(int32_t length);
void startTokenization(nsHtml5Tokenizer* self);
void doctype(nsAtom* name, nsHtml5String publicIdentifier,
nsHtml5String systemIdentifier, bool forceQuirks);

View File

@ -42,6 +42,7 @@ nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder)
quirks(false),
forceNoQuirks(false),
allowDeclarativeShadowRoots(false),
keepBuffer(false),
mBuilder(aBuilder),
mViewSource(nullptr),
mOpSink(nullptr),