<!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>[209173] trunk/Source</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/209173">209173</a></dd>
<dt>Author</dt> <dd>darin@apple.com</dd>
<dt>Date</dt> <dd>2016-11-30 20:32:50 -0800 (Wed, 30 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Roll out StringBuilder changes from the previous patch.
They were a slowdown on a Kraken JSON test.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSONObjectcpp">trunk/Source/JavaScriptCore/runtime/JSONObject.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtftextStringBuildercpp">trunk/Source/WTF/wtf/text/StringBuilder.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextStringBuilderh">trunk/Source/WTF/wtf/text/StringBuilder.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209172 => 209173)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-01 03:56:12 UTC (rev 209172)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-01 04:32:50 UTC (rev 209173)
</span><span class="lines">@@ -1,3 +1,11 @@
</span><ins>+2016-11-30  Darin Adler  &lt;darin@apple.com&gt;
+
+        Roll out StringBuilder changes from the previous patch.
+        They were a slowdown on a Kraken JSON test.
+
+        * runtime/JSONObject.cpp:
+        Roll out changes from below.
+
</ins><span class="cx"> 2016-11-30  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Specifying same module entry point multiple times cause TypeError
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSONObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSONObject.cpp (209172 => 209173)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSONObject.cpp        2016-12-01 03:56:12 UTC (rev 209172)
+++ trunk/Source/JavaScriptCore/runtime/JSONObject.cpp        2016-12-01 04:32:50 UTC (rev 209173)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2009-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2009, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -354,7 +354,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (value.isString()) {
</span><del>-        builder.appendQuotedJSONString(asString(value)-&gt;viewWithUnderlyingString(*m_exec).view);
</del><ins>+        builder.appendQuotedJSONString(asString(value)-&gt;value(m_exec));
</ins><span class="cx">         return StringifySucceeded;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (209172 => 209173)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-12-01 03:56:12 UTC (rev 209172)
+++ trunk/Source/WTF/ChangeLog        2016-12-01 04:32:50 UTC (rev 209173)
</span><span class="lines">@@ -1,5 +1,14 @@
</span><span class="cx"> 2016-11-30  Darin Adler  &lt;darin@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Roll out StringBuilder changes from the previous patch.
+        They were a slowdown on a Kraken JSON test.
+
+        * wtf/text/StringBuilder.cpp:
+        * wtf/text/StringBuilder.h:
+        Roll out changes from below.
+
+2016-11-30  Darin Adler  &lt;darin@apple.com&gt;
+
</ins><span class="cx">         Streamline and speed up tokenizer and segmented string classes
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=165003
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringBuildercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringBuilder.cpp (209172 => 209173)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringBuilder.cpp        2016-12-01 03:56:12 UTC (rev 209172)
+++ trunk/Source/WTF/wtf/text/StringBuilder.cpp        2016-12-01 04:32:50 UTC (rev 209173)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2010-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2012 Google Inc. All rights reserved.
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;IntegerToStringConversion.h&quot;
</span><span class="cx"> #include &quot;MathExtras.h&quot;
</span><ins>+#include &quot;WTFString.h&quot;
</ins><span class="cx"> #include &lt;wtf/dtoa.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="lines">@@ -39,18 +40,6 @@
</span><span class="cx">     return std::max(requiredLength, std::max(minimumCapacity, capacity * 2));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;&gt; ALWAYS_INLINE LChar* StringBuilder::bufferCharacters&lt;LChar&gt;()
-{
-    ASSERT(m_is8Bit);
-    return m_bufferCharacters8;
-}
-
-template&lt;&gt; ALWAYS_INLINE UChar* StringBuilder::bufferCharacters&lt;UChar&gt;()
-{
-    ASSERT(!m_is8Bit);
-    return m_bufferCharacters16;
-}
-
</del><span class="cx"> void StringBuilder::reifyString() const
</span><span class="cx"> {
</span><span class="cx">     // Check if the string already exists.
</span><span class="lines">@@ -108,7 +97,6 @@
</span><span class="cx"> void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requiredLength)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_is8Bit);
</span><del>-
</del><span class="cx">     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
</span><span class="cx">     auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters8);
</span><span class="cx">     memcpy(m_bufferCharacters8, currentCharacters, static_cast&lt;size_t&gt;(m_length) * sizeof(LChar)); // This can't overflow.
</span><span class="lines">@@ -124,7 +112,6 @@
</span><span class="cx"> void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requiredLength)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_is8Bit);
</span><del>-
</del><span class="cx">     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
</span><span class="cx">     auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16);
</span><span class="cx">     memcpy(m_bufferCharacters16, currentCharacters, static_cast&lt;size_t&gt;(m_length) * sizeof(UChar)); // This can't overflow.
</span><span class="lines">@@ -137,11 +124,10 @@
</span><span class="cx"> 
</span><span class="cx"> // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit and may come
</span><span class="cx"> // from either m_string or m_buffer, neither will be reassigned until the copy has completed).
</span><del>-void StringBuilder::allocateBufferUpconvert(const LChar* currentCharacters, unsigned requiredLength)
</del><ins>+void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_is8Bit);
</span><span class="cx">     ASSERT(requiredLength &gt;= m_length);
</span><del>-
</del><span class="cx">     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
</span><span class="cx">     auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16);
</span><span class="cx">     for (unsigned i = 0; i &lt; m_length; ++i)
</span><span class="lines">@@ -155,7 +141,8 @@
</span><span class="cx">     ASSERT(m_buffer-&gt;length() == requiredLength);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;&gt; void StringBuilder::reallocateBuffer&lt;LChar&gt;(unsigned requiredLength)
</del><ins>+template &lt;&gt;
+void StringBuilder::reallocateBuffer&lt;LChar&gt;(unsigned requiredLength)
</ins><span class="cx"> {
</span><span class="cx">     // If the buffer has only one ref (by this StringBuilder), reallocate it,
</span><span class="cx">     // otherwise fall back to &quot;allocate and copy&quot; method.
</span><span class="lines">@@ -171,7 +158,8 @@
</span><span class="cx">     ASSERT(m_buffer-&gt;length() == requiredLength);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;&gt; void StringBuilder::reallocateBuffer&lt;UChar&gt;(unsigned requiredLength)
</del><ins>+template &lt;&gt;
+void StringBuilder::reallocateBuffer&lt;UChar&gt;(unsigned requiredLength)
</ins><span class="cx"> {
</span><span class="cx">     // If the buffer has only one ref (by this StringBuilder), reallocate it,
</span><span class="cx">     // otherwise fall back to &quot;allocate and copy&quot; method.
</span><span class="lines">@@ -178,7 +166,7 @@
</span><span class="cx">     m_string = String();
</span><span class="cx">     
</span><span class="cx">     if (m_buffer-&gt;is8Bit())
</span><del>-        allocateBufferUpconvert(m_buffer-&gt;characters8(), requiredLength);
</del><ins>+        allocateBufferUpConvert(m_buffer-&gt;characters8(), requiredLength);
</ins><span class="cx">     else if (m_buffer-&gt;hasOneRef())
</span><span class="cx">         m_buffer = StringImpl::reallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters16);
</span><span class="cx">     else
</span><span class="lines">@@ -200,7 +188,7 @@
</span><span class="cx">         // Grow the string, if necessary.
</span><span class="cx">         if (newCapacity &gt; m_length) {
</span><span class="cx">             if (!m_length) {
</span><del>-                LChar* nullPlaceholder = nullptr;
</del><ins>+                LChar* nullPlaceholder = 0;
</ins><span class="cx">                 allocateBuffer(nullPlaceholder, newCapacity);
</span><span class="cx">             } else if (m_string.is8Bit())
</span><span class="cx">                 allocateBuffer(m_string.characters8(), newCapacity);
</span><span class="lines">@@ -213,7 +201,8 @@
</span><span class="cx"> 
</span><span class="cx"> // Make 'length' additional capacity be available in m_buffer, update m_string &amp; m_length,
</span><span class="cx"> // return a pointer to the newly allocated storage.
</span><del>-template&lt;typename CharacterType&gt; ALWAYS_INLINE CharacterType* StringBuilder::appendUninitialized(unsigned length)
</del><ins>+template &lt;typename CharType&gt;
+ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(length);
</span><span class="cx"> 
</span><span class="lines">@@ -228,15 +217,16 @@
</span><span class="cx">         unsigned currentLength = m_length;
</span><span class="cx">         m_string = String();
</span><span class="cx">         m_length = requiredLength;
</span><del>-        return bufferCharacters&lt;CharacterType&gt;() + currentLength;
</del><ins>+        return getBufferCharacters&lt;CharType&gt;() + currentLength;
</ins><span class="cx">     }
</span><del>-
-    return appendUninitializedSlow&lt;CharacterType&gt;(requiredLength);
</del><ins>+    
+    return appendUninitializedSlow&lt;CharType&gt;(requiredLength);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Make 'length' additional capacity be available in m_buffer, update m_string &amp; m_length,
</span><span class="cx"> // return a pointer to the newly allocated storage.
</span><del>-template&lt;typename CharacterType&gt; CharacterType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
</del><ins>+template &lt;typename CharType&gt;
+CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(requiredLength);
</span><span class="cx"> 
</span><span class="lines">@@ -243,38 +233,19 @@
</span><span class="cx">     if (m_buffer) {
</span><span class="cx">         // If the buffer is valid it must be at least as long as the current builder contents!
</span><span class="cx">         ASSERT(m_buffer-&gt;length() &gt;= m_length);
</span><del>-        reallocateBuffer&lt;CharacterType&gt;(expandedCapacity(capacity(), requiredLength));
</del><ins>+        
+        reallocateBuffer&lt;CharType&gt;(expandedCapacity(capacity(), requiredLength));
</ins><span class="cx">     } else {
</span><span class="cx">         ASSERT(m_string.length() == m_length);
</span><del>-        allocateBuffer(m_length ? m_string.characters&lt;CharacterType&gt;() : nullptr, expandedCapacity(capacity(), requiredLength));
</del><ins>+        allocateBuffer(m_length ? m_string.characters&lt;CharType&gt;() : 0, expandedCapacity(capacity(), requiredLength));
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    auto* result = bufferCharacters&lt;CharacterType&gt;() + m_length;
</del><ins>+    CharType* result = getBufferCharacters&lt;CharType&gt;() + m_length;
</ins><span class="cx">     m_length = requiredLength;
</span><span class="cx">     ASSERT(m_buffer-&gt;length() &gt;= m_length);
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline UChar* StringBuilder::appendUninitializedUpconvert(unsigned length)
-{
-    unsigned requiredLength = length + m_length;
-    if (requiredLength &lt; length)
-        CRASH();
-
-    if (m_buffer) {
-        // If the buffer is valid it must be at least as long as the current builder contents!
-        ASSERT(m_buffer-&gt;length() &gt;= m_length);
-        allocateBufferUpconvert(m_buffer-&gt;characters8(), expandedCapacity(capacity(), requiredLength));
-    } else {
-        ASSERT(m_string.length() == m_length);
-        allocateBufferUpconvert(m_string.isNull() ? nullptr : m_string.characters8(), expandedCapacity(capacity(), requiredLength));
-    }
-
-    auto* result = m_bufferCharacters16 + m_length;
-    m_length = requiredLength;
-    return result;
-}
-
</del><span class="cx"> void StringBuilder::append(const UChar* characters, unsigned length)
</span><span class="cx"> {
</span><span class="cx">     if (!length)
</span><span class="lines">@@ -283,16 +254,32 @@
</span><span class="cx">     ASSERT(characters);
</span><span class="cx"> 
</span><span class="cx">     if (m_is8Bit) {
</span><del>-        if (length == 1 &amp;&amp; !(*characters &amp; ~0xFF)) {
</del><ins>+        if (length == 1 &amp;&amp; !(*characters &amp; ~0xff)) {
</ins><span class="cx">             // Append as 8 bit character
</span><span class="cx">             LChar lChar = static_cast&lt;LChar&gt;(*characters);
</span><span class="cx">             append(&amp;lChar, 1);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        memcpy(appendUninitializedUpconvert(length), characters, static_cast&lt;size_t&gt;(length) * sizeof(UChar));
</del><ins>+
+        // Calculate the new size of the builder after appending.
+        unsigned requiredLength = length + m_length;
+        if (requiredLength &lt; length)
+            CRASH();
+        
+        if (m_buffer) {
+            // If the buffer is valid it must be at least as long as the current builder contents!
+            ASSERT(m_buffer-&gt;length() &gt;= m_length);
+            
+            allocateBufferUpConvert(m_buffer-&gt;characters8(), expandedCapacity(capacity(), requiredLength));
+        } else {
+            ASSERT(m_string.length() == m_length);
+            allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), expandedCapacity(capacity(), requiredLength));
+        }
+
+        memcpy(m_bufferCharacters16 + m_length, characters, static_cast&lt;size_t&gt;(length) * sizeof(UChar));
+        m_length = requiredLength;
</ins><span class="cx">     } else
</span><span class="cx">         memcpy(appendUninitialized&lt;UChar&gt;(length), characters, static_cast&lt;size_t&gt;(length) * sizeof(UChar));
</span><del>-
</del><span class="cx">     ASSERT(m_buffer-&gt;length() &gt;= m_length);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -303,22 +290,19 @@
</span><span class="cx">     ASSERT(characters);
</span><span class="cx"> 
</span><span class="cx">     if (m_is8Bit) {
</span><del>-        auto* destination = appendUninitialized&lt;LChar&gt;(length);
-        // FIXME: How did we determine a threshold of 8 here was the right one?
-        // Also, this kind of optimization could be useful anywhere else we have a
-        // performance-sensitive code path that calls memcpy.
</del><ins>+        LChar* dest = appendUninitialized&lt;LChar&gt;(length);
</ins><span class="cx">         if (length &gt; 8)
</span><del>-            memcpy(destination, characters, length);
</del><ins>+            memcpy(dest, characters, static_cast&lt;size_t&gt;(length) * sizeof(LChar));
</ins><span class="cx">         else {
</span><span class="cx">             const LChar* end = characters + length;
</span><span class="cx">             while (characters &lt; end)
</span><del>-                *destination++ = *characters++;
</del><ins>+                *(dest++) = *(characters++);
</ins><span class="cx">         }
</span><span class="cx">     } else {
</span><del>-        auto* destination = appendUninitialized&lt;UChar&gt;(length);
</del><ins>+        UChar* dest = appendUninitialized&lt;UChar&gt;(length);
</ins><span class="cx">         const LChar* end = characters + length;
</span><span class="cx">         while (characters &lt; end)
</span><del>-            *destination++ = *characters++;
</del><ins>+            *(dest++) = *(characters++);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -401,58 +385,17 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;typename LengthType, typename CharacterType&gt; static LengthType quotedJSONStringLength(const CharacterType* input, unsigned length)
</del><ins>+template &lt;typename OutputCharacterType, typename InputCharacterType&gt;
+static void appendQuotedJSONStringInternal(OutputCharacterType*&amp; output, const InputCharacterType* input, unsigned length)
</ins><span class="cx"> {
</span><del>-    LengthType quotedLength = 2;
-    for (unsigned i = 0; i &lt; length; ++i) {
-        auto character = input[i];
-        if (LIKELY(character &gt; 0x1F)) {
-            switch (character) {
-            case '&quot;':
-            case '\\':
-                quotedLength += 2;
-                break;
-            default:
-                ++quotedLength;
-                break;
-            }
-        } else {
-            switch (character) {
-            case '\t':
-            case '\r':
-            case '\n':
-            case '\f':
-            case '\b':
-                quotedLength += 2;
-                break;
-            default:
-                quotedLength += 6;
-            }
-        }
-    }
-    return quotedLength;
-}
-
-template&lt;typename CharacterType&gt; static inline unsigned quotedJSONStringLength(const CharacterType* input, unsigned length)
-{
-    constexpr auto maxSafeLength = (std::numeric_limits&lt;unsigned&gt;::max() - 2) / 6;
-    if (length &lt;= maxSafeLength)
-        return quotedJSONStringLength&lt;unsigned&gt;(input, length);
-    return quotedJSONStringLength&lt;Checked&lt;unsigned&gt;&gt;(input, length).unsafeGet();
-}
-
-template&lt;typename OutputCharacterType, typename InputCharacterType&gt; static inline void appendQuotedJSONStringInternal(OutputCharacterType* output, const InputCharacterType* input, unsigned length)
-{
-    *output++ = '&quot;';
-    for (unsigned i = 0; i &lt; length; ++i) {
-        auto character = input[i];
-        if (LIKELY(character &gt; 0x1F)) {
-            if (UNLIKELY(character == '&quot;' || character == '\\'))
</del><ins>+    for (const InputCharacterType* end = input + length; input != end; ++input) {
+        if (LIKELY(*input &gt; 0x1F)) {
+            if (*input == '&quot;' || *input == '\\')
</ins><span class="cx">                 *output++ = '\\';
</span><del>-            *output++ = character;
</del><ins>+            *output++ = *input;
</ins><span class="cx">             continue;
</span><span class="cx">         }
</span><del>-        switch (character) {
</del><ins>+        switch (*input) {
</ins><span class="cx">         case '\t':
</span><span class="cx">             *output++ = '\\';
</span><span class="cx">             *output++ = 't';
</span><span class="lines">@@ -474,35 +417,56 @@
</span><span class="cx">             *output++ = 'b';
</span><span class="cx">             break;
</span><span class="cx">         default:
</span><del>-            ASSERT(!(character &amp; ~0xFF));
</del><ins>+            ASSERT((*input &amp; 0xFF00) == 0);
+            static const char hexDigits[] = &quot;0123456789abcdef&quot;;
</ins><span class="cx">             *output++ = '\\';
</span><span class="cx">             *output++ = 'u';
</span><span class="cx">             *output++ = '0';
</span><span class="cx">             *output++ = '0';
</span><del>-            *output++ = upperNibbleToLowercaseASCIIHexDigit(character);
-            *output++ = lowerNibbleToLowercaseASCIIHexDigit(character);
</del><ins>+            *output++ = static_cast&lt;LChar&gt;(hexDigits[(*input &gt;&gt; 4) &amp; 0xF]);
+            *output++ = static_cast&lt;LChar&gt;(hexDigits[*input &amp; 0xF]);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    *output = '&quot;';
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void StringBuilder::appendQuotedJSONString(StringView string)
</del><ins>+void StringBuilder::appendQuotedJSONString(const String&amp; string)
</ins><span class="cx"> {
</span><del>-    unsigned length = string.length();
-    if (string.is8Bit()) {
-        auto* characters = string.characters8();
-        if (m_is8Bit)
-            appendQuotedJSONStringInternal(appendUninitialized&lt;LChar&gt;(quotedJSONStringLength(characters, length)), characters, length);
-        else
-            appendQuotedJSONStringInternal(appendUninitialized&lt;UChar&gt;(quotedJSONStringLength(characters, length)), characters, length);
</del><ins>+    // Make sure we have enough buffer space to append this string without having
+    // to worry about reallocating in the middle.
+    // The 2 is for the '&quot;' quotes on each end.
+    // The 6 is for characters that need to be \uNNNN encoded.
+    Checked&lt;unsigned&gt; stringLength = string.length();
+    Checked&lt;unsigned&gt; maximumCapacityRequired = length();
+    maximumCapacityRequired += 2 + stringLength * 6;
+    unsigned allocationSize = maximumCapacityRequired.unsafeGet();
+    // This max() is here to allow us to allocate sizes between the range [2^31, 2^32 - 2] because roundUpToPowerOfTwo(1&lt;&lt;31 + some int smaller than 1&lt;&lt;31) == 0.
+    allocationSize = std::max(allocationSize, roundUpToPowerOfTwo(allocationSize));
+
+    if (is8Bit() &amp;&amp; !string.is8Bit())
+        allocateBufferUpConvert(m_bufferCharacters8, allocationSize);
+    else
+        reserveCapacity(allocationSize);
+    ASSERT(m_buffer-&gt;length() &gt;= allocationSize);
+
+    if (is8Bit()) {
+        ASSERT(string.is8Bit());
+        LChar* output = m_bufferCharacters8 + m_length;
+        *output++ = '&quot;';
+        appendQuotedJSONStringInternal(output, string.characters8(), string.length());
+        *output++ = '&quot;';
+        m_length = output - m_bufferCharacters8;
</ins><span class="cx">     } else {
</span><del>-        auto* characters = string.characters16();
-        if (m_is8Bit)
-            appendQuotedJSONStringInternal(appendUninitializedUpconvert(quotedJSONStringLength(characters, length)), characters, length);
</del><ins>+        UChar* output = m_bufferCharacters16 + m_length;
+        *output++ = '&quot;';
+        if (string.is8Bit())
+            appendQuotedJSONStringInternal(output, string.characters8(), string.length());
</ins><span class="cx">         else
</span><del>-            appendQuotedJSONStringInternal(appendUninitialized&lt;UChar&gt;(quotedJSONStringLength(characters, length)), characters, length);
</del><ins>+            appendQuotedJSONStringInternal(output, string.characters16(), string.length());
+        *output++ = '&quot;';
+        m_length = output - m_bufferCharacters16;
</ins><span class="cx">     }
</span><ins>+    ASSERT(m_buffer-&gt;length() &gt;= m_length);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WTF
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringBuilderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringBuilder.h (209172 => 209173)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringBuilder.h        2016-12-01 03:56:12 UTC (rev 209172)
+++ trunk/Source/WTF/wtf/text/StringBuilder.h        2016-12-01 04:32:50 UTC (rev 209173)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2009-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2009-2010, 2012-2013, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2012 Google Inc. All rights reserved.
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -24,18 +24,26 @@
</span><span class="cx">  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-#pragma once
</del><ins>+#ifndef StringBuilder_h
+#define StringBuilder_h
</ins><span class="cx"> 
</span><ins>+#include &lt;wtf/text/AtomicString.h&gt;
</ins><span class="cx"> #include &lt;wtf/text/StringView.h&gt;
</span><ins>+#include &lt;wtf/text/WTFString.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><span class="cx"> class StringBuilder {
</span><del>-    // Disallow copying since it's expensive and we don't want anyone to do it by accident.
</del><ins>+    // Disallow copying since it's expensive and we don't want code to do it by accident.
</ins><span class="cx">     WTF_MAKE_NONCOPYABLE(StringBuilder);
</span><span class="cx"> 
</span><span class="cx"> public:
</span><del>-    StringBuilder() = default;
</del><ins>+    StringBuilder()
+        : m_length(0)
+        , m_is8Bit(true)
+        , m_bufferCharacters8(0)
+    {
+    }
</ins><span class="cx"> 
</span><span class="cx">     WTF_EXPORT_PRIVATE void append(const UChar*, unsigned);
</span><span class="cx">     WTF_EXPORT_PRIVATE void append(const LChar*, unsigned);
</span><span class="lines">@@ -42,27 +50,29 @@
</span><span class="cx"> 
</span><span class="cx">     ALWAYS_INLINE void append(const char* characters, unsigned length) { append(reinterpret_cast&lt;const LChar*&gt;(characters), length); }
</span><span class="cx"> 
</span><del>-    void append(const AtomicString&amp; atomicString) { append(atomicString.string()); }
</del><ins>+    void append(const AtomicString&amp; atomicString)
+    {
+        append(atomicString.string());
+    }
</ins><span class="cx"> 
</span><span class="cx">     void append(const String&amp; string)
</span><span class="cx">     {
</span><del>-        unsigned length = string.length();
-        if (!length)
</del><ins>+        if (!string.length())
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        // If we're appending to an empty string, and there is not a buffer
-        // (reserveCapacity has not been called) then just retain the string.
</del><ins>+        // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
+        // then just retain the string.
</ins><span class="cx">         if (!m_length &amp;&amp; !m_buffer) {
</span><span class="cx">             m_string = string;
</span><del>-            m_length = length;
-            m_is8Bit = string.is8Bit();
</del><ins>+            m_length = string.length();
+            m_is8Bit = m_string.is8Bit();
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (string.is8Bit())
</span><del>-            append(string.characters8(), length);
</del><ins>+            append(string.characters8(), string.length());
</ins><span class="cx">         else
</span><del>-            append(string.characters16(), length);
</del><ins>+            append(string.characters16(), string.length());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void append(const StringBuilder&amp; other)
</span><span class="lines">@@ -70,12 +80,11 @@
</span><span class="cx">         if (!other.m_length)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        // If we're appending to an empty string, and there is not a buffer
-        // (reserveCapacity has not been called) then just retain the string.
</del><ins>+        // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
+        // then just retain the string.
</ins><span class="cx">         if (!m_length &amp;&amp; !m_buffer &amp;&amp; !other.m_string.isNull()) {
</span><span class="cx">             m_string = other.m_string;
</span><span class="cx">             m_length = other.m_length;
</span><del>-            m_is8Bit = other.m_is8Bit;
</del><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -96,7 +105,6 @@
</span><span class="cx"> #if USE(CF)
</span><span class="cx">     WTF_EXPORT_PRIVATE void append(CFStringRef);
</span><span class="cx"> #endif
</span><del>-
</del><span class="cx"> #if USE(CF) &amp;&amp; defined(__OBJC__)
</span><span class="cx">     void append(NSString *string) { append((__bridge CFStringRef)string); }
</span><span class="cx"> #endif
</span><span class="lines">@@ -103,20 +111,11 @@
</span><span class="cx">     
</span><span class="cx">     void append(const String&amp; string, unsigned offset, unsigned length)
</span><span class="cx">     {
</span><del>-        ASSERT(offset &lt;= string.length());
-        ASSERT(offset + length &lt;= string.length());
-
-        if (!length)
</del><ins>+        if (!string.length())
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        // If we're appending to an empty string, and there is not a buffer
-        // (reserveCapacity has not been called) then just retain the string.
-        if (!offset &amp;&amp; !m_length &amp;&amp; !m_buffer &amp;&amp; length == string.length()) {
-            m_string = string;
-            m_length = length;
-            m_is8Bit = string.is8Bit();
</del><ins>+        if ((offset + length) &gt; string.length())
</ins><span class="cx">             return;
</span><del>-        }
</del><span class="cx"> 
</span><span class="cx">         if (string.is8Bit())
</span><span class="cx">             append(string.characters8() + offset, length);
</span><span class="lines">@@ -130,33 +129,37 @@
</span><span class="cx">             append(characters, strlen(characters));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void append(UChar character)
</del><ins>+    void append(UChar c)
</ins><span class="cx">     {
</span><span class="cx">         if (m_buffer &amp;&amp; m_length &lt; m_buffer-&gt;length() &amp;&amp; m_string.isNull()) {
</span><span class="cx">             if (!m_is8Bit) {
</span><del>-                m_bufferCharacters16[m_length++] = character;
</del><ins>+                m_bufferCharacters16[m_length++] = c;
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><del>-            if (!(character &amp; ~0xFF)) {
-                m_bufferCharacters8[m_length++] = static_cast&lt;LChar&gt;(character);
</del><ins>+
+            if (!(c &amp; ~0xff)) {
+                m_bufferCharacters8[m_length++] = static_cast&lt;LChar&gt;(c);
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-        append(&amp;character, 1);
</del><ins>+        append(&amp;c, 1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void append(LChar character)
</del><ins>+    void append(LChar c)
</ins><span class="cx">     {
</span><span class="cx">         if (m_buffer &amp;&amp; m_length &lt; m_buffer-&gt;length() &amp;&amp; m_string.isNull()) {
</span><span class="cx">             if (m_is8Bit)
</span><del>-                m_bufferCharacters8[m_length++] = character;
</del><ins>+                m_bufferCharacters8[m_length++] = c;
</ins><span class="cx">             else
</span><del>-                m_bufferCharacters16[m_length++] = character;
</del><ins>+                m_bufferCharacters16[m_length++] = c;
</ins><span class="cx">         } else
</span><del>-            append(&amp;character, 1);
</del><ins>+            append(&amp;c, 1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void append(char character) { append(static_cast&lt;LChar&gt;(character)); }
</del><ins>+    void append(char c)
+    {
+        append(static_cast&lt;LChar&gt;(c));
+    }
</ins><span class="cx"> 
</span><span class="cx">     void append(UChar32 c)
</span><span class="cx">     {
</span><span class="lines">@@ -168,9 +171,10 @@
</span><span class="cx">         append(U16_TRAIL(c));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    WTF_EXPORT_PRIVATE void appendQuotedJSONString(StringView);
</del><ins>+    WTF_EXPORT_PRIVATE void appendQuotedJSONString(const String&amp;);
</ins><span class="cx"> 
</span><del>-    template&lt;unsigned charactersCount&gt; ALWAYS_INLINE void appendLiteral(const char (&amp;characters)[charactersCount]) { append(characters, charactersCount - 1); }
</del><ins>+    template&lt;unsigned charactersCount&gt;
+    ALWAYS_INLINE void appendLiteral(const char (&amp;characters)[charactersCount]) { append(characters, charactersCount - 1); }
</ins><span class="cx"> 
</span><span class="cx">     WTF_EXPORT_PRIVATE void appendNumber(int);
</span><span class="cx">     WTF_EXPORT_PRIVATE void appendNumber(unsigned int);
</span><span class="lines">@@ -216,15 +220,24 @@
</span><span class="cx">         return AtomicString(m_buffer.get(), 0, m_length);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    unsigned length() const { return m_length; }
</del><ins>+    unsigned length() const
+    {
+        return m_length;
+    }
+
</ins><span class="cx">     bool isEmpty() const { return !m_length; }
</span><span class="cx"> 
</span><span class="cx">     WTF_EXPORT_PRIVATE void reserveCapacity(unsigned newCapacity);
</span><span class="cx"> 
</span><del>-    unsigned capacity() const { return m_buffer ? m_buffer-&gt;length() : m_length; }
</del><ins>+    unsigned capacity() const
+    {
+        return m_buffer ? m_buffer-&gt;length() : m_length;
+    }
</ins><span class="cx"> 
</span><span class="cx">     WTF_EXPORT_PRIVATE void resize(unsigned newSize);
</span><ins>+
</ins><span class="cx">     WTF_EXPORT_PRIVATE bool canShrink() const;
</span><ins>+
</ins><span class="cx">     WTF_EXPORT_PRIVATE void shrinkToFit();
</span><span class="cx"> 
</span><span class="cx">     UChar operator[](unsigned i) const
</span><span class="lines">@@ -281,36 +294,43 @@
</span><span class="cx"> private:
</span><span class="cx">     void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength);
</span><span class="cx">     void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
</span><del>-    void allocateBufferUpconvert(const LChar* currentCharacters, unsigned requiredLength);
-    template&lt;typename CharacterType&gt; void reallocateBuffer(unsigned requiredLength);
-    UChar* appendUninitializedUpconvert(unsigned length);
-    template&lt;typename CharacterType&gt; CharacterType* appendUninitialized(unsigned length);
-    template&lt;typename CharacterType&gt; CharacterType* appendUninitializedSlow(unsigned length);
-    template&lt;typename CharacterType&gt; CharacterType* bufferCharacters();
</del><ins>+    void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength);
+    template &lt;typename CharType&gt;
+    void reallocateBuffer(unsigned requiredLength);
+    template &lt;typename CharType&gt;
+    ALWAYS_INLINE CharType* appendUninitialized(unsigned length);
+    template &lt;typename CharType&gt;
+    CharType* appendUninitializedSlow(unsigned length);
+    template &lt;typename CharType&gt;
+    ALWAYS_INLINE CharType * getBufferCharacters();
</ins><span class="cx">     WTF_EXPORT_PRIVATE void reifyString() const;
</span><span class="cx"> 
</span><del>-    unsigned m_length { 0 };
</del><ins>+    unsigned m_length;
</ins><span class="cx">     mutable String m_string;
</span><span class="cx">     RefPtr&lt;StringImpl&gt; m_buffer;
</span><del>-    bool m_is8Bit { true };
</del><ins>+    bool m_is8Bit;
</ins><span class="cx">     union {
</span><del>-        LChar* m_bufferCharacters8 { nullptr };
</del><ins>+        LChar* m_bufferCharacters8;
</ins><span class="cx">         UChar* m_bufferCharacters16;
</span><span class="cx">     };
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-template&lt;typename StringType&gt; bool equal(const StringBuilder&amp;, const StringType&amp;);
-bool equal(const StringBuilder&amp;, const String&amp;); // Only needed because is8Bit dereferences nullptr when the string is null.
-template&lt;typename CharacterType&gt; bool equal(const StringBuilder&amp;, const CharacterType*, unsigned length);
</del><ins>+template &lt;&gt;
+ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters&lt;LChar&gt;()
+{
+    ASSERT(m_is8Bit);
+    return m_bufferCharacters8;
+}
</ins><span class="cx"> 
</span><del>-bool operator==(const StringBuilder&amp;, const StringBuilder&amp;);
-bool operator!=(const StringBuilder&amp;, const StringBuilder&amp;);
-bool operator==(const StringBuilder&amp;, const String&amp;);
-bool operator!=(const StringBuilder&amp;, const String&amp;);
-bool operator==(const String&amp;, const StringBuilder&amp;);
-bool operator!=(const String&amp;, const StringBuilder&amp;);
</del><ins>+template &lt;&gt;
+ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters&lt;UChar&gt;()
+{
+    ASSERT(!m_is8Bit);
+    return m_bufferCharacters16;
+}    
</ins><span class="cx"> 
</span><del>-template&lt;typename CharacterType&gt; inline bool equal(const StringBuilder&amp; s, const CharacterType* buffer, unsigned length)
</del><ins>+template &lt;typename CharType&gt;
+bool equal(const StringBuilder&amp; s, const CharType* buffer, unsigned length)
</ins><span class="cx"> {
</span><span class="cx">     if (s.length() != length)
</span><span class="cx">         return false;
</span><span class="lines">@@ -321,18 +341,24 @@
</span><span class="cx">     return equal(s.characters16(), buffer, length);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;typename StringType&gt; inline bool equal(const StringBuilder&amp; a, const StringType&amp; b)
</del><ins>+template &lt;typename StringType&gt;
+bool equal(const StringBuilder&amp; a, const StringType&amp; b)
</ins><span class="cx"> {
</span><del>-    return equalCommon(a, b);
-}
</del><ins>+    if (a.length() != b.length())
+        return false;
</ins><span class="cx"> 
</span><del>-inline bool equal(const StringBuilder&amp; a, const String&amp; b)
-{
-    // FIXME: This preserves historic behavior where an empty StringBuilder compares as equal
-    // to a null String. This does not seem like desirable behavior since a null String and
-    // an empty String do not compare as equal, but we have regression tests expecting it,
-    // and there is a slim chance we also have code depending on it.
-    return b.isNull() ? a.isEmpty() : equalCommon(a, b);
</del><ins>+    if (!a.length())
+        return true;
+
+    if (a.is8Bit()) {
+        if (b.is8Bit())
+            return equal(a.characters8(), b.characters8(), a.length());
+        return equal(a.characters8(), b.characters16(), a.length());
+    }
+
+    if (b.is8Bit())
+        return equal(a.characters16(), b.characters8(), a.length());
+    return equal(a.characters16(), b.characters16(), a.length());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool operator==(const StringBuilder&amp; a, const StringBuilder&amp; b) { return equal(a, b); }
</span><span class="lines">@@ -345,3 +371,5 @@
</span><span class="cx"> } // namespace WTF
</span><span class="cx"> 
</span><span class="cx"> using WTF::StringBuilder;
</span><ins>+
+#endif // StringBuilder_h
</ins></span></pre>
</div>
</div>

</body>
</html>