Title: [223834] trunk
Revision
223834
Author
utatane....@gmail.com
Date
2017-10-23 04:50:21 -0700 (Mon, 23 Oct 2017)

Log Message

[JSC] Use fastJoin in Array#toString
https://bugs.webkit.org/show_bug.cgi?id=178062

Reviewed by Darin Adler.

JSTests:

* microbenchmarks/contiguous-array-to-string.js: Added.
(target):
* microbenchmarks/double-array-to-string.js: Added.
(target):
* microbenchmarks/int32-array-to-string.js: Added.
(target):

Source/_javascript_Core:

Array#toString()'s fast path uses original join operation.
But this should use fastJoin if possible.
This patch adds a fast path using fastJoin in Array#toString.
And we also extend fastJoin to perform fast joining for int32
arrays.

                                     baseline                  patched

double-array-to-string          126.6157+-5.8625     ^    103.7343+-4.4968        ^ definitely 1.2206x faster
int32-array-to-string            64.7792+-2.6524           61.2390+-2.1749          might be 1.0578x faster
contiguous-array-to-string       62.6224+-2.6388     ^     56.9899+-2.0852        ^ definitely 1.0988x faster

* runtime/ArrayPrototype.cpp:
(JSC::fastJoin):
(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncToLocaleString):
* runtime/JSStringJoiner.h:
(JSC::JSStringJoiner::appendWithoutSideEffects):
(JSC::JSStringJoiner::appendInt32):
(JSC::JSStringJoiner::appendDouble):

Source/WTF:

A bit cleaning up to use StringImpl::copyChars instead of
using for-loop directly.

* wtf/text/StringView.h:
(WTF::StringView::getCharactersWithUpconvert const):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (223833 => 223834)


--- trunk/JSTests/ChangeLog	2017-10-23 10:11:12 UTC (rev 223833)
+++ trunk/JSTests/ChangeLog	2017-10-23 11:50:21 UTC (rev 223834)
@@ -1,3 +1,17 @@
+2017-10-23  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Use fastJoin in Array#toString
+        https://bugs.webkit.org/show_bug.cgi?id=178062
+
+        Reviewed by Darin Adler.
+
+        * microbenchmarks/contiguous-array-to-string.js: Added.
+        (target):
+        * microbenchmarks/double-array-to-string.js: Added.
+        (target):
+        * microbenchmarks/int32-array-to-string.js: Added.
+        (target):
+
 2017-10-22  Zan Dobersek  <zdober...@igalia.com>
 
         stress/check-string-ident.js is improperly skipped

Added: trunk/JSTests/microbenchmarks/contiguous-array-to-string.js (0 => 223834)


--- trunk/JSTests/microbenchmarks/contiguous-array-to-string.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/contiguous-array-to-string.js	2017-10-23 11:50:21 UTC (rev 223834)
@@ -0,0 +1,12 @@
+var array = [];
+for (var i = 0; i < 20; ++i)
+    array.push(`${i}`);
+
+function target(array)
+{
+    return array.toString();
+}
+noInline(target);
+
+for (var i = 0; i < 1e5; ++i)
+    target(array);

Added: trunk/JSTests/microbenchmarks/double-array-to-string.js (0 => 223834)


--- trunk/JSTests/microbenchmarks/double-array-to-string.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/double-array-to-string.js	2017-10-23 11:50:21 UTC (rev 223834)
@@ -0,0 +1,12 @@
+var array = [];
+for (var i = 0; i < 20; ++i)
+    array.push(i * 0.1);
+
+function target(array)
+{
+    return array.toString();
+}
+noInline(target);
+
+for (var i = 0; i < 1e5; ++i)
+    target(array);

Added: trunk/JSTests/microbenchmarks/int32-array-to-string.js (0 => 223834)


--- trunk/JSTests/microbenchmarks/int32-array-to-string.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/int32-array-to-string.js	2017-10-23 11:50:21 UTC (rev 223834)
@@ -0,0 +1,12 @@
+var array = [];
+for (var i = 0; i < 20; ++i)
+    array.push(i);
+
+function target(array)
+{
+    return array.toString();
+}
+noInline(target);
+
+for (var i = 0; i < 1e5; ++i)
+    target(array);

Added: trunk/JSTests/stress/array-to-locale-string.js (0 => 223834)


--- trunk/JSTests/stress/array-to-locale-string.js	                        (rev 0)
+++ trunk/JSTests/stress/array-to-locale-string.js	2017-10-23 11:50:21 UTC (rev 223834)
@@ -0,0 +1,7 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var array = [null, null, null];
+shouldBe(array.toLocaleString(), `,,`)

Modified: trunk/Source/_javascript_Core/ChangeLog (223833 => 223834)


