<!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>[185899] 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/185899">185899</a></dd>
<dt>Author</dt> <dd>darin@apple.com</dd>
<dt>Date</dt> <dd>2015-06-23 19:33:18 -0700 (Tue, 23 Jun 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make Array.join work directly on substrings without reifying them
https://bugs.webkit.org/show_bug.cgi?id=146191

Reviewed by Andreas Kling.

Source/JavaScriptCore:

Besides the Array.join change, this has other optimizations based on
profiling the Peacekeeper array benchmark.

I measured a 14% speed improvement in the Peacekeeper array benchmark.

Still a lot of low hanging fruit in that test because so many of functions
on the array prototype are not optimizing for simple cases. For example,
the reverse function does individual get and put calls even when the array
is entirely made up of integers in contiguous storage.

* runtime/ArrayPrototype.cpp:
(JSC::getProperty): Use tryGetIndexQuickly first before getPropertySlot.
(JSC::argumentClampedIndexFromStartOrEnd): Marked inline.
(JSC::shift): Use the getProperty helper in this file instead of using
getPropertySlot. Use putByIndexInline instead of calling putByIndex directly.
In both cases this can yield a faster code path.
(JSC::unshift): Ditto.
(JSC::arrayProtoFuncToString): Updated to use the new JSStringJoiner
interface. Changed local variable name to thisArray since it's not a
JSObject*. Changed loop index to i instead of k.
(JSC::arrayProtoFuncToLocaleString): Updated to use the new JSStringJoiner
interface. Renamed thisObj to thisObject. Added a missing exception check
after the toLocaleString function is called, but before toString is called
the result of that function.
(JSC::arrayProtoFuncJoin): Updated to use the new JSStringJointer interface.
Added a missing exception check after calling toString on the separator
but before calling get to get the first element in the array-like object
being joined. Changed loop index to i instead of k. Added missing exception
check after calling toString on each string from the array before calling
get for the next element.
(JSC::arrayProtoFuncConcat): Use JSArray::length instead of using the
getLength function.
(JSC::arrayProtoFuncReverse): Ditto. Also use putByIndexInline.
(JSC::arrayProtoFuncShift): Ditto.
(JSC::arrayProtoFuncSplice): Use getIndex instead of get, which includes some
additional optimizations.
(JSC::getOrHole): Deleted. Unused function.
(JSC::arrayProtoFuncUnShift): Use putByIndexInline.

* runtime/ExceptionHelpers.cpp:
(JSC::errorDescriptionForValue): Removed the duplicate copy of the the logic
from JSValue::toString.

* runtime/JSCJSValue.cpp:
(JSC::JSValue::toStringSlowCase): Improved the performance when converting a
small integer to a single character string.
(JSC::JSValue::toWTFStringSlowCase): Moved the contents of the
inlineJSValueNotStringtoString function here.
* runtime/JSCJSValue.h: Removed no longer used toWTFStringInline and fixed
a comment with a typo.

* runtime/JSObject.h:
(JSC::JSObject::putByIndexInline): Marked ALWAYS_INLINE because this was not
getting inlined at some call sites.
(JSC::JSObject::indexingData): Deleted. Unused function.
(JSC::JSObject::currentIndexingData): Deleted. Unused function.
(JSC::JSObject::getHolyIndexQuickly): Deleted. Unused function.
(JSC::JSObject::relevantLength): Deleted. Unused function.
(JSC::JSObject::currentRelevantLength): Deleted. Unused function.

* runtime/JSString.h: Added the StringViewWithUnderlyingString struct and
the viewWithUnderlyingString function. Removed the inlineJSValueNotStringtoString
and toWTFStringInline functions.

* runtime/JSStringJoiner.cpp:
(JSC::appendStringToData): Changed this to be a template instead of writing
it out, since StringView::getCharactersWithUpconvert does almsot exactly what
this function was trying to do.
(JSC::joinStrings): Rewrote this to use StringView.
(JSC::JSStringJoiner::joinedLength): Added. Factored out from the join function.
(JSC::JSStringJoiner::join): Rewrote to make it a bit simpler. Added an assertion
that we entirely filled capacity, since we are now reserving capacity and using
uncheckedAppend. Use String instead of RefPtr&lt;StringImpl&gt; because there was no
particular value to using the impl directly.

* runtime/JSStringJoiner.h: Changed the interface to the class to use StringView.
Also changed this class so it now has the responsibility to convert each JSValue
into a string. This let us share more code between toString and join, and also
lets us use the new viewWithUnderlyingString function, which could be confusing at
all the call sites, but is easier to understand here.

Source/WTF:

* wtf/Vector.h: Added an overload of uncheckedAppend like the one we added
a while back, a non-template function that forwards through to the function
template. This lets us call uncheckedAppend on an argument list and have it
properly convert it to the Vector's element type.

* wtf/text/StringView.h:
(WTF::StringView::getCharactersWithUpconvert): Changed to not use memcpy;
saw some indication the hand-written loop was faster when profiling. Also
use m_length directly when we know we are dealing with an 8-bit string,
since the masking that the index function does is not needed in that case.
(WTF::StringView::UpconvertedCharacters::UpconvertedCharacters): Ditto.
(WTF::StringView::toString): Ditto.
(WTF::StringView::toFloat): Ditto.
(WTF::StringView::toInt): Ditto.
(WTF::StringView::toStringWithoutCopying): Ditto.
(WTF::StringView::find): Ditto.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayPrototypecpp">trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeExceptionHelperscpp">trunk/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValuecpp">trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValueh">trunk/Source/JavaScriptCore/runtime/JSCJSValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringh">trunk/Source/JavaScriptCore/runtime/JSString.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringJoinercpp">trunk/Source/JavaScriptCore/runtime/JSStringJoiner.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringJoinerh">trunk/Source/JavaScriptCore/runtime/JSStringJoiner.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfVectorh">trunk/Source/WTF/wtf/Vector.h</a></li>
<li><a href="#trunkSourceWTFwtftextStringViewh">trunk/Source/WTF/wtf/text/StringView.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -1,3 +1,91 @@
</span><ins>+2015-06-22  Darin Adler  &lt;darin@apple.com&gt;
+
+        Make Array.join work directly on substrings without reifying them
+        https://bugs.webkit.org/show_bug.cgi?id=146191
+
+        Reviewed by Andreas Kling.
+
+        Besides the Array.join change, this has other optimizations based on
+        profiling the Peacekeeper array benchmark.
+
+        I measured a 14% speed improvement in the Peacekeeper array benchmark.
+
+        Still a lot of low hanging fruit in that test because so many of functions
+        on the array prototype are not optimizing for simple cases. For example,
+        the reverse function does individual get and put calls even when the array
+        is entirely made up of integers in contiguous storage.
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::getProperty): Use tryGetIndexQuickly first before getPropertySlot.
+        (JSC::argumentClampedIndexFromStartOrEnd): Marked inline.
+        (JSC::shift): Use the getProperty helper in this file instead of using
+        getPropertySlot. Use putByIndexInline instead of calling putByIndex directly.
+        In both cases this can yield a faster code path.
+        (JSC::unshift): Ditto.
+        (JSC::arrayProtoFuncToString): Updated to use the new JSStringJoiner
+        interface. Changed local variable name to thisArray since it's not a
+        JSObject*. Changed loop index to i instead of k.
+        (JSC::arrayProtoFuncToLocaleString): Updated to use the new JSStringJoiner
+        interface. Renamed thisObj to thisObject. Added a missing exception check
+        after the toLocaleString function is called, but before toString is called
+        the result of that function.
+        (JSC::arrayProtoFuncJoin): Updated to use the new JSStringJointer interface.
+        Added a missing exception check after calling toString on the separator
+        but before calling get to get the first element in the array-like object
+        being joined. Changed loop index to i instead of k. Added missing exception
+        check after calling toString on each string from the array before calling
+        get for the next element.
+        (JSC::arrayProtoFuncConcat): Use JSArray::length instead of using the
+        getLength function.
+        (JSC::arrayProtoFuncReverse): Ditto. Also use putByIndexInline.
+        (JSC::arrayProtoFuncShift): Ditto.
+        (JSC::arrayProtoFuncSplice): Use getIndex instead of get, which includes some
+        additional optimizations.
+        (JSC::getOrHole): Deleted. Unused function.
+        (JSC::arrayProtoFuncUnShift): Use putByIndexInline.
+
+        * runtime/ExceptionHelpers.cpp:
+        (JSC::errorDescriptionForValue): Removed the duplicate copy of the the logic
+        from JSValue::toString.
+
+        * runtime/JSCJSValue.cpp:
+        (JSC::JSValue::toStringSlowCase): Improved the performance when converting a
+        small integer to a single character string.
+        (JSC::JSValue::toWTFStringSlowCase): Moved the contents of the
+        inlineJSValueNotStringtoString function here.
+        * runtime/JSCJSValue.h: Removed no longer used toWTFStringInline and fixed
+        a comment with a typo.
+
+        * runtime/JSObject.h:
+        (JSC::JSObject::putByIndexInline): Marked ALWAYS_INLINE because this was not
+        getting inlined at some call sites.
+        (JSC::JSObject::indexingData): Deleted. Unused function.
+        (JSC::JSObject::currentIndexingData): Deleted. Unused function.
+        (JSC::JSObject::getHolyIndexQuickly): Deleted. Unused function.
+        (JSC::JSObject::relevantLength): Deleted. Unused function.
+        (JSC::JSObject::currentRelevantLength): Deleted. Unused function.
+
+        * runtime/JSString.h: Added the StringViewWithUnderlyingString struct and
+        the viewWithUnderlyingString function. Removed the inlineJSValueNotStringtoString
+        and toWTFStringInline functions.
+
+        * runtime/JSStringJoiner.cpp:
+        (JSC::appendStringToData): Changed this to be a template instead of writing
+        it out, since StringView::getCharactersWithUpconvert does almsot exactly what
+        this function was trying to do.
+        (JSC::joinStrings): Rewrote this to use StringView.
+        (JSC::JSStringJoiner::joinedLength): Added. Factored out from the join function.
+        (JSC::JSStringJoiner::join): Rewrote to make it a bit simpler. Added an assertion
+        that we entirely filled capacity, since we are now reserving capacity and using
+        uncheckedAppend. Use String instead of RefPtr&lt;StringImpl&gt; because there was no
+        particular value to using the impl directly.
+
+        * runtime/JSStringJoiner.h: Changed the interface to the class to use StringView.
+        Also changed this class so it now has the responsibility to convert each JSValue
+        into a string. This let us share more code between toString and join, and also
+        lets us use the new viewWithUnderlyingString function, which could be confusing at
+        all the call sites, but is easier to understand here.
+
</ins><span class="cx"> 2015-06-23  Matthew Mirman  &lt;mmirman@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Completes native binding descriptors with native getters and potentially setters.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -138,11 +138,12 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ Array Functions ----------------------------
</span><span class="cx"> 
</span><del>-// Helper function
-static ALWAYS_INLINE JSValue getProperty(ExecState* exec, JSObject* obj, unsigned index)
</del><ins>+static ALWAYS_INLINE JSValue getProperty(ExecState* exec, JSObject* object, unsigned index)
</ins><span class="cx"> {
</span><del>-    PropertySlot slot(obj);
-    if (!obj-&gt;getPropertySlot(exec, index, slot))
</del><ins>+    if (JSValue result = object-&gt;tryGetIndexQuickly(index))
+        return result;
+    PropertySlot slot(object);
+    if (!object-&gt;getPropertySlot(exec, index, slot))
</ins><span class="cx">         return JSValue();
</span><span class="cx">     return slot.getValue(exec, index);
</span><span class="cx"> }
</span><span class="lines">@@ -160,7 +161,7 @@
</span><span class="cx">     obj-&gt;methodTable()-&gt;put(obj, exec, exec-&gt;propertyNames().length, value, slot);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
</del><ins>+static inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
</ins><span class="cx"> {
</span><span class="cx">     JSValue value = exec-&gt;argument(argument);
</span><span class="cx">     if (value.isUndefined())
</span><span class="lines">@@ -174,7 +175,6 @@
</span><span class="cx">     return indexDouble &gt; length ? length : static_cast&lt;unsigned&gt;(indexDouble);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> // The shift/unshift function implement the shift/unshift behaviour required
</span><span class="cx"> // by the corresponding array prototype methods, and by splice. In both cases,
</span><span class="cx"> // the methods are operating an an array or array like object.
</span><span class="lines">@@ -189,6 +189,7 @@
</span><span class="cx"> // currentCount) will be shifted to the left or right as appropriate; in the
</span><span class="cx"> // case of shift this must be removing values, in the case of unshift this
</span><span class="cx"> // must be introducing new values.
</span><ins>+
</ins><span class="cx"> template&lt;JSArray::ShiftCountMode shiftCountMode&gt;
</span><span class="cx"> void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
</span><span class="cx"> {
</span><span class="lines">@@ -207,12 +208,10 @@
</span><span class="cx">     for (unsigned k = header; k &lt; length - currentCount; ++k) {
</span><span class="cx">         unsigned from = k + currentCount;
</span><span class="cx">         unsigned to = k + resultCount;
</span><del>-        PropertySlot slot(thisObj);
-        if (thisObj-&gt;getPropertySlot(exec, from, slot)) {
-            JSValue value = slot.getValue(exec, from);
</del><ins>+        if (JSValue value = getProperty(exec, thisObj, from)) {
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return;
</span><del>-            thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, to, value, true);
</del><ins>+            thisObj-&gt;putByIndexInline(exec, to, value, true);
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return;
</span><span class="cx">         } else if (!thisObj-&gt;methodTable(exec-&gt;vm())-&gt;deletePropertyByIndex(thisObj, exec, to)) {
</span><span class="lines">@@ -227,6 +226,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> template&lt;JSArray::ShiftCountMode shiftCountMode&gt;
</span><span class="cx"> void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
</span><span class="cx"> {
</span><span class="lines">@@ -247,16 +247,14 @@
</span><span class="cx">         if (array-&gt;length() == length &amp;&amp; array-&gt;unshiftCount&lt;shiftCountMode&gt;(exec, header, count))
</span><span class="cx">             return;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     for (unsigned k = length - currentCount; k &gt; header; --k) {
</span><span class="cx">         unsigned from = k + currentCount - 1;
</span><span class="cx">         unsigned to = k + resultCount - 1;
</span><del>-        PropertySlot slot(thisObj);
-        if (thisObj-&gt;getPropertySlot(exec, from, slot)) {
-            JSValue value = slot.getValue(exec, from);
</del><ins>+        if (JSValue value = getProperty(exec, thisObj, from)) {
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return;
</span><del>-            thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, to, value, true);
</del><ins>+            thisObj-&gt;putByIndexInline(exec, to, value, true);
</ins><span class="cx">         } else if (!thisObj-&gt;methodTable(exec-&gt;vm())-&gt;deletePropertyByIndex(thisObj, exec, to)) {
</span><span class="cx">             throwTypeError(exec, ASCIILiteral(&quot;Unable to delete property.&quot;));
</span><span class="cx">             return;
</span><span class="lines">@@ -291,80 +289,75 @@
</span><span class="cx">         return JSValue::encode(call(exec, function, callType, callData, thisObject, exec-&gt;emptyList()));
</span><span class="cx"> 
</span><span class="cx">     ASSERT(isJSArray(thisValue));
</span><del>-    JSArray* thisObj = asArray(thisValue);
</del><ins>+    JSArray* thisArray = asArray(thisValue);
</ins><span class="cx">     
</span><del>-    unsigned length = getLength(exec, thisObj);
-    if (exec-&gt;hadException())
-        return JSValue::encode(jsUndefined());
</del><ins>+    unsigned length = thisArray-&gt;length();
</ins><span class="cx"> 
</span><del>-    StringRecursionChecker checker(exec, thisObj);
</del><ins>+    StringRecursionChecker checker(exec, thisArray);
</ins><span class="cx">     if (JSValue earlyReturnValue = checker.earlyReturnValue())
</span><span class="cx">         return JSValue::encode(earlyReturnValue);
</span><span class="cx"> 
</span><del>-    String separator(&quot;,&quot;, String::ConstructFromLiteral);
-    JSStringJoiner stringJoiner(separator, length);
-    for (unsigned k = 0; k &lt; length; k++) {
-        JSValue element;
-        if (thisObj-&gt;canGetIndexQuickly(k))
-            element = thisObj-&gt;getIndexQuickly(k);
-        else {
-            element = thisObj-&gt;get(exec, k);
</del><ins>+    JSStringJoiner joiner(*exec, ',', length);
+    if (exec-&gt;hadException())
+        return JSValue::encode(jsUndefined());
+
+    for (unsigned i = 0; i &lt; length; ++i) {
+        JSValue element = thisArray-&gt;tryGetIndexQuickly(i);
+        if (!element) {
+            element = thisArray-&gt;get(exec, i);
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return JSValue::encode(jsUndefined());
</span><span class="cx">         }
</span><del>-
-        if (element.isUndefinedOrNull())
-            stringJoiner.append(String());
-        else
-            stringJoiner.append(element.toWTFString(exec));
-
</del><ins>+        joiner.append(*exec, element);
</ins><span class="cx">         if (exec-&gt;hadException())
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><span class="cx">     }
</span><del>-    return JSValue::encode(stringJoiner.join(exec));
</del><ins>+
+    return JSValue::encode(joiner.join(*exec));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     JSValue thisValue = exec-&gt;thisValue().toThis(exec, StrictMode);
</span><span class="cx"> 
</span><del>-    JSObject* thisObj = thisValue.toObject(exec);
</del><ins>+    JSObject* thisObject = thisValue.toObject(exec);
</ins><span class="cx">     if (exec-&gt;hadException())
</span><span class="cx">         return JSValue::encode(jsUndefined());
</span><span class="cx"> 
</span><del>-    unsigned length = getLength(exec, thisObj);
</del><ins>+    unsigned length = getLength(exec, thisObject);
</ins><span class="cx">     if (exec-&gt;hadException())
</span><span class="cx">         return JSValue::encode(jsUndefined());
</span><span class="cx"> 
</span><del>-    StringRecursionChecker checker(exec, thisObj);
</del><ins>+    StringRecursionChecker checker(exec, thisObject);
</ins><span class="cx">     if (JSValue earlyReturnValue = checker.earlyReturnValue())
</span><span class="cx">         return JSValue::encode(earlyReturnValue);
</span><span class="cx"> 
</span><del>-    String separator(&quot;,&quot;, String::ConstructFromLiteral);
-    JSStringJoiner stringJoiner(separator, length);
-    for (unsigned k = 0; k &lt; length; k++) {
-        JSValue element = thisObj-&gt;get(exec, k);
</del><ins>+    JSStringJoiner stringJoiner(*exec, ',', length);
+    if (exec-&gt;hadException())
+        return JSValue::encode(jsUndefined());
+
+    for (unsigned i = 0; i &lt; length; ++i) {
+        JSValue element = thisObject-&gt;getIndex(exec, i);
</ins><span class="cx">         if (exec-&gt;hadException())
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><del>-        if (!element.isUndefinedOrNull()) {
-            JSObject* o = element.toObject(exec);
-            JSValue conversionFunction = o-&gt;get(exec, exec-&gt;propertyNames().toLocaleString);
</del><ins>+        if (element.isUndefinedOrNull())
+            continue;
+        JSValue conversionFunction = element.get(exec, exec-&gt;propertyNames().toLocaleString);
+        if (exec-&gt;hadException())
+            return JSValue::encode(jsUndefined());
+        CallData callData;
+        CallType callType = getCallData(conversionFunction, callData);
+        if (callType != CallTypeNone) {
+            element = call(exec, conversionFunction, callType, callData, element, exec-&gt;emptyList());
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return JSValue::encode(jsUndefined());
</span><del>-            String str;
-            CallData callData;
-            CallType callType = getCallData(conversionFunction, callData);
-            if (callType != CallTypeNone)
-                str = call(exec, conversionFunction, callType, callData, element, exec-&gt;emptyList()).toWTFString(exec);
-            else
-                str = element.toWTFString(exec);
-            if (exec-&gt;hadException())
-                return JSValue::encode(jsUndefined());
-            stringJoiner.append(str);
</del><span class="cx">         }
</span><ins>+        stringJoiner.append(*exec, element);
+        if (exec-&gt;hadException())
+            return JSValue::encode(jsUndefined());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return JSValue::encode(stringJoiner.join(exec));
</del><ins>+    return JSValue::encode(stringJoiner.join(*exec));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
</span><span class="lines">@@ -378,61 +371,56 @@
</span><span class="cx">     if (JSValue earlyReturnValue = checker.earlyReturnValue())
</span><span class="cx">         return JSValue::encode(earlyReturnValue);
</span><span class="cx"> 
</span><del>-    String separator;
-    if (!exec-&gt;argument(0).isUndefined())
-        separator = exec-&gt;argument(0).toWTFString(exec);
-    if (separator.isNull())
-        separator = String(&quot;,&quot;, String::ConstructFromLiteral);
</del><ins>+    JSString* separator = nullptr;
+    if (!exec-&gt;argument(0).isUndefined()) {
+        separator = exec-&gt;argument(0).toString(exec);
+        if (exec-&gt;hadException())
+            return JSValue::encode(jsUndefined());
+    }
</ins><span class="cx"> 
</span><del>-    JSStringJoiner stringJoiner(separator, length);
</del><ins>+    const LChar comma = ',';
+    JSStringJoiner stringJoiner(*exec, separator ? separator-&gt;view(exec) : StringView{ &amp;comma, 1 }, length);
+    if (exec-&gt;hadException())
+        return JSValue::encode(jsUndefined());
</ins><span class="cx"> 
</span><del>-    unsigned k = 0;
</del><ins>+    unsigned i = 0;
+
</ins><span class="cx">     if (isJSArray(thisObj)) {
</span><span class="cx">         JSArray* array = asArray(thisObj);
</span><del>-
-        for (; k &lt; length; k++) {
-            if (!array-&gt;canGetIndexQuickly(k))
-                break;
-
-            JSValue element = array-&gt;getIndexQuickly(k);
-            if (!element.isUndefinedOrNull())
-                stringJoiner.append(element.toWTFStringInline(exec));
-            else
-                stringJoiner.append(String());
</del><ins>+        for (; i &lt; length &amp;&amp; array-&gt;canGetIndexQuickly(i); ++i) {
+            stringJoiner.append(*exec, array-&gt;getIndexQuickly(i));
+            if (exec-&gt;hadException())
+                return JSValue::encode(jsUndefined());
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    for (; k &lt; length; k++) {
-        JSValue element = thisObj-&gt;get(exec, k);
</del><ins>+    for (; i &lt; length; ++i) {
+        JSValue element = thisObj-&gt;get(exec, i);
</ins><span class="cx">         if (exec-&gt;hadException())
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><del>-        if (!element.isUndefinedOrNull())
-            stringJoiner.append(element.toWTFStringInline(exec));
-        else
-            stringJoiner.append(String());
</del><ins>+        stringJoiner.append(*exec, element);
+        if (exec-&gt;hadException())
+            return JSValue::encode(jsUndefined());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return JSValue::encode(stringJoiner.join(exec));
</del><ins>+    return JSValue::encode(stringJoiner.join(*exec));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     JSValue thisValue = exec-&gt;thisValue().toThis(exec, StrictMode);
</span><del>-    size_t argCount = exec-&gt;argumentCount();
</del><ins>+    unsigned argCount = exec-&gt;argumentCount();
</ins><span class="cx">     JSValue curArg = thisValue.toObject(exec);
</span><span class="cx">     Checked&lt;unsigned, RecordOverflow&gt; finalArraySize = 0;
</span><span class="cx"> 
</span><del>-    for (size_t i = 0;;) {
-        if (JSArray* currentArray = jsDynamicCast&lt;JSArray*&gt;(curArg)) {
-            finalArraySize += getLength(exec, currentArray);
-            if (exec-&gt;hadException())
-                return JSValue::encode(jsUndefined());
-        } else
-            finalArraySize++;
</del><ins>+    for (unsigned i = 0; ; ++i) {
+        if (JSArray* currentArray = jsDynamicCast&lt;JSArray*&gt;(curArg))
+            finalArraySize += currentArray-&gt;length();
+        else
+            ++finalArraySize;
</ins><span class="cx">         if (i == argCount)
</span><span class="cx">             break;
</span><span class="cx">         curArg = exec-&gt;uncheckedArgument(i);
</span><del>-        ++i;
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (finalArraySize.hasOverflowed())
</span><span class="lines">@@ -444,9 +432,9 @@
</span><span class="cx"> 
</span><span class="cx">     curArg = thisValue.toObject(exec);
</span><span class="cx">     unsigned n = 0;
</span><del>-    for (size_t i = 0;;) {
</del><ins>+    for (unsigned i = 0; ; ++i) {
</ins><span class="cx">         if (JSArray* currentArray = jsDynamicCast&lt;JSArray*&gt;(curArg)) {
</span><del>-            unsigned length = getLength(exec, currentArray);
</del><ins>+            unsigned length = currentArray-&gt;length();
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return JSValue::encode(jsUndefined());
</span><span class="cx">             for (unsigned k = 0; k &lt; length; ++k) {
</span><span class="lines">@@ -464,7 +452,6 @@
</span><span class="cx">         if (i == argCount)
</span><span class="cx">             break;
</span><span class="cx">         curArg = exec-&gt;uncheckedArgument(i);
</span><del>-        ++i;
</del><span class="cx">     }
</span><span class="cx">     arr-&gt;setLength(exec, n);
</span><span class="cx">     return JSValue::encode(arr);
</span><span class="lines">@@ -550,7 +537,7 @@
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><span class="cx"> 
</span><span class="cx">         if (obj2) {
</span><del>-            thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, k, obj2, true);
</del><ins>+            thisObj-&gt;putByIndexInline(exec, k, obj2, true);
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return JSValue::encode(jsUndefined());
</span><span class="cx">         } else if (!thisObj-&gt;methodTable(exec-&gt;vm())-&gt;deletePropertyByIndex(thisObj, exec, k)) {
</span><span class="lines">@@ -559,7 +546,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (obj) {
</span><del>-            thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, lk1, obj, true);
</del><ins>+            thisObj-&gt;putByIndexInline(exec, lk1, obj, true);
</ins><span class="cx">             if (exec-&gt;hadException())
</span><span class="cx">                 return JSValue::encode(jsUndefined());
</span><span class="cx">         } else if (!thisObj-&gt;methodTable(exec-&gt;vm())-&gt;deletePropertyByIndex(thisObj, exec, lk1)) {
</span><span class="lines">@@ -582,7 +569,7 @@
</span><span class="cx">         putLength(exec, thisObj, jsNumber(length));
</span><span class="cx">         result = jsUndefined();
</span><span class="cx">     } else {
</span><del>-        result = thisObj-&gt;get(exec, 0);
</del><ins>+        result = thisObj-&gt;getIndex(exec, 0);
</ins><span class="cx">         shift&lt;JSArray::ShiftCountForShift&gt;(exec, thisObj, 0, 1, 0, length);
</span><span class="cx">         if (exec-&gt;hadException())
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><span class="lines">@@ -621,15 +608,6 @@
</span><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSValue getOrHole(JSObject* obj, ExecState* exec, unsigned propertyName)
-{
-    PropertySlot slot(obj);
-    if (obj-&gt;getPropertySlot(exec, propertyName, slot))
-        return slot.getValue(exec, propertyName);
-
-    return JSValue();
-}
-
</del><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     // 15.4.4.12
</span><span class="lines">@@ -686,7 +664,7 @@
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><span class="cx">     }
</span><span class="cx">     for (unsigned k = 0; k &lt; additionalArgs; ++k) {
</span><del>-        thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, k + begin, exec-&gt;uncheckedArgument(k + 2), true);
</del><ins>+        thisObj-&gt;putByIndexInline(exec, k + begin, exec-&gt;uncheckedArgument(k + 2), true);
</ins><span class="cx">         if (exec-&gt;hadException())
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><span class="cx">     }
</span><span class="lines">@@ -711,7 +689,7 @@
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><span class="cx">     }
</span><span class="cx">     for (unsigned k = 0; k &lt; nrArgs; ++k) {
</span><del>-        thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, k, exec-&gt;uncheckedArgument(k), true);
</del><ins>+        thisObj-&gt;putByIndexInline(exec, k, exec-&gt;uncheckedArgument(k), true);
</ins><span class="cx">         if (exec-&gt;hadException())
</span><span class="cx">             return JSValue::encode(jsUndefined());
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeExceptionHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -82,32 +82,16 @@
</span><span class="cx">     
</span><span class="cx"> JSString* errorDescriptionForValue(ExecState* exec, JSValue v)
</span><span class="cx"> {
</span><del>-    VM&amp; vm = exec-&gt;vm();
-    if (v.isNull())
-        return vm.smallStrings.nullString();
-    if (v.isUndefined())
-        return vm.smallStrings.undefinedString();
-    if (v.isInt32())
-        return jsString(&amp;vm, vm.numericStrings.add(v.asInt32()));
-    if (v.isDouble())
-        return jsString(&amp;vm, vm.numericStrings.add(v.asDouble()));
-    if (v.isTrue())
-        return vm.smallStrings.trueString();
-    if (v.isFalse())
-        return vm.smallStrings.falseString();
</del><span class="cx">     if (v.isString())
</span><del>-        return jsNontrivialString(&amp;vm, makeString('&quot;',  asString(v)-&gt;value(exec), '&quot;'));
</del><ins>+        return jsNontrivialString(exec, makeString('&quot;',  asString(v)-&gt;value(exec), '&quot;'));
</ins><span class="cx">     if (v.isObject()) {
</span><span class="cx">         CallData callData;
</span><span class="cx">         JSObject* object = asObject(v);
</span><span class="cx">         if (object-&gt;methodTable()-&gt;getCallData(object, callData) != CallTypeNone)
</span><del>-            return vm.smallStrings.functionString();
</del><ins>+            return exec-&gt;vm().smallStrings.functionString();
</ins><span class="cx">         return jsString(exec, JSObject::calculatedClassName(object));
</span><span class="cx">     }
</span><del>-    
-    // The JSValue should never be empty, so this point in the code should never be reached.
-    ASSERT_NOT_REACHED();
-    return vm.smallStrings.emptyString();
</del><ins>+    return v.toString(exec);
</ins><span class="cx"> }
</span><span class="cx">     
</span><span class="cx"> static String defaultApproximateSourceError(const String&amp; originalMessage, const String&amp; sourceText)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -353,8 +353,12 @@
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     ASSERT(!isString());
</span><del>-    if (isInt32())
-        return jsString(&amp;vm, vm.numericStrings.add(asInt32()));
</del><ins>+    if (isInt32()) {
+        auto integer = asInt32();
+        if (static_cast&lt;unsigned&gt;(integer) &lt;= 9)
+            return vm.smallStrings.singleCharacterString(integer + '0');
+        return jsNontrivialString(&amp;vm, vm.numericStrings.add(integer));
+    }
</ins><span class="cx">     if (isDouble())
</span><span class="cx">         return jsString(&amp;vm, vm.numericStrings.add(asDouble()));
</span><span class="cx">     if (isTrue())
</span><span class="lines">@@ -380,7 +384,20 @@
</span><span class="cx"> 
</span><span class="cx"> String JSValue::toWTFStringSlowCase(ExecState* exec) const
</span><span class="cx"> {
</span><del>-    return inlineJSValueNotStringtoString(*this, exec);
</del><ins>+    VM&amp; vm = exec-&gt;vm();
+    if (isInt32())
+        return vm.numericStrings.add(asInt32());
+    if (isDouble())
+        return vm.numericStrings.add(asDouble());
+    if (isTrue())
+        return vm.propertyNames-&gt;trueKeyword.string();
+    if (isFalse())
+        return vm.propertyNames-&gt;falseKeyword.string();
+    if (isNull())
+        return vm.propertyNames-&gt;nullKeyword.string();
+    if (isUndefined())
+        return vm.propertyNames-&gt;undefinedKeyword.string();
+    return toString(exec)-&gt;value(exec);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValue.h (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -252,7 +252,6 @@
</span><span class="cx">     JSString* toString(ExecState*) const;
</span><span class="cx">     Identifier toPropertyKey(ExecState*) const;
</span><span class="cx">     WTF::String toWTFString(ExecState*) const;
</span><del>-    WTF::String toWTFStringInline(ExecState*) const;
</del><span class="cx">     JSObject* toObject(ExecState*) const;
</span><span class="cx">     JSObject* toObject(ExecState*, JSGlobalObject*) const;
</span><span class="cx"> 
</span><span class="lines">@@ -262,8 +261,8 @@
</span><span class="cx">     int32_t toInt32(ExecState*) const;
</span><span class="cx">     uint32_t toUInt32(ExecState*) const;
</span><span class="cx"> 
</span><del>-    // Floating point conversions (this is a convenience method for webcore;
-    // signle precision float is not a representation used in JS or JSC).
</del><ins>+    // Floating point conversions (this is a convenience function for WebCore;
+    // single precision float is not a representation used in JS or JSC).
</ins><span class="cx">     float toFloat(ExecState* exec) const { return static_cast&lt;float&gt;(toNumber(exec)); }
</span><span class="cx"> 
</span><span class="cx">     // Object operations, with the toObject operation included.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -145,7 +145,7 @@
</span><span class="cx">     JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&amp;);
</span><span class="cx">     JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
</span><span class="cx">         
</span><del>-    void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
</del><ins>+    ALWAYS_INLINE void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
</ins><span class="cx">     {
</span><span class="cx">         if (canSetIndexQuickly(propertyName)) {
</span><span class="cx">             setIndexQuickly(exec-&gt;vm(), propertyName, value);
</span><span class="lines">@@ -837,103 +837,6 @@
</span><span class="cx">     // This is relevant to undecided, int32, double, and contiguous.
</span><span class="cx">     unsigned countElements();
</span><span class="cx">         
</span><del>-    // This strange method returns a pointer to the start of the indexed data
-    // as if it contained JSValues. But it won't always contain JSValues.
-    // Make sure you cast this to the appropriate type before using.
-    template&lt;IndexingType indexingType&gt;
-    ContiguousJSValues indexingData()
-    {
-        switch (indexingType) {
-        case ALL_INT32_INDEXING_TYPES:
-        case ALL_DOUBLE_INDEXING_TYPES:
-        case ALL_CONTIGUOUS_INDEXING_TYPES:
-            return m_butterfly-&gt;contiguous();
-                
-        case ALL_ARRAY_STORAGE_INDEXING_TYPES:
-            return m_butterfly-&gt;arrayStorage()-&gt;vector();
-
-        default:
-            CRASH();
-            return ContiguousJSValues();
-        }
-    }
-
-    ContiguousJSValues currentIndexingData()
-    {
-        switch (indexingType()) {
-        case ALL_INT32_INDEXING_TYPES:
-        case ALL_CONTIGUOUS_INDEXING_TYPES:
-            return m_butterfly-&gt;contiguous();
-
-        case ALL_ARRAY_STORAGE_INDEXING_TYPES:
-            return m_butterfly-&gt;arrayStorage()-&gt;vector();
-
-        default:
-            CRASH();
-            return ContiguousJSValues();
-        }
-    }
-        
-    JSValue getHolyIndexQuickly(unsigned i)
-    {
-        ASSERT(i &lt; m_butterfly-&gt;vectorLength());
-        switch (indexingType()) {
-        case ALL_INT32_INDEXING_TYPES:
-        case ALL_CONTIGUOUS_INDEXING_TYPES:
-            return m_butterfly-&gt;contiguous()[i].get();
-        case ALL_DOUBLE_INDEXING_TYPES: {
-            double value = m_butterfly-&gt;contiguousDouble()[i];
-            if (value == value)
-                return JSValue(JSValue::EncodeAsDouble, value);
-            return JSValue();
-        }
-        case ALL_ARRAY_STORAGE_INDEXING_TYPES:
-            return m_butterfly-&gt;arrayStorage()-&gt;m_vector[i].get();
-        default:
-            CRASH();
-            return JSValue();
-        }
-    }
-        
-    template&lt;IndexingType indexingType&gt;
-    unsigned relevantLength()
-    {
-        switch (indexingType) {
-        case ALL_INT32_INDEXING_TYPES:
-        case ALL_DOUBLE_INDEXING_TYPES:
-        case ALL_CONTIGUOUS_INDEXING_TYPES:
-            return m_butterfly-&gt;publicLength();
-                
-        case ALL_ARRAY_STORAGE_INDEXING_TYPES:
-            return std::min(
-                m_butterfly-&gt;arrayStorage()-&gt;length(),
-                m_butterfly-&gt;arrayStorage()-&gt;vectorLength());
-                
-        default:
-            CRASH();
-            return 0;
-        }
-    }
-
-    unsigned currentRelevantLength()
-    {
-        switch (indexingType()) {
-        case ALL_INT32_INDEXING_TYPES:
-        case ALL_DOUBLE_INDEXING_TYPES:
-        case ALL_CONTIGUOUS_INDEXING_TYPES:
-            return m_butterfly-&gt;publicLength();
-
-        case ALL_ARRAY_STORAGE_INDEXING_TYPES:
-            return std::min(
-                m_butterfly-&gt;arrayStorage()-&gt;length(),
-                m_butterfly-&gt;arrayStorage()-&gt;vectorLength());
-
-        default:
-            CRASH();
-            return 0;
-        }
-    }
-
</del><span class="cx"> private:
</span><span class="cx">     friend class LLIntOffsetsExtractor;
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSString.h (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSString.h        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/JSString.h        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -62,6 +62,11 @@
</span><span class="cx"> 
</span><span class="cx"> JSRopeString* jsStringBuilder(VM*);
</span><span class="cx"> 
</span><ins>+struct StringViewWithUnderlyingString {
+    StringView view;
+    String underlyingString;
+};
+
</ins><span class="cx"> class JSString : public JSCell {
</span><span class="cx"> public:
</span><span class="cx">     friend class JIT;
</span><span class="lines">@@ -144,6 +149,7 @@
</span><span class="cx">     AtomicString toAtomicString(ExecState*) const;
</span><span class="cx">     RefPtr&lt;AtomicStringImpl&gt; toExistingAtomicString(ExecState*) const;
</span><span class="cx">     StringView view(ExecState*) const;
</span><ins>+    StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&amp;) 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">@@ -384,6 +390,7 @@
</span><span class="cx">     void resolveRopeInternal16NoSubstring(UChar*) const;
</span><span class="cx">     void clearFibers() const;
</span><span class="cx">     StringView view(ExecState*) const;
</span><ins>+    StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&amp;) const;
</ins><span class="cx"> 
</span><span class="cx">     WriteBarrierBase&lt;JSString&gt;&amp; fiber(unsigned i) const
</span><span class="cx">     {
</span><span class="lines">@@ -673,32 +680,6 @@
</span><span class="cx">     return toWTFStringSlowCase(exec);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue&amp; value, ExecState* exec)
-{
-    VM&amp; vm = exec-&gt;vm();
-    if (value.isInt32())
-        return vm.numericStrings.add(value.asInt32());
-    if (value.isDouble())
-        return vm.numericStrings.add(value.asDouble());
-    if (value.isTrue())
-        return vm.propertyNames-&gt;trueKeyword.string();
-    if (value.isFalse())
-        return vm.propertyNames-&gt;falseKeyword.string();
-    if (value.isNull())
-        return vm.propertyNames-&gt;nullKeyword.string();
-    if (value.isUndefined())
-        return vm.propertyNames-&gt;undefinedKeyword.string();
-    return value.toString(exec)-&gt;value(exec);
-}
-
-ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const
-{
-    if (isString())
-        return static_cast&lt;JSString*&gt;(asCell())-&gt;value(exec);
-
-    return inlineJSValueNotStringtoString(*this, exec);
-}
-
</del><span class="cx"> ALWAYS_INLINE StringView JSRopeString::view(ExecState* exec) const
</span><span class="cx"> {
</span><span class="cx">     if (isSubstring()) {
</span><span class="lines">@@ -710,6 +691,18 @@
</span><span class="cx">     return StringView(m_value);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState&amp; state) const
+{
+    if (isSubstring()) {
+        auto&amp; base = substringBase()-&gt;m_value;
+        if (is8Bit())
+            return { { base.characters8() + substringOffset(), m_length }, base };
+        return { { base.characters16() + substringOffset(), m_length }, base };
+    }
+    resolveRope(&amp;state);
+    return { m_value, m_value };
+}
+
</ins><span class="cx"> ALWAYS_INLINE StringView JSString::view(ExecState* exec) const
</span><span class="cx"> {
</span><span class="cx">     if (isRope())
</span><span class="lines">@@ -717,6 +710,13 @@
</span><span class="cx">     return StringView(m_value);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState&amp; state) const
+{
+    if (isRope())
+        return static_cast&lt;const JSRopeString&amp;&gt;(*this).viewWithUnderlyingString(state);
+    return { m_value, m_value };
+}
+
</ins><span class="cx"> inline bool JSString::isSubstring() const
</span><span class="cx"> {
</span><span class="cx">     return isRope() &amp;&amp; static_cast&lt;const JSRopeString*&gt;(this)-&gt;isSubstring();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringJoinercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSStringJoiner.cpp (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSStringJoiner.cpp        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/JSStringJoiner.cpp        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012-2015 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">@@ -26,105 +26,94 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;JSStringJoiner.h&quot;
</span><span class="cx"> 
</span><del>-#include &quot;ExceptionHelpers.h&quot;
-#include &quot;JSScope.h&quot;
-#include &quot;JSString.h&quot;
</del><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><del>-#include &lt;wtf/text/StringImpl.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-// The destination is 16bits, at least one string is 16 bits.
-static inline void appendStringToData(UChar*&amp; data, const String&amp; string)
</del><ins>+template&lt;typename CharacterType&gt;
+static inline void appendStringToData(CharacterType*&amp; data, StringView string)
</ins><span class="cx"> {
</span><del>-    if (string.isNull())
-        return;
-
-    unsigned length = string.length();
-    const StringImpl* stringImpl = string.impl();
-
-    if (stringImpl-&gt;is8Bit()) {
-        for (unsigned i = 0; i &lt; length; ++i) {
-            *data = stringImpl-&gt;characters8()[i];
-            ++data;
-        }
-    } else {
-        for (unsigned i = 0; i &lt; length; ++i) {
-            *data = stringImpl-&gt;characters16()[i];
-            ++data;
-        }
-    }
</del><ins>+    string.getCharactersWithUpconvert(data);
+    data += string.length();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-// If the destination is 8bits, we know every string has to be 8bit.
-static inline void appendStringToData(LChar*&amp; data, const String&amp; string)
</del><ins>+template&lt;typename CharacterType&gt;
+static inline String joinStrings(const Vector&lt;StringViewWithUnderlyingString&gt;&amp; strings, StringView separator, unsigned joinedLength)
</ins><span class="cx"> {
</span><del>-    if (string.isNull())
-        return;
-    ASSERT(string.is8Bit());
</del><ins>+    ASSERT(joinedLength);
</ins><span class="cx"> 
</span><del>-    unsigned length = string.length();
-    const StringImpl* stringImpl = string.impl();
</del><ins>+    CharacterType* data;
+    String result = StringImpl::tryCreateUninitialized(joinedLength, data);
+    if (result.isNull())
+        return result;
</ins><span class="cx"> 
</span><del>-    for (unsigned i = 0; i &lt; length; ++i) {
-        *data = stringImpl-&gt;characters8()[i];
-        ++data;
</del><ins>+    appendStringToData(data, strings[0].view);
+
+    unsigned size = strings.size();
+
+    switch (separator.length()) {
+    case 0:
+        for (unsigned i = 1; i &lt; size; ++i)
+            appendStringToData(data, strings[i].view);
+        break;
+    case 1: {
+        CharacterType separatorCharacter = separator[0];
+        for (unsigned i = 1; i &lt; size; ++i) {
+            *data++ = separatorCharacter;
+            appendStringToData(data, strings[i].view);
+        }
+        break;
</ins><span class="cx">     }
</span><ins>+    default:
+        for (unsigned i = 1; i &lt; size; ++i) {
+            appendStringToData(data, separator);
+            appendStringToData(data, strings[i].view);
+        }
+    }
+    ASSERT(data == result.characters&lt;CharacterType&gt;() + joinedLength);
+
+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;typename CharacterType&gt;
-static inline PassRefPtr&lt;StringImpl&gt; joinStrings(const Vector&lt;String&gt;&amp; strings, const String&amp; separator, unsigned outputLength)
</del><ins>+inline unsigned JSStringJoiner::joinedLength(ExecState&amp; state) const
</ins><span class="cx"> {
</span><del>-    ASSERT(outputLength);
</del><ins>+    unsigned numberOfStrings = m_strings.size();
+    if (!numberOfStrings)
+        return 0;
</ins><span class="cx"> 
</span><del>-    CharacterType* data;
-    RefPtr&lt;StringImpl&gt; outputStringImpl = StringImpl::tryCreateUninitialized(outputLength, data);
-    if (!outputStringImpl)
-        return nullptr;
</del><ins>+    Checked&lt;unsigned, RecordOverflow&gt; separatorLength = m_separator.length();
+    Checked&lt;unsigned, RecordOverflow&gt; totalSeparatorsLength = separatorLength * (numberOfStrings - 1);
+    Checked&lt;unsigned, RecordOverflow&gt; totalLength = totalSeparatorsLength + m_accumulatedStringsLength;
</ins><span class="cx"> 
</span><del>-    const String firstString = strings.first();
-    appendStringToData(data, firstString);
-
-    for (size_t i = 1; i &lt; strings.size(); ++i) {
-        appendStringToData(data, separator);
-        appendStringToData(data, strings[i]);
</del><ins>+    unsigned result;
+    if (totalLength.safeGet(result) == CheckedState::DidOverflow) {
+        throwOutOfMemoryError(&amp;state);
+        return 0;
</ins><span class="cx">     }
</span><del>-
-    ASSERT(data == (outputStringImpl-&gt;characters&lt;CharacterType&gt;() + outputStringImpl-&gt;length()));
-    return outputStringImpl.release();
</del><ins>+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSValue JSStringJoiner::join(ExecState* exec)
</del><ins>+JSValue JSStringJoiner::join(ExecState&amp; state)
</ins><span class="cx"> {
</span><del>-    if (!m_isValid)
-        return throwOutOfMemoryError(exec);
</del><ins>+    ASSERT(m_strings.size() == m_strings.capacity());
</ins><span class="cx"> 
</span><del>-    if (!m_strings.size())
-        return jsEmptyString(exec);
</del><ins>+    unsigned length = joinedLength(state);
+    if (state.hadException())
+        return jsUndefined();
</ins><span class="cx"> 
</span><del>-    Checked&lt;unsigned, RecordOverflow&gt; separatorLength = m_separator.length();
-    // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1).
-    ASSERT(m_strings.size() &gt; 0);
-    Checked&lt;unsigned, RecordOverflow&gt; totalSeparactorsLength = separatorLength * (m_strings.size() - 1);
-    Checked&lt;unsigned, RecordOverflow&gt; outputStringSize = totalSeparactorsLength + m_accumulatedStringsLength;
</del><ins>+    if (!length)
+        return jsEmptyString(&amp;state);
</ins><span class="cx"> 
</span><del>-    unsigned finalSize;
-    if (outputStringSize.safeGet(finalSize) == CheckedState::DidOverflow)
-        return throwOutOfMemoryError(exec);
-        
-    if (!outputStringSize)
-        return jsEmptyString(exec);
-
-    RefPtr&lt;StringImpl&gt; outputStringImpl;
-    if (m_is8Bits)
-        outputStringImpl = joinStrings&lt;LChar&gt;(m_strings, m_separator, finalSize);
</del><ins>+    String result;
+    if (m_isAll8Bit)
+        result = joinStrings&lt;LChar&gt;(m_strings, m_separator, length);
</ins><span class="cx">     else
</span><del>-        outputStringImpl = joinStrings&lt;UChar&gt;(m_strings, m_separator, finalSize);
</del><ins>+        result = joinStrings&lt;UChar&gt;(m_strings, m_separator, length);
</ins><span class="cx"> 
</span><del>-    if (!outputStringImpl)
-        return throwOutOfMemoryError(exec);
</del><ins>+    if (result.isNull())
+        return throwOutOfMemoryError(&amp;state);
</ins><span class="cx"> 
</span><del>-    return JSString::create(exec-&gt;vm(), outputStringImpl.release());
</del><ins>+    return jsString(&amp;state, WTF::move(result));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringJoinerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSStringJoiner.h (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSStringJoiner.h        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/JavaScriptCore/runtime/JSStringJoiner.h        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012-2015 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">@@ -26,50 +26,112 @@
</span><span class="cx"> #ifndef JSStringJoiner_h
</span><span class="cx"> #define JSStringJoiner_h
</span><span class="cx"> 
</span><ins>+#include &quot;ExceptionHelpers.h&quot;
</ins><span class="cx"> #include &quot;JSCJSValue.h&quot;
</span><del>-#include &lt;wtf/Vector.h&gt;
-#include &lt;wtf/text/WTFString.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-class ExecState;
-
-
</del><span class="cx"> class JSStringJoiner {
</span><span class="cx"> public:
</span><del>-    JSStringJoiner(const String&amp; separator, size_t stringCount);
</del><ins>+    JSStringJoiner(ExecState&amp;, LChar separator, unsigned stringCount);
+    JSStringJoiner(ExecState&amp;, StringView separator, unsigned stringCount);
</ins><span class="cx"> 
</span><del>-    void append(const String&amp;);
-    JSValue join(ExecState*);
</del><ins>+    void append(ExecState&amp;, JSValue);
</ins><span class="cx"> 
</span><ins>+    JSValue join(ExecState&amp;);
+
</ins><span class="cx"> private:
</span><del>-    String m_separator;
-    Vector&lt;String&gt; m_strings;
</del><ins>+    void append(StringViewWithUnderlyingString&amp;&amp;);
+    void append8Bit(const String&amp;);
+    void appendLiteral(const Identifier&amp;);
+    void appendEmptyString();
+    unsigned joinedLength(ExecState&amp;) const;
</ins><span class="cx"> 
</span><ins>+    LChar m_singleCharacterSeparator;
+    StringView m_separator;
+    Vector&lt;StringViewWithUnderlyingString&gt; m_strings;
</ins><span class="cx">     Checked&lt;unsigned, RecordOverflow&gt; m_accumulatedStringsLength;
</span><del>-    bool m_isValid;
-    bool m_is8Bits;
</del><ins>+    bool m_isAll8Bit { true };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-inline JSStringJoiner::JSStringJoiner(const String&amp; separator, size_t stringCount)
</del><ins>+inline JSStringJoiner::JSStringJoiner(ExecState&amp; state, StringView separator, unsigned stringCount)
</ins><span class="cx">     : m_separator(separator)
</span><del>-    , m_isValid(true)
-    , m_is8Bits(m_separator.is8Bit())
</del><ins>+    , m_isAll8Bit(m_separator.is8Bit())
</ins><span class="cx"> {
</span><del>-    ASSERT(!m_separator.isNull());
-    m_isValid = m_strings.tryReserveCapacity(stringCount);
</del><ins>+    if (!m_strings.tryReserveCapacity(stringCount))
+        throwOutOfMemoryError(&amp;state);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void JSStringJoiner::append(const String&amp; str)
</del><ins>+inline JSStringJoiner::JSStringJoiner(ExecState&amp; state, LChar separator, unsigned stringCount)
+    : m_singleCharacterSeparator(separator)
+    , m_separator { &amp;m_singleCharacterSeparator, 1 }
</ins><span class="cx"> {
</span><del>-    if (!m_isValid)
</del><ins>+    if (!m_strings.tryReserveCapacity(stringCount))
+        throwOutOfMemoryError(&amp;state);
+}
+
+ALWAYS_INLINE void JSStringJoiner::append(StringViewWithUnderlyingString&amp;&amp; string)
+{
+    m_accumulatedStringsLength += string.view.length();
+    m_isAll8Bit = m_isAll8Bit &amp;&amp; string.view.is8Bit();
+    m_strings.uncheckedAppend(WTF::move(string));
+}
+
+ALWAYS_INLINE void JSStringJoiner::append8Bit(const String&amp; string)
+{
+    ASSERT(string.is8Bit());
+    m_accumulatedStringsLength += string.length();
+    m_strings.uncheckedAppend({ string, string });
+}
+
+ALWAYS_INLINE void JSStringJoiner::appendLiteral(const Identifier&amp; literal)
+{
+    m_accumulatedStringsLength += literal.length();
+    ASSERT(literal.string().is8Bit());
+    m_strings.uncheckedAppend({ literal.string(), { } });
+}
+
+ALWAYS_INLINE void JSStringJoiner::appendEmptyString()
+{
+    m_strings.uncheckedAppend({ { }, { } });
+}
+
+ALWAYS_INLINE void JSStringJoiner::append(ExecState&amp; state, JSValue value)
+{
+    // The following code differs from using the result of JSValue::toString in the following ways:
+    // 1) It's inlined more than JSValue::toString is.
+    // 2) It includes conversion to WTF::String in a way that avoids allocating copies of substrings.
+    // 3) It doesn't create a JSString for numbers, true, or false.
+    // 4) It turns undefined and null into the empty string instead of &quot;undefined&quot; and &quot;null&quot;.
+    // 5) It uses optimized code paths for all the cases known to be 8-bit and for the empty string.
+
+    if (value.isCell()) {
+        if (value.asCell()-&gt;isString()) {
+            append(asString(value)-&gt;viewWithUnderlyingString(state));
+            return;
+        }
+        append(value.toString(&amp;state)-&gt;viewWithUnderlyingString(state));
</ins><span class="cx">         return;
</span><ins>+    }
</ins><span class="cx"> 
</span><del>-    m_strings.append(str);
-    if (!str.isNull()) {
-        m_accumulatedStringsLength += str.length();
-        m_is8Bits = m_is8Bits &amp;&amp; str.is8Bit();
</del><ins>+    if (value.isInt32()) {
+        append8Bit(state.vm().numericStrings.add(value.asInt32()));
+        return;
</ins><span class="cx">     }
</span><ins>+    if (value.isDouble()) {
+        append8Bit(state.vm().numericStrings.add(value.asDouble()));
+        return;
+    }
+    if (value.isTrue()) {
+        append8Bit(state.vm().propertyNames-&gt;trueKeyword.string());
+        return;
+    }
+    if (value.isFalse()) {
+        append8Bit(state.vm().propertyNames-&gt;falseKeyword.string());
+        return;
+    }
+    ASSERT(value.isUndefinedOrNull());
+    appendEmptyString();
</ins><span class="cx"> }
</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 (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/WTF/ChangeLog        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2015-06-22  Darin Adler  &lt;darin@apple.com&gt;
+
+        Make Array.join work directly on substrings without reifying them
+        https://bugs.webkit.org/show_bug.cgi?id=146191
+
+        Reviewed by Andreas Kling.
+
+        * wtf/Vector.h: Added an overload of uncheckedAppend like the one we added
+        a while back, a non-template function that forwards through to the function
+        template. This lets us call uncheckedAppend on an argument list and have it
+        properly convert it to the Vector's element type.
+
+        * wtf/text/StringView.h:
+        (WTF::StringView::getCharactersWithUpconvert): Changed to not use memcpy;
+        saw some indication the hand-written loop was faster when profiling. Also
+        use m_length directly when we know we are dealing with an 8-bit string,
+        since the masking that the index function does is not needed in that case.
+        (WTF::StringView::UpconvertedCharacters::UpconvertedCharacters): Ditto.
+        (WTF::StringView::toString): Ditto.
+        (WTF::StringView::toFloat): Ditto.
+        (WTF::StringView::toInt): Ditto.
+        (WTF::StringView::toStringWithoutCopying): Ditto.
+        (WTF::StringView::find): Ditto.
+
</ins><span class="cx"> 2015-06-22  YunQiang Su  &lt;wzssyqa@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [WTF] Platform.h: use _ABI64 instead of _MIPS_SIM_ABI64 to determine MIPS N64
</span></span></pre></div>
<a id="trunkSourceWTFwtfVectorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Vector.h (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Vector.h        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/WTF/wtf/Vector.h        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -724,9 +724,12 @@
</span><span class="cx">     void clear() { shrinkCapacity(0); }
</span><span class="cx"> 
</span><span class="cx">     void append(ValueType&amp;&amp; value) { append&lt;ValueType&gt;(std::forward&lt;ValueType&gt;(value)); }
</span><ins>+    template&lt;typename U&gt; void append(U&amp;&amp;);
+
+    void uncheckedAppend(ValueType&amp;&amp; value) { uncheckedAppend&lt;ValueType&gt;(std::forward&lt;ValueType&gt;(value)); }
+    template&lt;typename U&gt; void uncheckedAppend(U&amp;&amp;);
+
</ins><span class="cx">     template&lt;typename U&gt; void append(const U*, size_t);
</span><del>-    template&lt;typename U&gt; void append(U&amp;&amp;);
-    template&lt;typename U&gt; void uncheckedAppend(U&amp;&amp; val);
</del><span class="cx">     template&lt;typename U, size_t otherCapacity&gt; void appendVector(const Vector&lt;U, otherCapacity&gt;&amp;);
</span><span class="cx">     template&lt;typename U&gt; bool tryAppend(const U*, size_t);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringView.h (185898 => 185899)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringView.h        2015-06-24 02:13:24 UTC (rev 185898)
+++ trunk/Source/WTF/wtf/text/StringView.h        2015-06-24 02:33:18 UTC (rev 185899)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2015 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">@@ -409,19 +409,23 @@
</span><span class="cx"> inline void StringView::getCharactersWithUpconvert(LChar* destination) const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(is8Bit());
</span><del>-    memcpy(destination, characters8(), length());
</del><ins>+    auto characters8 = this-&gt;characters8();
+    for (unsigned i = 0; i &lt; m_length; ++i)
+        destination[i] = characters8[i];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void StringView::getCharactersWithUpconvert(UChar* destination) const
</span><span class="cx"> {
</span><span class="cx">     if (is8Bit()) {
</span><del>-        const LChar* characters8 = this-&gt;characters8();
-        unsigned length = this-&gt;length();
-        for (unsigned i = 0; i &lt; length; ++i)
</del><ins>+        auto characters8 = this-&gt;characters8();
+        for (unsigned i = 0; i &lt; m_length; ++i)
</ins><span class="cx">             destination[i] = characters8[i];
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    memcpy(destination, characters16(), length() * sizeof(UChar));
</del><ins>+    auto characters16 = this-&gt;characters16();
+    unsigned length = this-&gt;length();
+    for (unsigned i = 0; i &lt; length; ++i)
+        destination[i] = characters16[i];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline StringView::UpconvertedCharacters::UpconvertedCharacters(const StringView&amp; string)
</span><span class="lines">@@ -431,7 +435,7 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     const LChar* characters8 = string.characters8();
</span><del>-    unsigned length = string.length();
</del><ins>+    unsigned length = string.m_length;
</ins><span class="cx">     m_upconvertedCharacters.reserveInitialCapacity(length);
</span><span class="cx">     for (unsigned i = 0; i &lt; length; ++i)
</span><span class="cx">         m_upconvertedCharacters.uncheckedAppend(characters8[i]);
</span><span class="lines">@@ -441,35 +445,35 @@
</span><span class="cx"> inline String StringView::toString() const
</span><span class="cx"> {
</span><span class="cx">     if (is8Bit())
</span><del>-        return String(characters8(), length());
</del><ins>+        return String(characters8(), m_length);
</ins><span class="cx">     return String(characters16(), length());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline float StringView::toFloat(bool&amp; isValid) const
</span><span class="cx"> {
</span><span class="cx">     if (is8Bit())
</span><del>-        return charactersToFloat(characters8(), length(), &amp;isValid);
</del><ins>+        return charactersToFloat(characters8(), m_length, &amp;isValid);
</ins><span class="cx">     return charactersToFloat(characters16(), length(), &amp;isValid);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline int StringView::toInt(bool&amp; isValid) const
</span><span class="cx"> {
</span><span class="cx">     if (is8Bit())
</span><del>-        return charactersToInt(characters8(), length(), &amp;isValid);
</del><ins>+        return charactersToInt(characters8(), m_length, &amp;isValid);
</ins><span class="cx">     return charactersToInt(characters16(), length(), &amp;isValid);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline String StringView::toStringWithoutCopying() const
</span><span class="cx"> {
</span><span class="cx">     if (is8Bit())
</span><del>-        return StringImpl::createWithoutCopying(characters8(), length());
</del><ins>+        return StringImpl::createWithoutCopying(characters8(), m_length);
</ins><span class="cx">     return StringImpl::createWithoutCopying(characters16(), length());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline size_t StringView::find(UChar character, unsigned start) const
</span><span class="cx"> {
</span><span class="cx">     if (is8Bit())
</span><del>-        return WTF::find(characters8(), length(), character, start);
</del><ins>+        return WTF::find(characters8(), m_length, character, start);
</ins><span class="cx">     return WTF::find(characters16(), length(), character, start);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>