<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[206044] trunk/Source/WebCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/206044">206044</a></dd>
<dt>Author</dt> <dd>achristensen@apple.com</dd>
<dt>Date</dt> <dd>2016-09-16 13:35:16 -0700 (Fri, 16 Sep 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Use Vector<LChar> instead of StringBuilder for the ASCII parts of URLParser
https://bugs.webkit.org/show_bug.cgi?id=162035
Reviewed by Chris Dumez.
StringBuilder::append checks to see whether its StringBuffer is 8-bit or 16-bit each time it is called.
When parsing URLs, almost all of the parsed URL is guaranteed to be 8-bit ASCII.
Using a Vector<LChar> for this allows us to use uncheckedAppend in some places, and it always eliminates the 8-bit check.
This is a ~20% speedup in url parsing.
Covered by existing API tests.
* platform/URLParser.cpp:
(WebCore::isWindowsDriveLetter):
(WebCore::percentEncode):
(WebCore::utf8PercentEncode):
(WebCore::utf8PercentEncodeQuery):
(WebCore::encodeQuery):
(WebCore::URLParser::copyURLPartsUntil):
(WebCore::URLParser::popPath):
(WebCore::URLParser::parse):
(WebCore::URLParser::parseAuthority):
(WebCore::appendNumber):
(WebCore::serializeIPv4):
(WebCore::serializeIPv6Piece):
(WebCore::serializeIPv6):
(WebCore::URLParser::parsePort):
(WebCore::URLParser::parseHost):
(WebCore::serializeURLEncodedForm):
(WebCore::URLParser::serialize):
(WebCore::bufferView): Deleted.
* platform/URLParser.h:</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformURLParsercpp">trunk/Source/WebCore/platform/URLParser.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformURLParserh">trunk/Source/WebCore/platform/URLParser.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (206043 => 206044)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-16 20:24:23 UTC (rev 206043)
+++ trunk/Source/WebCore/ChangeLog        2016-09-16 20:35:16 UTC (rev 206044)
</span><span class="lines">@@ -1,3 +1,38 @@
</span><ins>+2016-09-16 Alex Christensen <achristensen@webkit.org>
+
+ Use Vector<LChar> instead of StringBuilder for the ASCII parts of URLParser
+ https://bugs.webkit.org/show_bug.cgi?id=162035
+
+ Reviewed by Chris Dumez.
+
+ StringBuilder::append checks to see whether its StringBuffer is 8-bit or 16-bit each time it is called.
+ When parsing URLs, almost all of the parsed URL is guaranteed to be 8-bit ASCII.
+ Using a Vector<LChar> for this allows us to use uncheckedAppend in some places, and it always eliminates the 8-bit check.
+ This is a ~20% speedup in url parsing.
+
+ Covered by existing API tests.
+
+ * platform/URLParser.cpp:
+ (WebCore::isWindowsDriveLetter):
+ (WebCore::percentEncode):
+ (WebCore::utf8PercentEncode):
+ (WebCore::utf8PercentEncodeQuery):
+ (WebCore::encodeQuery):
+ (WebCore::URLParser::copyURLPartsUntil):
+ (WebCore::URLParser::popPath):
+ (WebCore::URLParser::parse):
+ (WebCore::URLParser::parseAuthority):
+ (WebCore::appendNumber):
+ (WebCore::serializeIPv4):
+ (WebCore::serializeIPv6Piece):
+ (WebCore::serializeIPv6):
+ (WebCore::URLParser::parsePort):
+ (WebCore::URLParser::parseHost):
+ (WebCore::serializeURLEncodedForm):
+ (WebCore::URLParser::serialize):
+ (WebCore::bufferView): Deleted.
+ * platform/URLParser.h:
+
</ins><span class="cx"> 2016-09-16 Dave Hyatt <hyatt@apple.com>
</span><span class="cx">
</span><span class="cx"> [CSS Parser] Get CSSPropertyParserHelpers.cpp compiling
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.cpp (206043 => 206044)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.cpp        2016-09-16 20:24:23 UTC (rev 206043)
+++ trunk/Source/WebCore/platform/URLParser.cpp        2016-09-16 20:35:16 UTC (rev 206044)
</span><span class="lines">@@ -109,10 +109,10 @@
</span><span class="cx"> auto CodePointIterator<UChar>::operator++() -> CodePointIterator&
</span><span class="cx"> {
</span><span class="cx"> ASSERT(!atEnd());
</span><del>- if (U16_IS_LEAD(m_begin[0]) && m_begin < m_end && U16_IS_TRAIL(m_begin[1]))
- m_begin += 2;
- else
- m_begin++;
</del><ins>+ unsigned i = 0;
+ size_t length = m_end - m_begin;
+ U16_FWD_1(m_begin, i, length);
+ m_begin += i;
</ins><span class="cx"> return *this;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -405,11 +405,11 @@
</span><span class="cx"> return *iterator == ':' || *iterator == '|';
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool isWindowsDriveLetter(const StringBuilder& builder, size_t index)
</del><ins>+static bool isWindowsDriveLetter(const Vector<LChar>& buffer, size_t index)
</ins><span class="cx"> {
</span><del>- if (builder.length() < index + 2)
</del><ins>+ if (buffer.size() < index + 2)
</ins><span class="cx"> return false;
</span><del>- return isASCIIAlpha(builder[index]) && (builder[index + 1] == ':' || builder[index + 1] == '|');
</del><ins>+ return isASCIIAlpha(buffer[index]) && (buffer[index + 1] == ':' || buffer[index + 1] == '|');
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename CharacterType>
</span><span class="lines">@@ -428,14 +428,14 @@
</span><span class="cx"> return !isSlashQuestionOrHash(*iterator);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void percentEncode(uint8_t byte, StringBuilder& builder)
</del><ins>+static void percentEncode(uint8_t byte, Vector<LChar>& buffer)
</ins><span class="cx"> {
</span><del>- builder.append('%');
- builder.append(upperNibbleToASCIIHexDigit(byte));
- builder.append(lowerNibbleToASCIIHexDigit(byte));
</del><ins>+ buffer.append('%');
+ buffer.append(upperNibbleToASCIIHexDigit(byte));
+ buffer.append(lowerNibbleToASCIIHexDigit(byte));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-static void utf8PercentEncode(UChar32 codePoint, StringBuilder& builder, bool(*isInCodeSet)(UChar32))
</del><ins>+static void utf8PercentEncode(UChar32 codePoint, Vector<LChar>& destination, bool(*isInCodeSet)(UChar32))
</ins><span class="cx"> {
</span><span class="cx"> if (isInCodeSet(codePoint)) {
</span><span class="cx"> uint8_t buffer[U8_MAX_LENGTH];
</span><span class="lines">@@ -444,12 +444,14 @@
</span><span class="cx"> U8_APPEND(buffer, offset, U8_MAX_LENGTH, codePoint, error);
</span><span class="cx"> // FIXME: Check error.
</span><span class="cx"> for (int32_t i = 0; i < offset; ++i)
</span><del>- percentEncode(buffer[i], builder);
- } else
- builder.append(codePoint);
</del><ins>+ percentEncode(buffer[i], destination);
+ } else {
+ ASSERT_WITH_MESSAGE(isASCII(codePoint), "isInCodeSet should always return true for non-ASCII characters");
+ destination.append(codePoint);
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-static void utf8PercentEncodeQuery(UChar32 codePoint, StringBuilder& builder)
</del><ins>+static void utf8PercentEncodeQuery(UChar32 codePoint, Vector<LChar>& destination)
</ins><span class="cx"> {
</span><span class="cx"> uint8_t buffer[U8_MAX_LENGTH];
</span><span class="cx"> int32_t offset = 0;
</span><span class="lines">@@ -460,13 +462,13 @@
</span><span class="cx"> for (int32_t i = 0; i < offset; ++i) {
</span><span class="cx"> auto byte = buffer[i];
</span><span class="cx"> if (shouldPercentEncodeQueryByte(byte))
</span><del>- percentEncode(byte, builder);
</del><ins>+ percentEncode(byte, destination);
</ins><span class="cx"> else
</span><del>- builder.append(byte);
</del><ins>+ destination.append(byte);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void encodeQuery(const StringBuilder& source, StringBuilder& destination, const TextEncoding& encoding)
</del><ins>+static void encodeQuery(const StringBuilder& source, Vector<LChar>& destination, const TextEncoding& encoding)
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: It is unclear in the spec what to do when encoding fails. The behavior should be specified and tested.
</span><span class="cx"> CString encoded = encoding.encode(source.toStringPreserveCapacity(), URLEncodedEntitiesForUnencodables);
</span><span class="lines">@@ -595,15 +597,6 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>-template<typename T>
-static StringView bufferView(const T& buffer, unsigned start, unsigned length)
-{
- ASSERT(buffer.length() >= length);
- if (buffer.is8Bit())
- return StringView(buffer.characters8() + start, length);
- return StringView(buffer.characters16() + start, length);
-}
-
</del><span class="cx"> enum class URLParser::URLPart {
</span><span class="cx"> SchemeEnd,
</span><span class="cx"> UserStart,
</span><span class="lines">@@ -644,11 +637,47 @@
</span><span class="cx"> ASSERT_NOT_REACHED();
</span><span class="cx"> return 0;
</span><span class="cx"> }
</span><del>-
</del><ins>+
+static void copyASCIIStringUntil(Vector<LChar>& destination, const String& string, size_t lengthIf8Bit, size_t lengthIf16Bit)
+{
+ ASSERT(destination.isEmpty());
+ if (string.is8Bit()) {
+ RELEASE_ASSERT(lengthIf8Bit <= string.length());
+ destination.append(string.characters8(), lengthIf8Bit);
+ } else {
+ RELEASE_ASSERT(lengthIf16Bit <= string.length());
+ destination.reserveCapacity(lengthIf16Bit);
+ const UChar* characters = string.characters16();
+ for (size_t i = 0; i < lengthIf16Bit; ++i) {
+ UChar c = characters[i];
+ ASSERT_WITH_SECURITY_IMPLICATION(isASCII(c));
+ destination.uncheckedAppend(c);
+ }
+ }
+}
+
</ins><span class="cx"> void URLParser::copyURLPartsUntil(const URL& base, URLPart part)
</span><span class="cx"> {
</span><del>- m_buffer.clear();
- m_buffer.append(base.m_string.substring(0, urlLengthUntilPart(base, part)));
</del><ins>+ m_asciiBuffer.clear();
+ m_unicodeFragmentBuffer.clear();
+ if (part == URLPart::FragmentEnd) {
+ copyASCIIStringUntil(m_asciiBuffer, base.m_string, urlLengthUntilPart(base, URLPart::FragmentEnd), urlLengthUntilPart(base, URLPart::QueryEnd));
+ if (!base.m_string.is8Bit()) {
+ const String& fragment = base.m_string;
+ bool seenUnicode = false;
+ for (size_t i = base.m_queryEnd; i < base.m_fragmentEnd; ++i) {
+ if (!seenUnicode && !isASCII(fragment[i]))
+ seenUnicode = true;
+ if (seenUnicode)
+ m_unicodeFragmentBuffer.uncheckedAppend(fragment[i]);
+ else
+ m_asciiBuffer.uncheckedAppend(fragment[i]);
+ }
+ }
+ } else {
+ size_t length = urlLengthUntilPart(base, part);
+ copyASCIIStringUntil(m_asciiBuffer, base.m_string, length, length);
+ }
</ins><span class="cx"> switch (part) {
</span><span class="cx"> case URLPart::FragmentEnd:
</span><span class="cx"> m_url.m_fragmentEnd = base.m_fragmentEnd;
</span><span class="lines">@@ -682,7 +711,7 @@
</span><span class="cx"> m_url.m_protocolIsInHTTPFamily = base.m_protocolIsInHTTPFamily;
</span><span class="cx"> m_url.m_schemeEnd = base.m_schemeEnd;
</span><span class="cx"> }
</span><del>- m_urlIsSpecial = isSpecialScheme(bufferView(m_buffer, 0, m_url.m_schemeEnd));
</del><ins>+ m_urlIsSpecial = isSpecialScheme(StringView(m_asciiBuffer.data(), m_url.m_schemeEnd));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static const char* dotASCIICode = "2e";
</span><span class="lines">@@ -802,13 +831,13 @@
</span><span class="cx"> {
</span><span class="cx"> if (m_url.m_pathAfterLastSlash > m_url.m_portEnd + 1) {
</span><span class="cx"> m_url.m_pathAfterLastSlash--;
</span><del>- if (m_buffer[m_url.m_pathAfterLastSlash] == '/')
</del><ins>+ if (m_asciiBuffer[m_url.m_pathAfterLastSlash] == '/')
</ins><span class="cx"> m_url.m_pathAfterLastSlash--;
</span><del>- while (m_url.m_pathAfterLastSlash > m_url.m_portEnd && m_buffer[m_url.m_pathAfterLastSlash] != '/')
</del><ins>+ while (m_url.m_pathAfterLastSlash > m_url.m_portEnd && m_asciiBuffer[m_url.m_pathAfterLastSlash] != '/')
</ins><span class="cx"> m_url.m_pathAfterLastSlash--;
</span><span class="cx"> m_url.m_pathAfterLastSlash++;
</span><span class="cx"> }
</span><del>- m_buffer.resize(m_url.m_pathAfterLastSlash);
</del><ins>+ m_asciiBuffer.resize(m_url.m_pathAfterLastSlash);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename CharacterType>
</span><span class="lines">@@ -844,8 +873,9 @@
</span><span class="cx"> {
</span><span class="cx"> LOG(URLParser, "Parsing URL <%s> base <%s>", String(input, length).utf8().data(), base.string().utf8().data());
</span><span class="cx"> m_url = { };
</span><del>- m_buffer.clear();
- m_buffer.reserveCapacity(length);
</del><ins>+ m_asciiBuffer.clear();
+ m_unicodeFragmentBuffer.clear();
+ m_asciiBuffer.reserveCapacity(length);
</ins><span class="cx">
</span><span class="cx"> bool isUTF8Encoding = encoding == UTF8Encoding();
</span><span class="cx"> StringBuilder queryBuffer;
</span><span class="lines">@@ -881,7 +911,7 @@
</span><span class="cx"> Fragment,
</span><span class="cx"> };
</span><span class="cx">
</span><del>-#define LOG_STATE(x) LOG(URLParser, "State %s, code point %c, buffer length %d", x, *c, m_buffer.length())
</del><ins>+#define LOG_STATE(x) LOG(URLParser, "State %s, code point %c, asciiBuffer size %zu", x, *c, m_asciiBuffer.size())
</ins><span class="cx"> #define LOG_FINAL_STATE(x) LOG(URLParser, "Final State: %s", x)
</span><span class="cx">
</span><span class="cx"> State state = State::SchemeStart;
</span><span class="lines">@@ -895,7 +925,7 @@
</span><span class="cx"> case State::SchemeStart:
</span><span class="cx"> LOG_STATE("SchemeStart");
</span><span class="cx"> if (isASCIIAlpha(*c)) {
</span><del>- m_buffer.append(toASCIILower(*c));
</del><ins>+ m_asciiBuffer.uncheckedAppend(toASCIILower(*c));
</ins><span class="cx"> ++c;
</span><span class="cx"> state = State::Scheme;
</span><span class="cx"> } else
</span><span class="lines">@@ -904,19 +934,19 @@
</span><span class="cx"> case State::Scheme:
</span><span class="cx"> LOG_STATE("Scheme");
</span><span class="cx"> if (isASCIIAlphanumeric(*c) || *c == '+' || *c == '-' || *c == '.')
</span><del>- m_buffer.append(toASCIILower(*c));
</del><ins>+ m_asciiBuffer.append(toASCIILower(*c));
</ins><span class="cx"> else if (*c == ':') {
</span><del>- m_url.m_schemeEnd = m_buffer.length();
- StringView urlScheme = bufferView(m_buffer, 0, m_url.m_schemeEnd);
</del><ins>+ m_url.m_schemeEnd = m_asciiBuffer.size();
+ StringView urlScheme = StringView(m_asciiBuffer.data(), m_url.m_schemeEnd);
</ins><span class="cx"> m_url.m_protocolIsInHTTPFamily = urlScheme == "http" || urlScheme == "https";
</span><span class="cx"> if (urlScheme == "file") {
</span><span class="cx"> m_urlIsSpecial = true;
</span><span class="cx"> state = State::File;
</span><del>- m_buffer.append(':');
</del><ins>+ m_asciiBuffer.append(':');
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- m_buffer.append(':');
</del><ins>+ m_asciiBuffer.append(':');
</ins><span class="cx"> if (isSpecialScheme(urlScheme)) {
</span><span class="cx"> m_urlIsSpecial = true;
</span><span class="cx"> // FIXME: This is unnecessarily allocating a String.
</span><span class="lines">@@ -926,7 +956,7 @@
</span><span class="cx"> else
</span><span class="cx"> state = State::SpecialAuthoritySlashes;
</span><span class="cx"> } else {
</span><del>- m_url.m_userStart = m_buffer.length();
</del><ins>+ m_url.m_userStart = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -936,7 +966,7 @@
</span><span class="cx"> while (!maybeSlash.atEnd() && isTabOrNewline(*maybeSlash))
</span><span class="cx"> ++maybeSlash;
</span><span class="cx"> if (!maybeSlash.atEnd() && *maybeSlash == '/') {
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
</span><span class="cx"> state = State::PathOrAuthority;
</span><span class="cx"> c = maybeSlash;
</span><span class="lines">@@ -950,7 +980,7 @@
</span><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> } else {
</span><del>- m_buffer.clear();
</del><ins>+ m_asciiBuffer.clear();
</ins><span class="cx"> state = State::NoScheme;
</span><span class="cx"> c = beginAfterControlAndSpace;
</span><span class="cx"> break;
</span><span class="lines">@@ -959,7 +989,7 @@
</span><span class="cx"> while (!c.atEnd() && isTabOrNewline(*c))
</span><span class="cx"> ++c;
</span><span class="cx"> if (c.atEnd()) {
</span><del>- m_buffer.clear();
</del><ins>+ m_asciiBuffer.clear();
</ins><span class="cx"> state = State::NoScheme;
</span><span class="cx"> c = beginAfterControlAndSpace;
</span><span class="cx"> }
</span><span class="lines">@@ -971,7 +1001,7 @@
</span><span class="cx"> if (base.m_cannotBeABaseURL && *c == '#') {
</span><span class="cx"> copyURLPartsUntil(base, URLPart::QueryEnd);
</span><span class="cx"> state = State::Fragment;
</span><del>- m_buffer.append('#');
</del><ins>+ m_asciiBuffer.append('#');
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -980,13 +1010,13 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> copyURLPartsUntil(base, URLPart::SchemeEnd);
</span><del>- m_buffer.append(':');
</del><ins>+ m_asciiBuffer.append(':');
</ins><span class="cx"> state = State::File;
</span><span class="cx"> break;
</span><span class="cx"> case State::SpecialRelativeOrAuthority:
</span><span class="cx"> LOG_STATE("SpecialRelativeOrAuthority");
</span><span class="cx"> if (*c == '/') {
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> ++c;
</span><span class="cx"> while (!c.atEnd() && isTabOrNewline(*c))
</span><span class="cx"> ++c;
</span><span class="lines">@@ -993,7 +1023,7 @@
</span><span class="cx"> if (c.atEnd())
</span><span class="cx"> return failure(input, length);
</span><span class="cx"> if (*c == '/') {
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> state = State::SpecialAuthorityIgnoreSlashes;
</span><span class="cx"> ++c;
</span><span class="cx"> }
</span><span class="lines">@@ -1003,8 +1033,8 @@
</span><span class="cx"> case State::PathOrAuthority:
</span><span class="cx"> LOG_STATE("PathOrAuthority");
</span><span class="cx"> if (*c == '/') {
</span><del>- m_buffer.append('/');
- m_url.m_userStart = m_buffer.length();
</del><ins>+ m_asciiBuffer.append('/');
+ m_url.m_userStart = m_asciiBuffer.size();
</ins><span class="cx"> state = State::AuthorityOrHost;
</span><span class="cx"> ++c;
</span><span class="cx"> authorityOrHostBegin = c;
</span><span class="lines">@@ -1021,13 +1051,13 @@
</span><span class="cx"> break;
</span><span class="cx"> case '?':
</span><span class="cx"> copyURLPartsUntil(base, URLPart::PathEnd);
</span><del>- m_buffer.append('?');
</del><ins>+ m_asciiBuffer.append('?');
</ins><span class="cx"> state = State::Query;
</span><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> case '#':
</span><span class="cx"> copyURLPartsUntil(base, URLPart::QueryEnd);
</span><del>- m_buffer.append('#');
</del><ins>+ m_asciiBuffer.append('#');
</ins><span class="cx"> state = State::Fragment;
</span><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="lines">@@ -1042,11 +1072,11 @@
</span><span class="cx"> if (*c == '/' || *c == '\\') {
</span><span class="cx"> ++c;
</span><span class="cx"> copyURLPartsUntil(base, URLPart::SchemeEnd);
</span><del>- m_buffer.append("://");
</del><ins>+ m_asciiBuffer.append("://", 3);
</ins><span class="cx"> state = State::SpecialAuthorityIgnoreSlashes;
</span><span class="cx"> } else {
</span><span class="cx"> copyURLPartsUntil(base, URLPart::PortEnd);
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> m_url.m_pathAfterLastSlash = base.m_portEnd + 1;
</span><span class="cx"> state = State::Path;
</span><span class="cx"> }
</span><span class="lines">@@ -1053,7 +1083,7 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::SpecialAuthoritySlashes:
</span><span class="cx"> LOG_STATE("SpecialAuthoritySlashes");
</span><del>- m_buffer.append("//");
</del><ins>+ m_asciiBuffer.append("//", 2);
</ins><span class="cx"> if (*c == '/' || *c == '\\') {
</span><span class="cx"> ++c;
</span><span class="cx"> while (!c.atEnd() && isTabOrNewline(*c))
</span><span class="lines">@@ -1066,10 +1096,10 @@
</span><span class="cx"> case State::SpecialAuthorityIgnoreSlashes:
</span><span class="cx"> LOG_STATE("SpecialAuthorityIgnoreSlashes");
</span><span class="cx"> if (*c == '/' || *c == '\\') {
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> ++c;
</span><span class="cx"> }
</span><del>- m_url.m_userStart = m_buffer.length();
</del><ins>+ m_url.m_userStart = m_asciiBuffer.size();
</ins><span class="cx"> state = State::AuthorityOrHost;
</span><span class="cx"> authorityOrHostBegin = c;
</span><span class="cx"> break;
</span><span class="lines">@@ -1088,13 +1118,13 @@
</span><span class="cx"> }
</span><span class="cx"> bool isSlash = *c == '/' || (m_urlIsSpecial && *c == '\\');
</span><span class="cx"> if (isSlash || *c == '?' || *c == '#') {
</span><del>- m_url.m_userEnd = m_buffer.length();
</del><ins>+ m_url.m_userEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx"> if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
</span><span class="cx"> return failure(input, length);
</span><span class="cx"> if (!isSlash) {
</span><del>- m_buffer.append('/');
- m_url.m_pathAfterLastSlash = m_buffer.length();
</del><ins>+ m_asciiBuffer.append('/');
+ m_url.m_pathAfterLastSlash = m_asciiBuffer.size();
</ins><span class="cx"> }
</span><span class="cx"> state = State::Path;
</span><span class="cx"> break;
</span><span class="lines">@@ -1121,7 +1151,7 @@
</span><span class="cx"> switch (*c) {
</span><span class="cx"> case '/':
</span><span class="cx"> case '\\':
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> state = State::FileSlash;
</span><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="lines">@@ -1128,8 +1158,8 @@
</span><span class="cx"> case '?':
</span><span class="cx"> if (!base.isNull() && base.protocolIs("file"))
</span><span class="cx"> copyURLPartsUntil(base, URLPart::PathEnd);
</span><del>- m_buffer.append("///?");
- m_url.m_userStart = m_buffer.length() - 2;
</del><ins>+ m_asciiBuffer.append("///?", 4);
+ m_url.m_userStart = m_asciiBuffer.size() - 2;
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1142,8 +1172,8 @@
</span><span class="cx"> case '#':
</span><span class="cx"> if (!base.isNull() && base.protocolIs("file"))
</span><span class="cx"> copyURLPartsUntil(base, URLPart::QueryEnd);
</span><del>- m_buffer.append("///#");
- m_url.m_userStart = m_buffer.length() - 2;
</del><ins>+ m_asciiBuffer.append("///#", 4);
+ m_url.m_userStart = m_asciiBuffer.size() - 2;
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1158,8 +1188,8 @@
</span><span class="cx"> if (!base.isNull() && base.protocolIs("file") && shouldCopyFileURL(c))
</span><span class="cx"> copyURLPartsUntil(base, URLPart::PathAfterLastSlash);
</span><span class="cx"> else {
</span><del>- m_buffer.append("///");
- m_url.m_userStart = m_buffer.length() - 1;
</del><ins>+ m_asciiBuffer.append("///", 3);
+ m_url.m_userStart = m_asciiBuffer.size() - 1;
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1174,8 +1204,8 @@
</span><span class="cx"> LOG_STATE("FileSlash");
</span><span class="cx"> if (*c == '/' || *c == '\\') {
</span><span class="cx"> ++c;
</span><del>- m_buffer.append('/');
- m_url.m_userStart = m_buffer.length();
</del><ins>+ m_asciiBuffer.append('/');
+ m_url.m_userStart = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1192,15 +1222,15 @@
</span><span class="cx"> ? isWindowsDriveLetter(CodePointIterator<LChar>(basePath.characters8(), basePath.characters8() + basePath.length()))
</span><span class="cx"> : isWindowsDriveLetter(CodePointIterator<UChar>(basePath.characters16(), basePath.characters16() + basePath.length()));
</span><span class="cx"> if (windowsQuirk) {
</span><del>- m_buffer.append(basePath[0]);
- m_buffer.append(basePath[1]);
</del><ins>+ m_asciiBuffer.append(basePath[0]);
+ m_asciiBuffer.append(basePath[1]);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> state = State::Path;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- m_buffer.append("//");
- m_url.m_userStart = m_buffer.length() - 1;
</del><ins>+ m_asciiBuffer.append("//", 2);
+ m_url.m_userStart = m_asciiBuffer.size() - 1;
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1211,15 +1241,15 @@
</span><span class="cx"> case State::FileHost:
</span><span class="cx"> LOG_STATE("FileHost");
</span><span class="cx"> if (isSlashQuestionOrHash(*c)) {
</span><del>- if (isWindowsDriveLetter(m_buffer, m_url.m_portEnd + 1)) {
</del><ins>+ if (isWindowsDriveLetter(m_asciiBuffer, m_url.m_portEnd + 1)) {
</ins><span class="cx"> state = State::Path;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> if (authorityOrHostBegin == c) {
</span><del>- ASSERT(m_buffer[m_buffer.length() - 1] == '/');
</del><ins>+ ASSERT(m_asciiBuffer[m_asciiBuffer.size() - 1] == '/');
</ins><span class="cx"> if (*c == '?') {
</span><del>- m_buffer.append("/?");
- m_url.m_pathAfterLastSlash = m_buffer.length() - 1;
</del><ins>+ m_asciiBuffer.append("/?", 2);
+ m_url.m_pathAfterLastSlash = m_asciiBuffer.size() - 1;
</ins><span class="cx"> m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx"> state = State::Query;
</span><span class="cx"> ++c;
</span><span class="lines">@@ -1226,8 +1256,8 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> if (*c == '#') {
</span><del>- m_buffer.append("/#");
- m_url.m_pathAfterLastSlash = m_buffer.length() - 1;
</del><ins>+ m_asciiBuffer.append("/#", 2);
+ m_url.m_pathAfterLastSlash = m_asciiBuffer.size() - 1;
</ins><span class="cx"> m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx"> m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx"> state = State::Fragment;
</span><span class="lines">@@ -1240,9 +1270,9 @@
</span><span class="cx"> if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
</span><span class="cx"> return failure(input, length);
</span><span class="cx">
</span><del>- if (bufferView(m_buffer, m_url.m_passwordEnd, m_buffer.length() - m_url.m_passwordEnd) == "localhost") {
- m_buffer.resize(m_url.m_passwordEnd);
- m_url.m_hostEnd = m_buffer.length();
</del><ins>+ if (StringView(m_asciiBuffer.data() + m_url.m_passwordEnd, m_asciiBuffer.size() - m_url.m_passwordEnd) == "localhost") {
+ m_asciiBuffer.shrink(m_url.m_passwordEnd);
+ m_url.m_hostEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_portEnd = m_url.m_hostEnd;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1262,35 +1292,35 @@
</span><span class="cx"> case State::Path:
</span><span class="cx"> LOG_STATE("Path");
</span><span class="cx"> if (*c == '/' || (m_urlIsSpecial && *c == '\\')) {
</span><del>- m_buffer.append('/');
- m_url.m_pathAfterLastSlash = m_buffer.length();
</del><ins>+ m_asciiBuffer.append('/');
+ m_url.m_pathAfterLastSlash = m_asciiBuffer.size();
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (m_buffer.length() && m_buffer[m_buffer.length() - 1] == '/') {
</del><ins>+ if (m_asciiBuffer.size() && m_asciiBuffer[m_asciiBuffer.size() - 1] == '/') {
</ins><span class="cx"> if (isDoubleDotPathSegment(c)) {
</span><span class="cx"> consumeDoubleDotPathSegment(c);
</span><span class="cx"> popPath();
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (m_buffer[m_buffer.length() - 1] == '/' && isSingleDotPathSegment(c)) {
</del><ins>+ if (m_asciiBuffer[m_asciiBuffer.size() - 1] == '/' && isSingleDotPathSegment(c)) {
</ins><span class="cx"> consumeSingleDotPathSegment(c);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> if (*c == '?') {
</span><del>- m_url.m_pathEnd = m_buffer.length();
</del><ins>+ m_url.m_pathEnd = m_asciiBuffer.size();
</ins><span class="cx"> state = State::Query;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> if (*c == '#') {
</span><del>- m_url.m_pathEnd = m_buffer.length();
</del><ins>+ m_url.m_pathEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_queryEnd = m_url.m_pathEnd;
</span><span class="cx"> state = State::Fragment;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> if (isPercentEncodedDot(c)) {
</span><del>- m_buffer.append('.');
</del><ins>+ m_asciiBuffer.append('.');
</ins><span class="cx"> ASSERT(*c == '%');
</span><span class="cx"> ++c;
</span><span class="cx"> ASSERT(*c == dotASCIICode[0]);
</span><span class="lines">@@ -1299,20 +1329,20 @@
</span><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- utf8PercentEncode(*c, m_buffer, isInDefaultEncodeSet);
</del><ins>+ utf8PercentEncode(*c, m_asciiBuffer, isInDefaultEncodeSet);
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> case State::CannotBeABaseURLPath:
</span><span class="cx"> LOG_STATE("CannotBeABaseURLPath");
</span><span class="cx"> if (*c == '?') {
</span><del>- m_url.m_pathEnd = m_buffer.length();
</del><ins>+ m_url.m_pathEnd = m_asciiBuffer.size();
</ins><span class="cx"> state = State::Query;
</span><span class="cx"> } else if (*c == '#') {
</span><del>- m_url.m_pathEnd = m_buffer.length();
</del><ins>+ m_url.m_pathEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_queryEnd = m_url.m_pathEnd;
</span><span class="cx"> state = State::Fragment;
</span><span class="cx"> } else {
</span><del>- utf8PercentEncode(*c, m_buffer, isInSimpleEncodeSet);
</del><ins>+ utf8PercentEncode(*c, m_asciiBuffer, isInSimpleEncodeSet);
</ins><span class="cx"> ++c;
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="lines">@@ -1320,13 +1350,13 @@
</span><span class="cx"> LOG_STATE("Query");
</span><span class="cx"> if (*c == '#') {
</span><span class="cx"> if (!isUTF8Encoding)
</span><del>- encodeQuery(queryBuffer, m_buffer, encoding);
- m_url.m_queryEnd = m_buffer.length();
</del><ins>+ encodeQuery(queryBuffer, m_asciiBuffer, encoding);
+ m_url.m_queryEnd = m_asciiBuffer.size();
</ins><span class="cx"> state = State::Fragment;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> if (isUTF8Encoding)
</span><del>- utf8PercentEncodeQuery(*c, m_buffer);
</del><ins>+ utf8PercentEncodeQuery(*c, m_asciiBuffer);
</ins><span class="cx"> else
</span><span class="cx"> queryBuffer.append(*c);
</span><span class="cx"> ++c;
</span><span class="lines">@@ -1333,7 +1363,10 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::Fragment:
</span><span class="cx"> LOG_STATE("Fragment");
</span><del>- m_buffer.append(*c);
</del><ins>+ if (m_unicodeFragmentBuffer.isEmpty() && isASCII(*c))
+ m_asciiBuffer.append(*c);
+ else
+ m_unicodeFragmentBuffer.append(*c);
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -1342,7 +1375,7 @@
</span><span class="cx"> switch (state) {
</span><span class="cx"> case State::SchemeStart:
</span><span class="cx"> LOG_FINAL_STATE("SchemeStart");
</span><del>- if (!m_buffer.length() && !base.isNull())
</del><ins>+ if (!m_asciiBuffer.size() && !base.isNull())
</ins><span class="cx"> return base;
</span><span class="cx"> return failure(input, length);
</span><span class="cx"> case State::Scheme:
</span><span class="lines">@@ -1369,7 +1402,7 @@
</span><span class="cx"> case State::RelativeSlash:
</span><span class="cx"> LOG_FINAL_STATE("RelativeSlash");
</span><span class="cx"> copyURLPartsUntil(base, URLPart::PortEnd);
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> m_url.m_pathAfterLastSlash = base.m_portEnd + 1;
</span><span class="cx"> m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx"> m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
</span><span class="lines">@@ -1377,7 +1410,7 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::SpecialAuthoritySlashes:
</span><span class="cx"> LOG_FINAL_STATE("SpecialAuthoritySlashes");
</span><del>- m_url.m_userStart = m_buffer.length();
</del><ins>+ m_url.m_userStart = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1393,7 +1426,7 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::AuthorityOrHost:
</span><span class="cx"> LOG_FINAL_STATE("AuthorityOrHost");
</span><del>- m_url.m_userEnd = m_buffer.length();
</del><ins>+ m_url.m_userEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx"> FALLTHROUGH;
</span><span class="cx"> case State::Host:
</span><span class="lines">@@ -1401,7 +1434,7 @@
</span><span class="cx"> LOG_FINAL_STATE("Host");
</span><span class="cx"> if (!parseHost(authorityOrHostBegin))
</span><span class="cx"> return failure(input, length);
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> m_url.m_pathEnd = m_url.m_portEnd + 1;
</span><span class="cx"> m_url.m_pathAfterLastSlash = m_url.m_pathEnd;
</span><span class="cx"> m_url.m_queryEnd = m_url.m_pathEnd;
</span><span class="lines">@@ -1411,10 +1444,10 @@
</span><span class="cx"> LOG_FINAL_STATE("File");
</span><span class="cx"> if (!base.isNull() && base.protocol() == "file") {
</span><span class="cx"> copyURLPartsUntil(base, URLPart::QueryEnd);
</span><del>- m_buffer.append(':');
</del><ins>+ m_asciiBuffer.append(':');
</ins><span class="cx"> }
</span><del>- m_buffer.append("///");
- m_url.m_userStart = m_buffer.length() - 1;
</del><ins>+ m_asciiBuffer.append("///", 3);
+ m_url.m_userStart = m_asciiBuffer.size() - 1;
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1426,8 +1459,8 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::FileSlash:
</span><span class="cx"> LOG_FINAL_STATE("FileSlash");
</span><del>- m_buffer.append("//");
- m_url.m_userStart = m_buffer.length() - 1;
</del><ins>+ m_asciiBuffer.append("//", 2);
+ m_url.m_userStart = m_asciiBuffer.size() - 1;
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1440,8 +1473,8 @@
</span><span class="cx"> case State::FileHost:
</span><span class="cx"> LOG_FINAL_STATE("FileHost");
</span><span class="cx"> if (authorityOrHostBegin == c) {
</span><del>- m_buffer.append('/');
- m_url.m_userStart = m_buffer.length() - 1;
</del><ins>+ m_asciiBuffer.append('/');
+ m_url.m_userStart = m_asciiBuffer.size() - 1;
</ins><span class="cx"> m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx"> m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1455,13 +1488,13 @@
</span><span class="cx">
</span><span class="cx"> if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
</span><span class="cx"> return failure(input, length);
</span><del>-
- if (bufferView(m_buffer, m_url.m_passwordEnd, m_buffer.length() - m_url.m_passwordEnd) == "localhost") {
- m_buffer.resize(m_url.m_passwordEnd);
- m_url.m_hostEnd = m_buffer.length();
</del><ins>+
+ if (StringView(m_asciiBuffer.data() + m_url.m_passwordEnd, m_asciiBuffer.size() - m_url.m_passwordEnd) == "localhost") {
+ m_asciiBuffer.shrink(m_url.m_passwordEnd);
+ m_url.m_hostEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_portEnd = m_url.m_hostEnd;
</span><span class="cx"> }
</span><del>- m_buffer.append('/');
</del><ins>+ m_asciiBuffer.append('/');
</ins><span class="cx"> m_url.m_pathAfterLastSlash = m_url.m_hostEnd + 1;
</span><span class="cx"> m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx"> m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
</span><span class="lines">@@ -1472,13 +1505,13 @@
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> case State::Path:
</span><span class="cx"> LOG_FINAL_STATE("Path");
</span><del>- m_url.m_pathEnd = m_buffer.length();
</del><ins>+ m_url.m_pathEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_queryEnd = m_url.m_pathEnd;
</span><span class="cx"> m_url.m_fragmentEnd = m_url.m_pathEnd;
</span><span class="cx"> break;
</span><span class="cx"> case State::CannotBeABaseURLPath:
</span><span class="cx"> LOG_FINAL_STATE("CannotBeABaseURLPath");
</span><del>- m_url.m_pathEnd = m_buffer.length();
</del><ins>+ m_url.m_pathEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_queryEnd = m_url.m_pathEnd;
</span><span class="cx"> m_url.m_fragmentEnd = m_url.m_pathEnd;
</span><span class="cx"> break;
</span><span class="lines">@@ -1485,17 +1518,27 @@
</span><span class="cx"> case State::Query:
</span><span class="cx"> LOG_FINAL_STATE("Query");
</span><span class="cx"> if (!isUTF8Encoding)
</span><del>- encodeQuery(queryBuffer, m_buffer, encoding);
- m_url.m_queryEnd = m_buffer.length();
</del><ins>+ encodeQuery(queryBuffer, m_asciiBuffer, encoding);
+ m_url.m_queryEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_fragmentEnd = m_url.m_queryEnd;
</span><span class="cx"> break;
</span><span class="cx"> case State::Fragment:
</span><span class="cx"> LOG_FINAL_STATE("Fragment");
</span><del>- m_url.m_fragmentEnd = m_buffer.length();
</del><ins>+ m_url.m_fragmentEnd = m_asciiBuffer.size() + m_unicodeFragmentBuffer.size();
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- m_url.m_string = m_buffer.toString();
</del><ins>+ if (m_unicodeFragmentBuffer.isEmpty()) {
+ // FIXME: String::adopt should require a WTFMove.
+ m_url.m_string = String::adopt(m_asciiBuffer);
+ } else {
+ StringBuilder builder;
+ builder.reserveCapacity(m_asciiBuffer.size() + m_unicodeFragmentBuffer.size());
+ builder.append(m_asciiBuffer.data(), m_asciiBuffer.size());
+ for (size_t i = 0; i < m_unicodeFragmentBuffer.size(); ++i)
+ builder.append(m_unicodeFragmentBuffer[i]);
+ m_url.m_string = builder.toString();
+ }
</ins><span class="cx"> m_url.m_isValid = true;
</span><span class="cx"> LOG(URLParser, "Parsed URL <%s>", m_url.m_string.utf8().data());
</span><span class="cx"> return m_url;
</span><span class="lines">@@ -1505,7 +1548,7 @@
</span><span class="cx"> void URLParser::parseAuthority(CodePointIterator<CharacterType> iterator)
</span><span class="cx"> {
</span><span class="cx"> if (iterator.atEnd()) {
</span><del>- m_url.m_userEnd = m_buffer.length();
</del><ins>+ m_url.m_userEnd = m_asciiBuffer.size();
</ins><span class="cx"> m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -1512,35 +1555,48 @@
</span><span class="cx"> for (; !iterator.atEnd(); ++iterator) {
</span><span class="cx"> if (*iterator == ':') {
</span><span class="cx"> ++iterator;
</span><del>- m_url.m_userEnd = m_buffer.length();
</del><ins>+ m_url.m_userEnd = m_asciiBuffer.size();
</ins><span class="cx"> if (iterator.atEnd()) {
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx"> if (m_url.m_userEnd > m_url.m_userStart)
</span><del>- m_buffer.append('@');
</del><ins>+ m_asciiBuffer.append('@');
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><del>- m_buffer.append(':');
</del><ins>+ m_asciiBuffer.append(':');
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>- utf8PercentEncode(*iterator, m_buffer, isInUserInfoEncodeSet);
</del><ins>+ utf8PercentEncode(*iterator, m_asciiBuffer, isInUserInfoEncodeSet);
</ins><span class="cx"> }
</span><span class="cx"> for (; !iterator.atEnd(); ++iterator)
</span><del>- utf8PercentEncode(*iterator, m_buffer, isInUserInfoEncodeSet);
- m_url.m_passwordEnd = m_buffer.length();
</del><ins>+ utf8PercentEncode(*iterator, m_asciiBuffer, isInUserInfoEncodeSet);
+ m_url.m_passwordEnd = m_asciiBuffer.size();
</ins><span class="cx"> if (!m_url.m_userEnd)
</span><span class="cx"> m_url.m_userEnd = m_url.m_passwordEnd;
</span><del>- m_buffer.append('@');
</del><ins>+ m_asciiBuffer.append('@');
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-static void serializeIPv4(uint32_t address, StringBuilder& buffer)
</del><ins>+template<typename UnsignedIntegerType>
+void append(Vector<LChar>& destination, UnsignedIntegerType number)
</ins><span class="cx"> {
</span><del>- buffer.appendNumber(address >> 24);
</del><ins>+ LChar buf[sizeof(UnsignedIntegerType) * 3 + 1];
+ LChar* end = buf + WTF_ARRAY_LENGTH(buf);
+ LChar* p = end;
+ do {
+ *--p = (number % 10) + '0';
+ number /= 10;
+ } while (number);
+ destination.append(p, end - p);
+}
+
+static void serializeIPv4(uint32_t address, Vector<LChar>& buffer)
+{
+ append<uint8_t>(buffer, address >> 24);
</ins><span class="cx"> buffer.append('.');
</span><del>- buffer.appendNumber((address >> 16) & 0xFF);
</del><ins>+ append<uint8_t>(buffer, address >> 16);
</ins><span class="cx"> buffer.append('.');
</span><del>- buffer.appendNumber((address >> 8) & 0xFF);
</del><ins>+ append<uint8_t>(buffer, address >> 8);
</ins><span class="cx"> buffer.append('.');
</span><del>- buffer.appendNumber(address & 0xFF);
</del><ins>+ append<uint8_t>(buffer, address);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static size_t zeroSequenceLength(const std::array<uint16_t, 8>& address, size_t begin)
</span><span class="lines">@@ -1570,7 +1626,7 @@
</span><span class="cx"> return longest;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void serializeIPv6Piece(uint16_t piece, StringBuilder& buffer)
</del><ins>+static void serializeIPv6Piece(uint16_t piece, Vector<LChar>& buffer)
</ins><span class="cx"> {
</span><span class="cx"> bool printed = false;
</span><span class="cx"> if (auto nibble0 = piece >> 12) {
</span><span class="lines">@@ -1588,7 +1644,7 @@
</span><span class="cx"> buffer.append(lowerNibbleToLowercaseASCIIHexDigit(piece & 0xF));
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void serializeIPv6(std::array<uint16_t, 8> address, StringBuilder& buffer)
</del><ins>+static void serializeIPv6(std::array<uint16_t, 8> address, Vector<LChar>& buffer)
</ins><span class="cx"> {
</span><span class="cx"> buffer.append('[');
</span><span class="cx"> auto compressPointer = findLongestZeroSequence(address);
</span><span class="lines">@@ -1598,7 +1654,7 @@
</span><span class="cx"> if (piece)
</span><span class="cx"> buffer.append(':');
</span><span class="cx"> else
</span><del>- buffer.append("::");
</del><ins>+ buffer.append("::", 2);
</ins><span class="cx"> while (piece < 8 && !address[piece])
</span><span class="cx"> piece++;
</span><span class="cx"> if (piece == 8)
</span><span class="lines">@@ -1880,10 +1936,10 @@
</span><span class="cx"> {
</span><span class="cx"> uint32_t port = 0;
</span><span class="cx"> if (iterator.atEnd()) {
</span><del>- m_url.m_portEnd = m_buffer.length();
</del><ins>+ m_url.m_portEnd = m_asciiBuffer.size();
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><del>- m_buffer.append(':');
</del><ins>+ m_asciiBuffer.append(':');
</ins><span class="cx"> for (; !iterator.atEnd(); ++iterator) {
</span><span class="cx"> if (isTabOrNewline(*iterator))
</span><span class="cx"> continue;
</span><span class="lines">@@ -1894,14 +1950,14 @@
</span><span class="cx"> } else
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><del>-
- if (isDefaultPort(bufferView(m_buffer, 0, m_url.m_schemeEnd), port)) {
- ASSERT(m_buffer[m_buffer.length() - 1] == ':');
- m_buffer.resize(m_buffer.length() - 1);
</del><ins>+
+ if (isDefaultPort(StringView(m_asciiBuffer.data(), m_url.m_schemeEnd), port)) {
+ ASSERT(m_asciiBuffer.last() == ':');
+ m_asciiBuffer.shrink(m_asciiBuffer.size() - 1);
</ins><span class="cx"> } else
</span><del>- m_buffer.appendNumber(port);
</del><ins>+ append<uint16_t>(m_asciiBuffer, static_cast<uint16_t>(port));
</ins><span class="cx">
</span><del>- m_url.m_portEnd = m_buffer.length();
</del><ins>+ m_url.m_portEnd = m_asciiBuffer.size();
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1916,8 +1972,8 @@
</span><span class="cx"> while (!ipv6End.atEnd() && *ipv6End != ']')
</span><span class="cx"> ++ipv6End;
</span><span class="cx"> if (auto address = parseIPv6Host(CodePointIterator<CharacterType>(iterator, ipv6End))) {
</span><del>- serializeIPv6(address.value(), m_buffer);
- m_url.m_hostEnd = m_buffer.length();
</del><ins>+ serializeIPv6(address.value(), m_asciiBuffer);
+ m_url.m_hostEnd = m_asciiBuffer.size();
</ins><span class="cx"> if (!ipv6End.atEnd()) {
</span><span class="cx"> ++ipv6End;
</span><span class="cx"> if (!ipv6End.atEnd() && *ipv6End == ':') {
</span><span class="lines">@@ -1924,7 +1980,7 @@
</span><span class="cx"> ++ipv6End;
</span><span class="cx"> return parsePort(ipv6End);
</span><span class="cx"> }
</span><del>- m_url.m_portEnd = m_buffer.length();
</del><ins>+ m_url.m_portEnd = m_asciiBuffer.size();
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> return true;
</span><span class="lines">@@ -1942,10 +1998,10 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> if (auto address = parseIPv4Host(CodePointIterator<CharacterType>(hostIterator, iterator))) {
</span><del>- serializeIPv4(address.value(), m_buffer);
- m_url.m_hostEnd = m_buffer.length();
</del><ins>+ serializeIPv4(address.value(), m_asciiBuffer);
+ m_url.m_hostEnd = m_asciiBuffer.size();
</ins><span class="cx"> if (iterator.atEnd()) {
</span><del>- m_url.m_portEnd = m_buffer.length();
</del><ins>+ m_url.m_portEnd = m_asciiBuffer.size();
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> ++iterator;
</span><span class="lines">@@ -1953,9 +2009,9 @@
</span><span class="cx"> }
</span><span class="cx"> for (; hostIterator != iterator; ++hostIterator) {
</span><span class="cx"> if (!isTabOrNewline(*hostIterator))
</span><del>- m_buffer.append(toASCIILower(*hostIterator));
</del><ins>+ m_asciiBuffer.append(toASCIILower(*hostIterator));
</ins><span class="cx"> }
</span><del>- m_url.m_hostEnd = m_buffer.length();
</del><ins>+ m_url.m_hostEnd = m_asciiBuffer.size();
</ins><span class="cx"> if (!hostIterator.atEnd()) {
</span><span class="cx"> ASSERT(*hostIterator == ':');
</span><span class="cx"> ++hostIterator;
</span><span class="lines">@@ -1963,7 +2019,7 @@
</span><span class="cx"> ++hostIterator;
</span><span class="cx"> return parsePort(hostIterator);
</span><span class="cx"> }
</span><del>- m_url.m_portEnd = m_buffer.length();
</del><ins>+ m_url.m_portEnd = m_asciiBuffer.size();
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1992,20 +2048,20 @@
</span><span class="cx"> String& asciiDomainValue = asciiDomain.value();
</span><span class="cx"> RELEASE_ASSERT(asciiDomainValue.is8Bit());
</span><span class="cx"> const LChar* asciiDomainCharacters = asciiDomainValue.characters8();
</span><del>-
</del><ins>+
</ins><span class="cx"> if (auto address = parseIPv4Host(CodePointIterator<LChar>(asciiDomainCharacters, asciiDomainCharacters + asciiDomainValue.length()))) {
</span><del>- serializeIPv4(address.value(), m_buffer);
- m_url.m_hostEnd = m_buffer.length();
</del><ins>+ serializeIPv4(address.value(), m_asciiBuffer);
+ m_url.m_hostEnd = m_asciiBuffer.size();
</ins><span class="cx"> if (iterator.atEnd()) {
</span><del>- m_url.m_portEnd = m_buffer.length();
</del><ins>+ m_url.m_portEnd = m_asciiBuffer.size();
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> ++iterator;
</span><span class="cx"> return parsePort(iterator);
</span><span class="cx"> }
</span><del>-
- m_buffer.append(asciiDomain.value());
- m_url.m_hostEnd = m_buffer.length();
</del><ins>+
+ m_asciiBuffer.append(asciiDomainCharacters, asciiDomainValue.length());
+ m_url.m_hostEnd = m_asciiBuffer.size();
</ins><span class="cx"> if (!iterator.atEnd()) {
</span><span class="cx"> ASSERT(*iterator == ':');
</span><span class="cx"> ++iterator;
</span><span class="lines">@@ -2013,7 +2069,7 @@
</span><span class="cx"> ++iterator;
</span><span class="cx"> return parsePort(iterator);
</span><span class="cx"> }
</span><del>- m_url.m_portEnd = m_buffer.length();
</del><ins>+ m_url.m_portEnd = m_asciiBuffer.size();
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -2047,7 +2103,7 @@
</span><span class="cx"> return output;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void serializeURLEncodedForm(const String& input, StringBuilder& output)
</del><ins>+static void serializeURLEncodedForm(const String& input, Vector<LChar>& output)
</ins><span class="cx"> {
</span><span class="cx"> auto utf8 = input.utf8(StrictConversion);
</span><span class="cx"> const char* data = utf8.data();
</span><span class="lines">@@ -2070,7 +2126,7 @@
</span><span class="cx">
</span><span class="cx"> String URLParser::serialize(const URLEncodedForm& tuples)
</span><span class="cx"> {
</span><del>- StringBuilder output;
</del><ins>+ Vector<LChar> output;
</ins><span class="cx"> for (auto& tuple : tuples) {
</span><span class="cx"> if (!output.isEmpty())
</span><span class="cx"> output.append('&');
</span><span class="lines">@@ -2078,7 +2134,7 @@
</span><span class="cx"> output.append('=');
</span><span class="cx"> serializeURLEncodedForm(tuple.second, output);
</span><span class="cx"> }
</span><del>- return output.toString();
</del><ins>+ return String::adopt(output);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> bool URLParser::allValuesEqual(const URL& a, const URL& b)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.h (206043 => 206044)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.h        2016-09-16 20:24:23 UTC (rev 206043)
+++ trunk/Source/WebCore/platform/URLParser.h        2016-09-16 20:35:16 UTC (rev 206044)
</span><span class="lines">@@ -48,7 +48,8 @@
</span><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> URL m_url;
</span><del>- StringBuilder m_buffer;
</del><ins>+ Vector<LChar> m_asciiBuffer;
+ Vector<UChar32> m_unicodeFragmentBuffer;
</ins><span class="cx"> bool m_urlIsSpecial { false };
</span><span class="cx"> bool m_hostHasPercentOrNonASCII { false };
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>