--- trunk/Source/_javascript_Core/ChangeLog	2017-10-23 10:11:12 UTC (rev 223833)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-10-23 11:50:21 UTC (rev 223834)
@@ -1,3 +1,32 @@
+2017-10-23  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Use fastJoin in Array#toString
+        https://bugs.webkit.org/show_bug.cgi?id=178062
+
+        Reviewed by Darin Adler.
+
+        Array#toString()'s fast path uses original join operation.
+        But this should use fastJoin if possible.
+        This patch adds a fast path using fastJoin in Array#toString.
+        And we also extend fastJoin to perform fast joining for int32
+        arrays.
+
+                                             baseline                  patched
+
+        double-array-to-string          126.6157+-5.8625     ^    103.7343+-4.4968        ^ definitely 1.2206x faster
+        int32-array-to-string            64.7792+-2.6524           61.2390+-2.1749          might be 1.0578x faster
+        contiguous-array-to-string       62.6224+-2.6388     ^     56.9899+-2.0852        ^ definitely 1.0988x faster
+
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::fastJoin):
+        (JSC::arrayProtoFuncToString):
+        (JSC::arrayProtoFuncToLocaleString):
+        * runtime/JSStringJoiner.h:
+        (JSC::JSStringJoiner::appendWithoutSideEffects):
+        (JSC::JSStringJoiner::appendInt32):
+        (JSC::JSStringJoiner::appendDouble):
+
 2017-10-22  Zan Dobersek  <zdober...@igalia.com>
 
         [JSC] Remove !(OS(LINUX) && CPU(ARM64)) guards in RegisterState.h

Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (223833 => 223834)


--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2017-10-23 10:11:12 UTC (rev 223833)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2017-10-23 11:50:21 UTC (rev 223834)
@@ -380,6 +380,9 @@
     }
 }
 
+static bool canUseFastJoin(const JSObject*);
+static JSValue fastJoin(ExecState&, JSObject*, StringView, unsigned);
+
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -424,6 +427,12 @@
     if (JSValue earlyReturnValue = checker.earlyReturnValue())
         return JSValue::encode(earlyReturnValue);
 
+    if (LIKELY(canUseFastJoin(thisArray))) {
+        const LChar comma = ',';
+        scope.release();
+        return JSValue::encode(fastJoin(*exec, thisArray, { &comma, 1 }, length));
+    }
+
     JSStringJoiner joiner(*exec, ',', length);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
@@ -462,6 +471,7 @@
 
 #if ENABLE(INTL)
     ArgList arguments(exec);
+#endif
     for (unsigned i = 0; i < length; ++i) {
         JSValue element = thisObject->getIndex(exec, i);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
@@ -473,7 +483,11 @@
             CallData callData;
             CallType callType = getCallData(conversionFunction, callData);
             if (callType != CallType::None) {
+#if ENABLE(INTL)
                 element = call(exec, conversionFunction, callType, callData, element, arguments);
+#else
+                element = call(exec, conversionFunction, callType, callData, element, *vm.emptyList);
+#endif
                 RETURN_IF_EXCEPTION(scope, encodedJSValue());
             }
         }
@@ -480,24 +494,6 @@
         stringJoiner.append(*exec, element);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
     }
-#else // !ENABLE(INTL)
-    for (unsigned i = 0; i < length; ++i) {
-        JSValue element = thisObject->getIndex(exec, i);
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        if (element.isUndefinedOrNull())
-            continue;
-        JSValue conversionFunction = element.get(exec, vm.propertyNames->toLocaleString);
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        CallData callData;
-        CallType callType = getCallData(conversionFunction, callData);
-        if (callType != CallType::None) {
-            element = call(exec, conversionFunction, callType, callData, element, *vm.emptyList);
-            RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        }
-        stringJoiner.append(*exec, element);
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    }
-#endif // !ENABLE(INTL)
 
     scope.release();
     return JSValue::encode(stringJoiner.join(*exec));
