<!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>[168256] 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/168256">168256</a></dd>
<dt>Author</dt> <dd>akling@apple.com</dd>
<dt>Date</dt> <dd>2014-05-04 23:24:44 -0700 (Sun, 04 May 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Optimize JSRopeString for resolving directly to AtomicString.
&lt;https://webkit.org/b/132548&gt;

Source/JavaScriptCore:
If we know that the JSRopeString we are resolving is going to be used
as an AtomicString, we can try to avoid creating a new string.

We do this by first resolving the rope into a stack buffer, and using
that buffer as a key into the AtomicString table. If there is already
an AtomicString with the same characters, we reuse that instead of
constructing a new StringImpl.

JSString gains these two public functions:

- AtomicString toAtomicString()

    Returns an AtomicString, tries to avoid allocating a new string
    if possible.

- AtomicStringImpl* toExistingAtomicString()

    Returns a non-null AtomicStringImpl* if one already exists in the
    AtomicString table. If none is found, the rope is left unresolved.

Reviewed by Filip Pizlo.

* runtime/JSString.cpp:
(JSC::JSRopeString::resolveRopeInternal8):
(JSC::JSRopeString::resolveRopeInternal16):
(JSC::JSRopeString::resolveRopeToAtomicString):
(JSC::JSRopeString::clearFibers):
(JSC::JSRopeString::resolveRopeToExistingAtomicString):
(JSC::JSRopeString::resolveRope):
(JSC::JSRopeString::outOfMemory):
* runtime/JSString.h:
(JSC::JSString::toAtomicString):
(JSC::JSString::toExistingAtomicString):

Source/WebCore:
Add two bindings generator attributes for parameters to influence
the way that JS rope strings are resolved:

- AtomicString

    Generates code that avoids allocating a new StringImpl if there
    is already an existing AtomicString we can reuse.

- RequiresExistingAtomicString

    Generates code that fails immediately if the provided string
    is not found in the AtomicString table. This is now used for
    document.getElementById(), and works because any existing ID
    is guaranteed to be in the table.

Reviewed by Filip Pizlo.

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateParametersCheck):
(JSValueToNative):
* bindings/scripts/IDLAttributes.txt:
* dom/Document.idl:

Source/WTF:
Add AtomicString::find([LU]Char*, unsigned length) helpers for finding
an existing AtomicString without a StringImpl on hand.

Reviewed by Filip Pizlo.

