Diff
Modified: trunk/Source/WTF/ChangeLog (280192 => 280193)
--- trunk/Source/WTF/ChangeLog 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WTF/ChangeLog 2021-07-22 19:18:45 UTC (rev 280193)
@@ -1,3 +1,21 @@
+2021-07-22 Yusuke Suzuki <[email protected]>
+
+ Micro-optimize innerHTML
+ https://bugs.webkit.org/show_bug.cgi?id=228142
+
+ Reviewed by Simon Fraser.
+
+ * wtf/Vector.h:
+ (WTF::Malloc>::shrinkToBestFit): This shrinks the backing storage to "appropriate for the living Vector".
+ * wtf/text/AtomStringImpl.cpp:
+ (WTF::UCharBufferTranslator::equal): WTF::equal for String does not check hash. This is because computing hash is expensive
+ and we would like to avoid that if it is not necessary. But when inserting string into AtomStringTable, we can use hash value
+ since they must be already computed because of HashMap's requirement. So let's use it before calling WTF::equal.
+ (WTF::LCharBufferTranslator::equal):
+ (WTF::BufferFromStaticDataTranslator::equal):
+ * wtf/text/StringView.h:
+ (WTF::StringView::stripLeadingMatchedCharacters): Add this and use it in HTMLTreeBuilder.
+
2021-07-22 Alex Christensen <[email protected]>
XHR.send(Document) should replace mismatched surrogates with replacement character before sending
Modified: trunk/Source/WTF/wtf/Vector.h (280192 => 280193)
--- trunk/Source/WTF/wtf/Vector.h 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WTF/wtf/Vector.h 2021-07-22 19:18:45 UTC (rev 280193)
@@ -768,6 +768,10 @@
void shrinkCapacity(size_t newCapacity);
void shrinkToFit() { shrinkCapacity(size()); }
+ // "shrinkToBestFit()" shrinks the capacity to fix the current size, while leaving sufficient capacity for more items.
+ // The upperbound of the capacity is that which would result from calling expandCapacity() with the current size.
+ void shrinkToBestFit();
+
void clear() { shrinkCapacity(0); }
template<typename U = T> Vector<U> isolatedCopy() const &;
@@ -1258,6 +1262,15 @@
}
template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::shrinkToBestFit()
+{
+ size_t currentSize = size();
+ size_t newCapacity = currentSize ? std::max<size_t>(minCapacity, currentSize + currentSize / 4 + 1) : 0;
+ ASSERT(currentSize <= newCapacity);
+ shrinkCapacity(newCapacity);
+}
+
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
template<FailureAction action, typename U>
ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(const U* data, size_t dataSize)
{
Modified: trunk/Source/WTF/wtf/text/AtomStringImpl.cpp (280192 => 280193)
--- trunk/Source/WTF/wtf/text/AtomStringImpl.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WTF/wtf/text/AtomStringImpl.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -127,7 +127,10 @@
static bool equal(PackedPtr<StringImpl> const& str, const UCharBuffer& buf)
{
- return WTF::equal(str.get(), buf.characters, buf.length);
+ StringImpl* impl = str.get();
+ if (impl->existingHash() != buf.hash)
+ return false;
+ return WTF::equal(impl, buf.characters, buf.length);
}
static void translate(PackedPtr<StringImpl>& location, const UCharBuffer& buf, unsigned hash)
@@ -307,7 +310,10 @@
static bool equal(PackedPtr<StringImpl> const& str, const LCharBuffer& buf)
{
- return WTF::equal(str.get(), buf.characters, buf.length);
+ StringImpl* impl = str.get();
+ if (impl->existingHash() != buf.hash)
+ return false;
+ return WTF::equal(impl, buf.characters, buf.length);
}
static void translate(PackedPtr<StringImpl>& location, const LCharBuffer& buf, unsigned hash)
@@ -329,7 +335,10 @@
static bool equal(PackedPtr<StringImpl> const& str, const Buffer& buf)
{
- return WTF::equal(str.get(), buf.characters, buf.length);
+ StringImpl* impl = str.get();
+ if (impl->existingHash() != buf.hash)
+ return false;
+ return WTF::equal(impl, buf.characters, buf.length);
}
static void translate(PackedPtr<StringImpl>& location, const Buffer& buf, unsigned hash)
Modified: trunk/Source/WTF/wtf/text/StringView.h (280192 => 280193)
--- trunk/Source/WTF/wtf/text/StringView.h 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WTF/wtf/text/StringView.h 2021-07-22 19:18:45 UTC (rev 280193)
@@ -131,6 +131,8 @@
StringView right(unsigned length) const { return substring(this->length() - length, length); }
template<typename MatchedCharacterPredicate>
+ StringView stripLeadingMatchedCharacters(const MatchedCharacterPredicate&);
+ template<typename MatchedCharacterPredicate>
StringView stripLeadingAndTrailingMatchedCharacters(const MatchedCharacterPredicate&);
class SplitResult;
@@ -182,6 +184,9 @@
void initialize(const UChar*, unsigned length);
template<typename CharacterType, typename MatchedCharacterPredicate>
+ StringView stripLeadingMatchedCharacters(const CharacterType*, const MatchedCharacterPredicate&);
+
+ template<typename CharacterType, typename MatchedCharacterPredicate>
StringView stripLeadingAndTrailingMatchedCharacters(const CharacterType*, const MatchedCharacterPredicate&);
#if CHECK_STRINGVIEW_LIFETIME
@@ -1030,6 +1035,32 @@
}
template<typename CharacterType, typename MatchedCharacterPredicate>
+inline StringView StringView::stripLeadingMatchedCharacters(const CharacterType* characters, const MatchedCharacterPredicate& predicate)
+{
+ unsigned start = 0;
+ while (start < m_length && predicate(characters[start]))
+ ++start;
+
+ if (start == m_length)
+ return StringView::empty();
+
+ if (!start)
+ return *this;
+
+ StringView result(characters + start, m_length - start);
+ result.setUnderlyingString(*this);
+ return result;
+}
+
+template<typename MatchedCharacterPredicate>
+StringView StringView::stripLeadingMatchedCharacters(const MatchedCharacterPredicate& predicate)
+{
+ if (is8Bit())
+ return stripLeadingMatchedCharacters<LChar>(characters8(), predicate);
+ return stripLeadingMatchedCharacters<UChar>(characters16(), predicate);
+}
+
+template<typename CharacterType, typename MatchedCharacterPredicate>
inline StringView StringView::stripLeadingAndTrailingMatchedCharacters(const CharacterType* characters, const MatchedCharacterPredicate& predicate)
{
if (!m_length)
Modified: trunk/Source/WebCore/ChangeLog (280192 => 280193)
--- trunk/Source/WebCore/ChangeLog 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/ChangeLog 2021-07-22 19:18:45 UTC (rev 280193)
@@ -1,3 +1,75 @@
+2021-07-22 Yusuke Suzuki <[email protected]>
+
+ Micro-optimize innerHTML
+ https://bugs.webkit.org/show_bug.cgi?id=228142
+
+ Reviewed by Simon Fraser.
+
+ No behavior change.
+
+ This patch does some micro optimizations revealed by the profiler when running some of Speedometer2 tests which intensively use innerHTML.
+ This offers improvement in jQuery-TodoMVC and Vanilla-ES2015-Babel-Webpack-TodoMVC since both are super innerHTML heavy benchmarks.
+
+ ----------------------------------------------------------------------------------------------------------------------------------
+ | subtest | ms | ms | b / a | pValue (significance using False Discovery Rate) |
+ ----------------------------------------------------------------------------------------------------------------------------------
+ | Elm-TodoMVC |126.862500 |126.687500 |0.998621 | 0.673462 |
+ | VueJS-TodoMVC |27.775000 |27.645833 |0.995350 | 0.741588 |
+ | EmberJS-TodoMVC |129.350000 |129.129167 |0.998293 | 0.624196 |
+ | BackboneJS-TodoMVC |51.129167 |51.204167 |1.001467 | 0.716622 |
+ | Preact-TodoMVC |21.870833 |21.337500 |0.975614 | 0.217771 |
+ | AngularJS-TodoMVC |139.854167 |140.266667 |1.002950 | 0.489838 |
+ | Vanilla-ES2015-TodoMVC |69.229167 |68.895833 |0.995185 | 0.238772 |
+ | Inferno-TodoMVC |68.391667 |68.266667 |0.998172 | 0.762281 |
+ | Flight-TodoMVC |77.979167 |78.166667 |1.002404 | 0.710324 |
+ | Angular2-TypeScript-TodoMVC |39.741667 |39.966667 |1.005662 | 0.524123 |
+ | VanillaJS-TodoMVC |55.416667 |55.512500 |1.001729 | 0.781447 |
+ | jQuery-TodoMVC |268.812500 |266.966667 |0.993133 | 0.003384 (significant) |
+ | EmberJS-Debug-TodoMVC |345.383333 |345.662500 |1.000808 | 0.695259 |
+ | React-TodoMVC |90.679167 |90.179167 |0.994486 | 0.067477 |
+ | React-Redux-TodoMVC |152.691667 |152.687500 |0.999973 | 0.991207 |
+ | Vanilla-ES2015-Babel-Webpack-TodoMVC |66.487500 |65.729167 |0.988594 | 0.000118 (significant) |
+ ----------------------------------------------------------------------------------------------------------------------------------
+
+
+ a mean = 242.12319
+ b mean = 242.80485
+ pValue = 0.1992654128
+ (Bigger means are better.)
+ 1.003 times better
+ Results ARE NOT significant
+
+ * html/parser/HTMLConstructionSite.cpp:
+ (WebCore::HTMLConstructionSite::insertTextNode):
+ * html/parser/HTMLConstructionSite.h:
+ * html/parser/HTMLDocumentParser.cpp:
+ (WebCore::HTMLDocumentParser::pumpTokenizerLoop): We do not need to call `shrinkToBestFit` in fragment parsing case since
+ we will discard HTMLToken soon.
+ * html/parser/HTMLMetaCharsetParser.cpp:
+ (WebCore::HTMLMetaCharsetParser::checkForMetaCharset):
+ * html/parser/HTMLPreloadScanner.cpp:
+ (WebCore::HTMLPreloadScanner::scan):
+ * html/parser/HTMLToken.h:
+ (WebCore::HTMLToken::clear): We found that these `clear` calls cause performance problem according to the Instruments: we
+ repeatedly use this Vector, and we repeatedly allocate and deallocate this Vector unnecessarily. We use `resize(0)` instead
+ to avoid this allocation and deallocation.
+ (WebCore::HTMLToken::shrinkToBestFit): But HTMLToken is kept so long, so at some point, we would like to make backing storage
+ small. So, we add shrinkToBestFit and we call it only after finishing batching of HTMLToken processing.
+ (WebCore::HTMLToken::beginStartTag):
+ (WebCore::HTMLToken::beginEndTag):
+ * html/parser/HTMLTokenizer.h:
+ (WebCore::HTMLTokenizer::shrinkToBestFit):
+ * html/parser/HTMLTreeBuilder.cpp:
+ (WebCore::HTMLTreeBuilder::ExternalCharacterTokenBuffer::characterPredicate):
+ (WebCore::HTMLTreeBuilder::insertPhoneNumberLink):
+ (WebCore::HTMLTreeBuilder::linkifyPhoneNumbers):
+ (WebCore::HTMLTreeBuilder::processCharacterBuffer):
+ (WebCore::HTMLTreeBuilder::processCharacterBufferForInBody):
+ (WebCore::HTMLTreeBuilder::defaultForInTableText):
+ (WebCore::HTMLTreeBuilder::processTokenInForeignContent):
+ (WebCore::HTMLTreeBuilder::processFakeCharacters): Deleted. It is dead code before this patch.
+ * html/parser/HTMLTreeBuilder.h:
+
2021-07-22 Wenson Hsieh <[email protected]>
Rename EventHandler::m_textRecognitionHoverTimerFired()
Modified: trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -566,7 +566,7 @@
m_openElements.push(HTMLStackItem::create(WTFMove(element), WTFMove(token), namespaceURI));
}
-void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
+void HTMLConstructionSite::insertTextNode(String&& characters, WhitespaceMode whitespaceMode)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
task.parent = ¤tNode();
@@ -596,7 +596,7 @@
// If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil.
if (!textNode->length()) {
String substring = characters.substring(currentPosition);
- textNode = Text::create(task.parent->document(), shouldUseAtomString ? AtomString(substring).string() : substring);
+ textNode = Text::create(task.parent->document(), shouldUseAtomString ? AtomString(WTFMove(substring)).string() : substring);
}
currentPosition += textNode->length();
Modified: trunk/Source/WebCore/html/parser/HTMLConstructionSite.h (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLConstructionSite.h 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLConstructionSite.h 2021-07-22 19:18:45 UTC (rev 280193)
@@ -111,7 +111,7 @@
void insertHTMLBodyElement(AtomicHTMLToken&&);
void insertHTMLFormElement(AtomicHTMLToken&&, bool isDemoted = false);
void insertScriptElement(AtomicHTMLToken&&);
- void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown);
+ void insertTextNode(String&&, WhitespaceMode = WhitespaceUnknown);
void insertForeignElement(AtomicHTMLToken&&, const AtomString& namespaceURI);
void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken&&);
Modified: trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -43,7 +43,7 @@
#include "NavigationScheduler.h"
#include "ScriptElement.h"
#include "ThrowOnDynamicMarkupInsertionCountIncrementer.h"
-
+#include <wtf/Scope.h>
#include <wtf/SystemTracing.h>
namespace WebCore {
@@ -256,6 +256,11 @@
bool HTMLDocumentParser::pumpTokenizerLoop(SynchronousMode mode, bool parsingFragment, PumpSession& session)
{
+ auto scopeExit = makeScopeExit([&] {
+ if (!parsingFragment)
+ m_tokenizer.shrinkToBestFit();
+ });
+
do {
if (UNLIKELY(isWaitingForScripts())) {
if (mode == AllowYield && m_parserScheduler->shouldYieldBeforeExecutingScript(m_treeBuilder->scriptToProcess(), session))
Modified: trunk/Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -31,6 +31,7 @@
#include "HTMLParserIdioms.h"
#include "TextCodec.h"
#include "TextEncodingRegistry.h"
+#include <wtf/Scope.h>
namespace WebCore {
@@ -157,6 +158,10 @@
bool ignoredSawErrorFlag;
m_input.append(m_codec->decode(data, length, false, false, ignoredSawErrorFlag));
+ auto scopeExit = makeScopeExit([&] {
+ m_tokenizer.shrinkToBestFit();
+ });
+
while (auto token = m_tokenizer.nextToken(m_input)) {
bool isEnd = token->type() == HTMLToken::EndTag;
if (isEnd || token->type() == HTMLToken::StartTag) {
Modified: trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -514,6 +514,7 @@
m_tokenizer.updateStateFor(AtomString(token->name()));
m_scanner.scan(*token, requests, document);
}
+ m_tokenizer.shrinkToBestFit();
preloader.preload(WTFMove(requests));
}
Modified: trunk/Source/WebCore/html/parser/HTMLToken.h (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLToken.h 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLToken.h 2021-07-22 19:18:45 UTC (rev 280193)
@@ -68,6 +68,7 @@
HTMLToken();
void clear();
+ void shrinkToBestFit();
Type type() const;
@@ -170,10 +171,16 @@
inline void HTMLToken::clear()
{
m_type = Uninitialized;
- m_data.clear();
+ m_data.resize(0);
m_data8BitCheck = 0;
}
+inline void HTMLToken::shrinkToBestFit()
+{
+ m_data.shrinkToBestFit();
+ m_attributes.shrinkToBestFit();
+}
+
inline HTMLToken::Type HTMLToken::type() const
{
return m_type;
@@ -273,7 +280,7 @@
ASSERT(m_type == Uninitialized);
m_type = StartTag;
m_selfClosing = false;
- m_attributes.clear();
+ m_attributes.resize(0);
#if ASSERT_ENABLED
m_currentAttribute = nullptr;
@@ -288,7 +295,7 @@
ASSERT(m_type == Uninitialized);
m_type = EndTag;
m_selfClosing = false;
- m_attributes.clear();
+ m_attributes.resize(0);
#if ASSERT_ENABLED
m_currentAttribute = nullptr;
@@ -302,7 +309,7 @@
ASSERT(m_type == Uninitialized);
m_type = EndTag;
m_selfClosing = false;
- m_attributes.clear();
+ m_attributes.resize(0);
#if ASSERT_ENABLED
m_currentAttribute = nullptr;
Modified: trunk/Source/WebCore/html/parser/HTMLTokenizer.h (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLTokenizer.h 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLTokenizer.h 2021-07-22 19:18:45 UTC (rev 280193)
@@ -79,6 +79,11 @@
bool neverSkipNullCharacters() const;
+ void shrinkToBestFit()
+ {
+ m_token.shrinkToBestFit();
+ }
+
private:
enum State {
DataState,
Modified: trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -226,11 +226,7 @@
template<bool characterPredicate(UChar)> void skipLeading()
{
ASSERT(!isEmpty());
- while (characterPredicate(m_text[0])) {
- m_text = m_text.substring(1);
- if (m_text.isEmpty())
- return;
- }
+ m_text = m_text.stripLeadingMatchedCharacters(characterPredicate);
}
template<bool characterPredicate(UChar)> String takeLeading()
@@ -433,13 +429,6 @@
processFakeEndTag(tagName.localName());
}
-void HTMLTreeBuilder::processFakeCharacters(const String& characters)
-{
- ASSERT(!characters.isEmpty());
- ExternalCharacterTokenBuffer buffer(characters);
- processCharacterBuffer(buffer);
-}
-
void HTMLTreeBuilder::processFakePEndTagIfPInButtonScope()
{
if (!m_tree.openElements().inButtonScope(pTag->localName()))
@@ -2195,7 +2184,7 @@
// FIXME: Extract the following iOS-specific code into a separate file.
// From the string 4089961010, creates a link of the form <a href="" and inserts it.
-void HTMLTreeBuilder::insertPhoneNumberLink(const String& string)
+void HTMLTreeBuilder::insertPhoneNumberLink(String&& string)
{
Vector<Attribute> attributes;
attributes.append(Attribute(HTMLNames::hrefAttr, makeString("tel:"_s, string)));
@@ -2206,7 +2195,7 @@
processStartTag(WTFMove(aStartToken));
m_tree.executeQueuedTasks();
- m_tree.insertTextNode(string);
+ m_tree.insertTextNode(WTFMove(string));
processEndTag(WTFMove(aEndToken));
}
@@ -2215,7 +2204,7 @@
// 2. Wraps the phone number in a tel: link.
// 3. Goes back to step 1 if a phone number is found in the rest of the string.
// 4. Appends the rest of the string as a text node.
-void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string)
+void HTMLTreeBuilder::linkifyPhoneNumbers(String&& string)
{
ASSERT(TelephoneNumberDetector::isSupported());
@@ -2248,10 +2237,10 @@
if (scannerPosition > 0) {
if (scannerPosition < length) {
String after = string.substring(scannerPosition, length - scannerPosition);
- m_tree.insertTextNode(after);
+ m_tree.insertTextNode(WTFMove(after));
}
} else
- m_tree.insertTextNode(string);
+ m_tree.insertTextNode(WTFMove(string));
}
// Looks at the ancestors of the element to determine whether we're inside an element which disallows parsing phone numbers.
@@ -2324,7 +2313,7 @@
case InsertionMode::InHead: {
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
- m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+ m_tree.insertTextNode(WTFMove(leadingWhitespace), AllWhitespace);
if (buffer.isEmpty())
return;
defaultForInHead();
@@ -2334,7 +2323,7 @@
case InsertionMode::AfterHead: {
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
- m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+ m_tree.insertTextNode(WTFMove(leadingWhitespace), AllWhitespace);
if (buffer.isEmpty())
return;
defaultForAfterHead();
@@ -2372,7 +2361,7 @@
case InsertionMode::InColumnGroup: {
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
- m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+ m_tree.insertTextNode(WTFMove(leadingWhitespace), AllWhitespace);
if (buffer.isEmpty())
return;
if (!processColgroupEndTagForInColumnGroup()) {
@@ -2395,7 +2384,7 @@
case InsertionMode::InHeadNoscript: {
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
- m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+ m_tree.insertTextNode(WTFMove(leadingWhitespace), AllWhitespace);
if (buffer.isEmpty())
return;
defaultForInHeadNoscript();
@@ -2405,7 +2394,7 @@
case InsertionMode::AfterFrameset: {
String leadingWhitespace = buffer.takeRemainingWhitespace();
if (!leadingWhitespace.isEmpty())
- m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+ m_tree.insertTextNode(WTFMove(leadingWhitespace), AllWhitespace);
// FIXME: We should generate a parse error if we skipped over any
// non-whitespace characters.
break;
@@ -2418,7 +2407,7 @@
String leadingWhitespace = buffer.takeRemainingWhitespace();
if (!leadingWhitespace.isEmpty()) {
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+ m_tree.insertTextNode(WTFMove(leadingWhitespace), AllWhitespace);
}
// FIXME: We should generate a parse error if we skipped over any
// non-whitespace characters.
@@ -2431,16 +2420,16 @@
{
m_tree.reconstructTheActiveFormattingElements();
String characters = buffer.takeRemaining();
+ if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
+ m_framesetOk = false;
#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS_FAMILY)
if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(m_tree.currentNode()) && TelephoneNumberDetector::isSupported())
- linkifyPhoneNumbers(characters);
+ linkifyPhoneNumbers(WTFMove(characters));
else
- m_tree.insertTextNode(characters);
+ m_tree.insertTextNode(WTFMove(characters));
#else
- m_tree.insertTextNode(characters);
+ m_tree.insertTextNode(WTFMove(characters));
#endif
- if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
- m_framesetOk = false;
}
void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken&& token)
@@ -2577,12 +2566,12 @@
// FIXME: parse error
HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertTextNode(characters, NotAllWhitespace);
+ m_tree.insertTextNode(WTFMove(characters), NotAllWhitespace);
m_framesetOk = false;
m_insertionMode = m_originalInsertionMode;
return;
}
- m_tree.insertTextNode(characters);
+ m_tree.insertTextNode(WTFMove(characters));
m_insertionMode = m_originalInsertionMode;
}
@@ -2820,9 +2809,9 @@
return;
case HTMLToken::Character: {
String characters = String(token.characters(), token.charactersLength());
- m_tree.insertTextNode(characters);
if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
m_framesetOk = false;
+ m_tree.insertTextNode(WTFMove(characters));
break;
}
case HTMLToken::EndOfFile:
Modified: trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h (280192 => 280193)
--- trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h 2021-07-22 19:18:45 UTC (rev 280193)
@@ -108,8 +108,8 @@
bool isParsingFragmentOrTemplateContents() const;
#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS_FAMILY)
- void insertPhoneNumberLink(const String&);
- void linkifyPhoneNumbers(const String&);
+ void insertPhoneNumberLink(String&&);
+ void linkifyPhoneNumbers(String&&);
#endif
void processToken(AtomicHTMLToken&&);
@@ -145,7 +145,6 @@
void processFakeStartTag(const QualifiedName&, Vector<Attribute>&& attributes = Vector<Attribute>());
void processFakeEndTag(const QualifiedName&);
void processFakeEndTag(const AtomString&);
- void processFakeCharacters(const String&);
void processFakePEndTagIfPInButtonScope();
void processGenericRCDATAStartTag(AtomicHTMLToken&&);
Modified: trunk/Tools/ChangeLog (280192 => 280193)
--- trunk/Tools/ChangeLog 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Tools/ChangeLog 2021-07-22 19:18:45 UTC (rev 280193)
@@ -1,3 +1,15 @@
+2021-07-22 Yusuke Suzuki <[email protected]>
+
+ Micro-optimize innerHTML
+ https://bugs.webkit.org/show_bug.cgi?id=228142
+
+ Reviewed by Simon Fraser.
+
+ * TestWebKitAPI/Tests/WTF/StringView.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WTF/Vector.cpp:
+ (TestWebKitAPI::TEST):
+
2021-07-22 Peng Liu <[email protected]>
[ BigSur Debug ] TestWebKitAPI.GPUProcess.CrashWhilePlayingAudioViaCreateMediaElementSource is flaky, hitting ASSERTION FAILED: !isInRoutingArbitrationForToken(token)
Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp (280192 => 280193)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -959,6 +959,28 @@
EXPECT_EQ(reference.reverseFind('c', 4), notFound);
}
+TEST(WTF, StringViewStripLeadingMatchedCharacters)
+{
+ auto isA = [] (UChar c) {
+ return c == 'A';
+ };
+
+ EXPECT_TRUE(stringViewFromLiteral("AAABBBAAA").stripLeadingMatchedCharacters(isA) == stringViewFromLiteral("BBBAAA"));
+ EXPECT_TRUE(stringViewFromLiteral("AAABBBCCC").stripLeadingMatchedCharacters(isA) == stringViewFromLiteral("BBBCCC"));
+ EXPECT_TRUE(stringViewFromLiteral("CCCBBBAAA").stripLeadingMatchedCharacters(isA) == stringViewFromLiteral("CCCBBBAAA"));
+ EXPECT_TRUE(stringViewFromLiteral("CCCBBBCCC").stripLeadingMatchedCharacters(isA) == stringViewFromLiteral("CCCBBBCCC"));
+ EXPECT_TRUE(stringViewFromLiteral("AAAAAACCC").stripLeadingMatchedCharacters(isA) == stringViewFromLiteral("CCC"));
+ EXPECT_TRUE(stringViewFromLiteral("BBBAAAAAA").stripLeadingMatchedCharacters(isA) == stringViewFromLiteral("BBBAAAAAA"));
+ EXPECT_TRUE(stringViewFromLiteral("CCCAAABBB").stripLeadingMatchedCharacters(isA) == stringViewFromLiteral("CCCAAABBB"));
+ EXPECT_TRUE(stringViewFromLiteral("AAAAAAAAA").stripLeadingMatchedCharacters(isA) == StringView::empty());
+
+ StringView emptyView = StringView::empty();
+ EXPECT_TRUE(emptyView.stripLeadingMatchedCharacters(isA) == emptyView);
+
+ StringView nullView;
+ EXPECT_TRUE(nullView.stripLeadingMatchedCharacters(isA) == nullView);
+}
+
TEST(WTF, StringViewStripLeadingAndTrailingMatchedCharacters)
{
auto isA = [] (UChar c) {
Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp (280192 => 280193)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp 2021-07-22 19:13:01 UTC (rev 280192)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp 2021-07-22 19:18:45 UTC (rev 280193)
@@ -1458,5 +1458,41 @@
EXPECT_EQ(vector[3], 4);
EXPECT_EQ(vector[4], 5);
}
-
+
+TEST(WTF_Vector, ShrinkToBestFitClear)
+{
+ Vector<uint32_t> vector;
+ vector.append(20);
+ vector.append(20);
+ vector.append(20);
+ vector.resize(0);
+ vector.shrinkToBestFit();
+ EXPECT_EQ(vector.size(), 0U);
+ EXPECT_EQ(vector.capacity(), 0U);
+}
+
+TEST(WTF_Vector, ShrinkToBestFitDoesNotChangeIfCapacityMatches)
+{
+ Vector<uint32_t> vector;
+ vector.append(20);
+ vector.append(20);
+ vector.append(20);
+ unsigned capacity = vector.capacity();
+ vector.shrinkToBestFit();
+ EXPECT_EQ(vector.size(), 3U);
+ EXPECT_EQ(vector.capacity(), capacity);
+}
+
+TEST(WTF_Vector, ShrinkToBestFit)
+{
+ Vector<uint32_t> vector;
+ for (unsigned index = 0; index < 400; ++index)
+ vector.append(index);
+ vector.resize(100);
+ EXPECT_GE(vector.capacity(), 400U);
+ vector.shrinkToBestFit();
+ EXPECT_LE(vector.capacity(), 200U);
+ EXPECT_GE(vector.capacity(), 100U);
+}
+
} // namespace TestWebKitAPI