@@ -594,10 +590,9 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     switch (thisObject->indexingType()) {
-    case ALL_CONTIGUOUS_INDEXING_TYPES:
     case ALL_INT32_INDEXING_TYPES: {
         auto& butterfly = *thisObject->butterfly();
-        if (length > butterfly.publicLength())
+        if (UNLIKELY(length > butterfly.publicLength()))
             break;
         JSStringJoiner joiner(state, separator, length);
         RETURN_IF_EXCEPTION(scope, { });
@@ -604,6 +599,30 @@
         auto data = ""
         bool holesKnownToBeOK = false;
         for (unsigned i = 0; i < length; ++i) {
+            JSValue value = data[i].get();
+            if (LIKELY(value))
+                joiner.appendNumber(vm, value.asInt32());
+            else {
+                if (!holesKnownToBeOK) {
+                    if (holesMustForwardToPrototype(vm, thisObject))
+                        goto generalCase;
+                    holesKnownToBeOK = true;
+                }
+                joiner.appendEmptyString();
+            }
+        }
+        scope.release();
+        return joiner.join(state);
+    }
+    case ALL_CONTIGUOUS_INDEXING_TYPES: {
+        auto& butterfly = *thisObject->butterfly();
+        if (UNLIKELY(length > butterfly.publicLength()))
+            break;
+        JSStringJoiner joiner(state, separator, length);
+        RETURN_IF_EXCEPTION(scope, { });
+        auto data = ""
+        bool holesKnownToBeOK = false;
+        for (unsigned i = 0; i < length; ++i) {
             if (JSValue value = data[i].get()) {
                 if (!joiner.appendWithoutSideEffects(state, value))
                     goto generalCase;
@@ -621,7 +640,7 @@
     }
     case ALL_DOUBLE_INDEXING_TYPES: {
         auto& butterfly = *thisObject->butterfly();
-        if (length > butterfly.publicLength())
+        if (UNLIKELY(length > butterfly.publicLength()))
             break;
         JSStringJoiner joiner(state, separator, length);
         RETURN_IF_EXCEPTION(scope, { });
@@ -629,8 +648,8 @@
         bool holesKnownToBeOK = false;
         for (unsigned i = 0; i < length; ++i) {
             double value = data[i];
-            if (!isHole(value))
-                joiner.append(state, jsDoubleNumber(value));
+            if (LIKELY(!isHole(value)))
+                joiner.appendNumber(vm, value);
             else {
                 if (!holesKnownToBeOK) {
                     if (holesMustForwardToPrototype(vm, thisObject))

Modified: trunk/Source/_javascript_Core/runtime/JSStringJoiner.h (223833 => 223834)


--- trunk/Source/_javascript_Core/runtime/JSStringJoiner.h	2017-10-23 10:11:12 UTC (rev 223833)
+++ trunk/Source/_javascript_Core/runtime/JSStringJoiner.h	2017-10-23 11:50:21 UTC (rev 223834)
@@ -37,6 +37,8 @@
     ~JSStringJoiner();
 
     void append(ExecState&, JSValue);
+    void appendNumber(VM&, int32_t);
+    void appendNumber(VM&, double);
     bool appendWithoutSideEffects(ExecState&, JSValue);
     void appendEmptyString();
 
@@ -121,11 +123,11 @@
     }
 
     if (value.isInt32()) {
-        append8Bit(state.vm().numericStrings.add(value.asInt32()));
+        appendNumber(state.vm(), value.asInt32());
         return true;
     }
     if (value.isDouble()) {
-        append8Bit(state.vm().numericStrings.add(value.asDouble()));
+        appendNumber(state.vm(), value.asDouble());
         return true;
     }
     if (value.isTrue()) {
@@ -149,4 +151,14 @@
     }
 }
 
+ALWAYS_INLINE void JSStringJoiner::appendNumber(VM& vm, int32_t value)
+{
+    append8Bit(vm.numericStrings.add(value));
+}
+
+ALWAYS_INLINE void JSStringJoiner::appendNumber(VM& vm, double value)
+{
+    append8Bit(vm.numericStrings.add(value));
+}
+
 } // namespace JSC

Modified: trunk/Source/WTF/ChangeLog (223833 => 223834)


--- trunk/Source/WTF/ChangeLog	2017-10-23 10:11:12 UTC (rev 223833)
+++ trunk/Source/WTF/ChangeLog	2017-10-23 11:50:21 UTC (rev 223834)
@@ -1,3 +1,16 @@
+2017-10-23  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Use fastJoin in Array#toString
+        https://bugs.webkit.org/show_bug.cgi?id=178062
+
+        Reviewed by Darin Adler.
+
+        A bit cleaning up to use StringImpl::copyChars instead of
+        using for-loop directly.
+
+        * wtf/text/StringView.h:
+        (WTF::StringView::getCharactersWithUpconvert const):
+
 2017-10-20  Antoine Quint  <grao...@apple.com>
 
         [Web Animations] Provide basic timeline and animation interfaces

Modified: trunk/Source/WTF/wtf/text/StringView.h (223833 => 223834)


--- trunk/Source/WTF/wtf/text/StringView.h	2017-10-23 10:11:12 UTC (rev 223833)
+++ trunk/Source/WTF/wtf/text/StringView.h	2017-10-23 11:50:21 UTC (rev 223834)
@@ -451,22 +451,16 @@
 inline void StringView::getCharactersWithUpconvert(LChar* destination) const
 {
     ASSERT(is8Bit());
-    auto characters8 = this->characters8();
-    for (unsigned i = 0; i < m_length; ++i)
-        destination[i] = characters8[i];
+    StringImpl::copyChars(destination, characters8(), m_length);
 }
 
 inline void StringView::getCharactersWithUpconvert(UChar* destination) const
 {
     if (is8Bit()) {
-        auto characters8 = this->characters8();
-        for (unsigned i = 0; i < m_length; ++i)
-            destination[i] = characters8[i];
+        StringImpl::copyChars(destination, characters8(), m_length);
         return;
     }
-    auto characters16 = this->characters16();
-    for (unsigned i = 0; i < m_length; ++i)
-        destination[i] = characters16[i];
+    StringImpl::copyChars(destination, characters16(), m_length);
 }
 
 inline StringView::UpconvertedCharacters::UpconvertedCharacters(const StringView& string)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to