* wtf/text/AtomicString.h:
* wtf/text/AtomicString.cpp:
(WTF::AtomicString::find):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringcpp">trunk/Source/JavaScriptCore/runtime/JSString.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringh">trunk/Source/JavaScriptCore/runtime/JSString.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtftextAtomicStringcpp">trunk/Source/WTF/wtf/text/AtomicString.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextAtomicStringh">trunk/Source/WTF/wtf/text/AtomicString.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptsCodeGeneratorJSpm">trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptsIDLAttributestxt">trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt</a></li>
<li><a href="#trunkSourceWebCoredomDocumentidl">trunk/Source/WebCore/dom/Document.idl</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -1,5 +1,44 @@
</span><span class="cx"> 2014-05-04  Andreas Kling  &lt;akling@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Optimize JSRopeString for resolving directly to AtomicString.
+        &lt;https://webkit.org/b/132548&gt;
+
+        If we know that the JSRopeString we are resolving is going to be used
+        as an AtomicString, we can try to avoid creating a new string.
+
+        We do this by first resolving the rope into a stack buffer, and using
+        that buffer as a key into the AtomicString table. If there is already
+        an AtomicString with the same characters, we reuse that instead of
+        constructing a new StringImpl.
+
+        JSString gains these two public functions:
+
+        - AtomicString toAtomicString()
+
+            Returns an AtomicString, tries to avoid allocating a new string
+            if possible.
+
+        - AtomicStringImpl* toExistingAtomicString()
+
+            Returns a non-null AtomicStringImpl* if one already exists in the
+            AtomicString table. If none is found, the rope is left unresolved.
+
+        Reviewed by Filip Pizlo.
+
+        * runtime/JSString.cpp:
+        (JSC::JSRopeString::resolveRopeInternal8):
+        (JSC::JSRopeString::resolveRopeInternal16):
+        (JSC::JSRopeString::resolveRopeToAtomicString):
+        (JSC::JSRopeString::clearFibers):
+        (JSC::JSRopeString::resolveRopeToExistingAtomicString):
+        (JSC::JSRopeString::resolveRope):
+        (JSC::JSRopeString::outOfMemory):
+        * runtime/JSString.h:
+        (JSC::JSString::toAtomicString):
+        (JSC::JSString::toExistingAtomicString):
+
+2014-05-04  Andreas Kling  &lt;akling@apple.com&gt;
+
</ins><span class="cx">         Unreviewed, rolling out r168254.
</span><span class="cx"> 
</span><span class="cx">         Very crashy on debug JSC tests.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSString.cpp (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSString.cpp        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/JavaScriptCore/runtime/JSString.cpp        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -53,7 +53,7 @@
</span><span class="cx"> void JSString::dumpToStream(const JSCell* cell, PrintStream&amp; out)
</span><span class="cx"> {
</span><span class="cx">     const JSString* thisObject = jsCast&lt;const JSString*&gt;(cell);
</span><del>-    out.printf(&quot;&lt;%p, %s, [%u], &quot;, thisObject, thisObject-&gt;className(), thisObject-&gt;length()); 
</del><ins>+    out.printf(&quot;&lt;%p, %s, [%u], &quot;, thisObject, thisObject-&gt;className(), thisObject-&gt;length());
</ins><span class="cx">     if (thisObject-&gt;isRope())
</span><span class="cx">         out.printf(&quot;[rope]&quot;);
</span><span class="cx">     else {
</span><span class="lines">@@ -86,6 +86,113 @@
</span><span class="cx">         visitor.append(&amp;m_fibers[i]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static const unsigned maxLengthForOnStackResolve = 2048;
+
+void JSRopeString::resolveRopeInternal8(LChar* buffer) const
+{
+    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
+        if (m_fibers[i]-&gt;isRope()) {
+            resolveRopeSlowCase8(buffer);
+            return;
+        }
+    }
+
+    LChar* position = buffer;
+    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
+        const StringImpl&amp; fiberString = *m_fibers[i]-&gt;m_value.impl();
+        unsigned length = fiberString.length();
+        StringImpl::copyChars(position, fiberString.characters8(), length);
+        position += length;
+    }
+    ASSERT((buffer + m_length) == position);
+}
+
+void JSRopeString::resolveRopeInternal16(UChar* buffer) const
+{
+    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
+        if (m_fibers[i]-&gt;isRope()) {
+            resolveRopeSlowCase(buffer);
+            return;
+        }
+    }
+
+    UChar* position = buffer;
+    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
+        const StringImpl&amp; fiberString = *m_fibers[i]-&gt;m_value.impl();
+        unsigned length = fiberString.length();
+        if (fiberString.is8Bit())
+            StringImpl::copyChars(position, fiberString.characters8(), length);
+        else
+            StringImpl::copyChars(position, fiberString.characters16(), length);
+        position += length;
+    }
+    ASSERT((buffer + m_length) == position);
+}
+
+void JSRopeString::resolveRopeToAtomicString(ExecState* exec) const
+{
+    if (m_length &gt; maxLengthForOnStackResolve) {
+        resolveRope(exec);
+        m_value = AtomicString(m_value);
+        return;
+    }
+
+    if (is8Bit()) {
+        LChar buffer[maxLengthForOnStackResolve];
+        resolveRopeInternal8(buffer);
+        m_value = AtomicString(buffer, m_length);
+    } else {
+        UChar buffer[maxLengthForOnStackResolve];
+        resolveRopeInternal16(buffer);
+        m_value = AtomicString(buffer, m_length);
+    }
+
+    clearFibers();
+
+    // If we resolved a string that didn't previously exist, notify the heap that we've grown.
+    if (m_value.impl()-&gt;hasOneRef())
+        Heap::heap(this)-&gt;reportExtraMemoryCost(m_value.impl()-&gt;cost());
+}
+
+void JSRopeString::clearFibers() const
+{
+    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i)
+        m_fibers[i].clear();
+}
+
+AtomicStringImpl* JSRopeString::resolveRopeToExistingAtomicString(ExecState* exec) const
+{
+    if (m_length &gt; maxLengthForOnStackResolve) {
+        resolveRope(exec);
+        if (AtomicStringImpl* existingAtomicString = AtomicString::find(m_value.impl())) {
+            m_value = *existingAtomicString;
+            clearFibers();
+            return existingAtomicString;
+        }
+        return nullptr;
+    }
+
+    if (is8Bit()) {
+        LChar buffer[maxLengthForOnStackResolve];
+        resolveRopeInternal8(buffer);
+        if (AtomicStringImpl* existingAtomicString = AtomicString::find(buffer, m_length)) {
+            m_value = *existingAtomicString;
+            clearFibers();
+            return existingAtomicString;
+        }
+    } else {
+        UChar buffer[maxLengthForOnStackResolve];
+        resolveRopeInternal16(buffer);
+        if (AtomicStringImpl* existingAtomicString = AtomicString::find(buffer, m_length)) {
+            m_value = *existingAtomicString;
+            clearFibers();
+            return existingAtomicString;
+        }
+    }
+
+    return nullptr;
+}
+
</ins><span class="cx"> void JSRopeString::resolveRope(ExecState* exec) const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isRope());
</span><span class="lines">@@ -99,23 +206,9 @@
</span><span class="cx">             outOfMemory(exec);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-
-        for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
-            if (m_fibers[i]-&gt;isRope())
-                return resolveRopeSlowCase8(buffer);
-        }
-
-        LChar* position = buffer;
-        for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
-            StringImpl* string = m_fibers[i]-&gt;m_value.impl();
-            unsigned length = string-&gt;length();
-            StringImpl::copyChars(position, string-&gt;characters8(), length);
-            position += length;
-            m_fibers[i].clear();
-        }
-        ASSERT((buffer + m_length) == position);
</del><ins>+        resolveRopeInternal8(buffer);
+        clearFibers();
</ins><span class="cx">         ASSERT(!isRope());
</span><del>-
</del><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -128,23 +221,8 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
-        if (m_fibers[i]-&gt;isRope())
-            return resolveRopeSlowCase(buffer);
-    }
-
-    UChar* position = buffer;
-    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i) {
-        StringImpl* string = m_fibers[i]-&gt;m_value.impl();
-        unsigned length = string-&gt;length();
-        if (string-&gt;is8Bit())
-            StringImpl::copyChars(position, string-&gt;characters8(), length);
-        else
-            StringImpl::copyChars(position, string-&gt;characters16(), length);
-        position += length;
-        m_fibers[i].clear();
-    }
-    ASSERT((buffer + m_length) == position);
</del><ins>+    resolveRopeInternal16(buffer);
+    clearFibers();
</ins><span class="cx">     ASSERT(!isRope());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -224,8 +302,7 @@
</span><span class="cx"> 
</span><span class="cx"> void JSRopeString::outOfMemory(ExecState* exec) const
</span><span class="cx"> {
</span><del>-    for (size_t i = 0; i &lt; s_maxInternalRopeLength &amp;&amp; m_fibers[i]; ++i)
-        m_fibers[i].clear();
</del><ins>+    clearFibers();
</ins><span class="cx">     ASSERT(isRope());
</span><span class="cx">     ASSERT(m_value.isNull());
</span><span class="cx">     if (exec)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSString.h (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSString.h        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/JavaScriptCore/runtime/JSString.h        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -139,6 +139,8 @@
</span><span class="cx">             return newString;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        const AtomicString&amp; toAtomicString(ExecState*) const;
+        AtomicStringImpl* toExistingAtomicString(ExecState*) const;
</ins><span class="cx">         const String&amp; value(ExecState*) const;
</span><span class="cx">         const String&amp; tryGetValue() const;
</span><span class="cx">         const StringImpl* tryGetValueImpl() const;
</span><span class="lines">@@ -329,9 +331,14 @@
</span><span class="cx">         friend JSValue jsStringFromArguments(ExecState*, JSValue);
</span><span class="cx"> 
</span><span class="cx">         JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
</span><ins>+        JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const;
+        JS_EXPORT_PRIVATE AtomicStringImpl* resolveRopeToExistingAtomicString(ExecState*) const;
</ins><span class="cx">         void resolveRopeSlowCase8(LChar*) const;
</span><span class="cx">         void resolveRopeSlowCase(UChar*) const;
</span><span class="cx">         void outOfMemory(ExecState*) const;
</span><ins>+        void resolveRopeInternal8(LChar*) const;
+        void resolveRopeInternal16(UChar*) const;
+        void clearFibers() const;
</ins><span class="cx">             
</span><span class="cx">         JS_EXPORT_PRIVATE JSString* getIndexSlowCase(ExecState*, unsigned);
</span><span class="cx"> 
</span><span class="lines">@@ -380,6 +387,28 @@
</span><span class="cx">         return JSString::create(*vm, s.impl());
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE const AtomicString&amp; JSString::toAtomicString(ExecState* exec) const
+    {
+        if (isRope())
+            static_cast&lt;const JSRopeString*&gt;(this)-&gt;resolveRopeToAtomicString(exec);
+        else if (!m_value.impl()-&gt;isAtomic())
+            m_value = AtomicString(m_value);
+        return *reinterpret_cast&lt;const AtomicString*&gt;(&amp;m_value);
+    }
+
+    ALWAYS_INLINE AtomicStringImpl* JSString::toExistingAtomicString(ExecState* exec) const
+    {
+        if (isRope())
+            return static_cast&lt;const JSRopeString*&gt;(this)-&gt;resolveRopeToExistingAtomicString(exec);
+        if (m_value.impl()-&gt;isAtomic())
+            return static_cast&lt;AtomicStringImpl*&gt;(m_value.impl());
+        if (AtomicStringImpl* existingAtomicString = AtomicString::find(m_value.impl())) {
+            m_value = *existingAtomicString;
+            return existingAtomicString;
+        }
+        return nullptr;
+    }
+
</ins><span class="cx">     inline const String&amp; JSString::value(ExecState* exec) const
</span><span class="cx">     {
</span><span class="cx">         if (isRope())
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/WTF/ChangeLog        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-05-04  Andreas Kling  &lt;akling@apple.com&gt;
+
+        Optimize JSRopeString for resolving directly to AtomicString.
+        &lt;https://webkit.org/b/132548&gt;
+
+        Add AtomicString::find([LU]Char*, unsigned length) helpers for finding
+        an existing AtomicString without a StringImpl on hand.
+
+        Reviewed by Filip Pizlo.
+
+        * wtf/text/AtomicString.h:
+        * wtf/text/AtomicString.cpp:
+        (WTF::AtomicString::find):
+
</ins><span class="cx"> 2014-05-01  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix handling of attributes prior to compiling shader
</span></span></pre></div>
<a id="trunkSourceWTFwtftextAtomicStringcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/AtomicString.cpp (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/AtomicString.cpp        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/WTF/wtf/text/AtomicString.cpp        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -525,6 +525,30 @@
</span><span class="cx">     return String(numberToFixedPrecisionString(number, 6, buffer, true));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+AtomicStringImpl* AtomicString::find(LChar* characters, unsigned length)
+{
+    AtomicStringTableLocker locker;
+    auto&amp; table = stringTable();
+
+    LCharBuffer buffer = { characters, length };
+    auto iterator = table.find&lt;LCharBufferTranslator&gt;(buffer);
+    if (iterator != table.end())
+        return static_cast&lt;AtomicStringImpl*&gt;(*iterator);
+    return nullptr;
+}
+
+AtomicStringImpl* AtomicString::find(UChar* characters, unsigned length)
+{
+    AtomicStringTableLocker locker;
+    auto&amp; table = stringTable();
+
+    UCharBuffer buffer = { characters, length };
+    auto iterator = table.find&lt;UCharBufferTranslator&gt;(buffer);
+    if (iterator != table.end())
+        return static_cast&lt;AtomicStringImpl*&gt;(*iterator);
+    return nullptr;
+}
+
</ins><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx"> bool AtomicString::isInAtomicStringTable(StringImpl* string)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWTFwtftextAtomicStringh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/AtomicString.h (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/AtomicString.h        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/WTF/wtf/text/AtomicString.h        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -87,6 +87,8 @@
</span><span class="cx">     bool isHashTableDeletedValue() const { return m_string.isHashTableDeletedValue(); }
</span><span class="cx"> 
</span><span class="cx">     WTF_EXPORT_STRING_API static AtomicStringImpl* findStringWithHash(const StringImpl&amp;);
</span><ins>+    WTF_EXPORT_STRING_API static AtomicStringImpl* find(LChar*, unsigned length);
+    WTF_EXPORT_STRING_API static AtomicStringImpl* find(UChar*, unsigned length);
</ins><span class="cx">     static AtomicStringImpl* find(StringImpl* string)
</span><span class="cx">     {
</span><span class="cx">         if (!string || string-&gt;isAtomic())
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/WebCore/ChangeLog        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2014-05-04  Andreas Kling  &lt;akling@apple.com&gt;
+
+        Optimize JSRopeString for resolving directly to AtomicString.
+        &lt;https://webkit.org/b/132548&gt;
+
+        Add two bindings generator attributes for parameters to influence
+        the way that JS rope strings are resolved:
+
+        - AtomicString
+
+            Generates code that avoids allocating a new StringImpl if there
+            is already an existing AtomicString we can reuse.
+
+        - RequiresExistingAtomicString
+
+            Generates code that fails immediately if the provided string
+            is not found in the AtomicString table. This is now used for
+            document.getElementById(), and works because any existing ID
+            is guaranteed to be in the table.
+
+        Reviewed by Filip Pizlo.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateParametersCheck):
+        (JSValueToNative):
+        * bindings/scripts/IDLAttributes.txt:
+        * dom/Document.idl:
+
</ins><span class="cx"> 2014-05-04  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [iOS WK2] Compositing layers in iframes are misplaced
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptsCodeGeneratorJSpm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -3283,7 +3283,14 @@
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            push(@$outputArray, &quot;    &quot; . GetNativeTypeFromSignature($parameter) . &quot; $name(&quot; . JSValueToNative($parameter, $optional &amp;&amp; $defaultAttribute &amp;&amp; $defaultAttribute eq &quot;NullString&quot; ? &quot;argumentOrNull(exec, $argsIndex)&quot; : &quot;exec-&gt;argument($argsIndex)&quot;) . &quot;);\n&quot;);
</del><ins>+            if ($parameter-&gt;extendedAttributes-&gt;{&quot;RequiresExistingAtomicString&quot;}) {
+                push(@$outputArray, &quot;    AtomicStringImpl* existing_$name = exec-&gt;argument($argsIndex).isEmpty() ? nullptr : exec-&gt;argument($argsIndex).toString(exec)-&gt;toExistingAtomicString(exec);\n&quot;);
+                push(@$outputArray, &quot;    if (!existing_$name)\n&quot;);
+                push(@$outputArray, &quot;        return JSValue::encode(jsNull());\n&quot;);
+                push(@$outputArray, &quot;    const AtomicString&amp; $name(existing_$name);\n&quot;);
+            } else {
+                push(@$outputArray, &quot;    &quot; . GetNativeTypeFromSignature($parameter) . &quot; $name(&quot; . JSValueToNative($parameter, $optional &amp;&amp; $defaultAttribute &amp;&amp; $defaultAttribute eq &quot;NullString&quot; ? &quot;argumentOrNull(exec, $argsIndex)&quot; : &quot;exec-&gt;argument($argsIndex)&quot;) . &quot;);\n&quot;);
+            }
</ins><span class="cx"> 
</span><span class="cx">             # If a parameter is &quot;an index&quot; and it's negative it should throw an INDEX_SIZE_ERR exception.
</span><span class="cx">             # But this needs to be done in the bindings, because the type is unsigned and the fact that it
</span><span class="lines">@@ -3761,6 +3768,9 @@
</span><span class="cx">         if (($signature-&gt;extendedAttributes-&gt;{&quot;TreatNullAs&quot;} and $signature-&gt;extendedAttributes-&gt;{&quot;TreatNullAs&quot;} eq &quot;NullString&quot;) or $signature-&gt;extendedAttributes-&gt;{&quot;Reflect&quot;}) {
</span><span class="cx">             return &quot;valueToStringWithNullCheck(exec, $value)&quot;
</span><span class="cx">         }
</span><ins>+        if ($signature-&gt;extendedAttributes-&gt;{&quot;AtomicString&quot;}) {
+            return &quot;$value.isEmpty() ? AtomicString() : $value.toString(exec)-&gt;toAtomicString(exec)&quot;;
+        }
</ins><span class="cx">         # FIXME: Add the case for 'if ($signature-&gt;extendedAttributes-&gt;{&quot;TreatUndefinedAs&quot;} and $signature-&gt;extendedAttributes-&gt;{&quot;TreatUndefinedAs&quot;} eq &quot;NullString&quot;))'.
</span><span class="cx">         return &quot;$value.isEmpty() ? String() : $value.toString(exec)-&gt;value(exec)&quot;;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptsIDLAttributestxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -19,6 +19,7 @@
</span><span class="cx"> #
</span><span class="cx"> 
</span><span class="cx"> ActiveDOMObject
</span><ins>+AtomicString
</ins><span class="cx"> CPPPureInterface
</span><span class="cx"> CachedAttribute
</span><span class="cx"> CallbackNeedsOperatorEqual
</span><span class="lines">@@ -101,6 +102,7 @@
</span><span class="cx"> Replaceable
</span><span class="cx"> ReplaceableConstructor
</span><span class="cx"> ReportExtraMemoryCost
</span><ins>+RequiresExistingAtomicString
</ins><span class="cx"> ReturnNewObject
</span><span class="cx"> SetterRaisesException
</span><span class="cx"> SkipVTableValidation
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumentidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.idl (168255 => 168256)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.idl        2014-05-05 06:10:03 UTC (rev 168255)
+++ trunk/Source/WebCore/dom/Document.idl        2014-05-05 06:24:44 UTC (rev 168256)
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx">                                                                           [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName);
</span><span class="cx">     [ObjCLegacyUnnamedParameters] NodeList getElementsByTagNameNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
</span><span class="cx">                                                    [Default=Undefined] optional DOMString localName);
</span><del>-    Element getElementById([Default=Undefined,ObjCExplicitAtomicString] optional DOMString elementId);
</del><ins>+    Element getElementById([Default=Undefined,ObjCExplicitAtomicString,RequiresExistingAtomicString] optional DOMString elementId);
</ins><span class="cx"> 
</span><span class="cx">     // DOM Level 3 Core
</span><span class="cx"> 
</span><span class="lines">@@ -156,7 +156,7 @@
</span><span class="cx">     readonly attribute HTMLCollection anchors;
</span><span class="cx">     readonly attribute DOMString lastModified;
</span><span class="cx"> 
</span><del>-    NodeList getElementsByName([Default=Undefined] optional DOMString elementName);
</del><ins>+    NodeList getElementsByName([Default=Undefined,AtomicString] optional DOMString elementName);
</ins><span class="cx"> 
</span><span class="cx"> #if defined(LANGUAGE_JAVASCRIPT) &amp;&amp; LANGUAGE_JAVASCRIPT
</span><span class="cx">              [Custom] attribute Location location;
</span></span></pre>
</div>
</div>

</body>
</html>