Reserve capacity for StringBuilder in unescape
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Jan 2017 16:19:33 +0000 (16:19 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Jan 2017 16:19:33 +0000 (16:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=167008

Reviewed by Sam Weinig.

JSTests:

* stress/unescape.js: Added.
(shouldBe):

Source/JavaScriptCore:

`unescape` function is frequently called in Kraken sha256-iterative.
This patch just reserves the capacity for the StringBuilder.

Currently, we select the length of the string for the reserved capacity.
It improves the performance 2.73%.

    Benchmark report for Kraken on sakura-trick.

    VMs tested:
    "baseline" at /home/yusukesuzuki/dev/WebKit/WebKitBuild/untot/Release/bin/jsc
    "patched" at /home/yusukesuzuki/dev/WebKit/WebKitBuild/un/Release/bin/jsc

    Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc() between
    sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the jsc-specific preciseTime()
    function to get microsecond-level timing. Reporting benchmark execution times with 95% confidence intervals in
    milliseconds.

                                               baseline                  patched

    stanford-crypto-sha256-iterative        51.609+-0.672             50.237+-0.860           might be 1.0273x faster

    <arithmetic>                            51.609+-0.672             50.237+-0.860           might be 1.0273x faster

* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncUnescape):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@210766 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/unescape.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

index c2c3743..c0e6c46 100644 (file)
@@ -1,3 +1,13 @@
+2017-01-14  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Reserve capacity for StringBuilder in unescape
+        https://bugs.webkit.org/show_bug.cgi?id=167008
+
+        Reviewed by Sam Weinig.
+
+        * stress/unescape.js: Added.
+        (shouldBe):
+
 2017-01-12  Saam Barati  <sbarati@apple.com>
 
         Add a slice intrinsic to the DFG/FTL
diff --git a/JSTests/stress/unescape.js b/JSTests/stress/unescape.js
new file mode 100644 (file)
index 0000000..f8c1524
--- /dev/null
@@ -0,0 +1,7 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+shouldBe(unescape("%0"), "%0");
+shouldBe(unescape("%a"), "%a");
index a07ac08..552f736 100644 (file)
@@ -1,3 +1,36 @@
+2017-01-14  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Reserve capacity for StringBuilder in unescape
+        https://bugs.webkit.org/show_bug.cgi?id=167008
+
+        Reviewed by Sam Weinig.
+
+        `unescape` function is frequently called in Kraken sha256-iterative.
+        This patch just reserves the capacity for the StringBuilder.
+
+        Currently, we select the length of the string for the reserved capacity.
+        It improves the performance 2.73%.
+
+            Benchmark report for Kraken on sakura-trick.
+
+            VMs tested:
+            "baseline" at /home/yusukesuzuki/dev/WebKit/WebKitBuild/untot/Release/bin/jsc
+            "patched" at /home/yusukesuzuki/dev/WebKit/WebKitBuild/un/Release/bin/jsc
+
+            Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc() between
+            sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the jsc-specific preciseTime()
+            function to get microsecond-level timing. Reporting benchmark execution times with 95% confidence intervals in
+            milliseconds.
+
+                                                       baseline                  patched
+
+            stanford-crypto-sha256-iterative        51.609+-0.672             50.237+-0.860           might be 1.0273x faster
+
+            <arithmetic>                            51.609+-0.672             50.237+-0.860           might be 1.0273x faster
+
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncUnescape):
+
 2017-01-13  Joseph Pecoraro  <pecoraro@apple.com>
 
         Remove ENABLE(DETAILS_ELEMENT) guards
index 47e6ccd..d5e6f29 100644 (file)
@@ -814,22 +814,26 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
 EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
 {
     return JSValue::encode(toStringView(exec, exec->argument(0), [&] (StringView view) {
-        StringBuilder builder;
+        // We use int for k and length intentionally since we would like to evaluate
+        // the condition `k <= length -6` even if length is less than 6.
         int k = 0;
-        int len = view.length();
+        int length = view.length();
+
+        StringBuilder builder;
+        builder.reserveCapacity(length);
 
         if (view.is8Bit()) {
             const LChar* characters = view.characters8();
             LChar convertedLChar;
-            while (k < len) {
+            while (k < length) {
                 const LChar* c = characters + k;
-                if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
+                if (c[0] == '%' && k <= length - 6 && c[1] == 'u') {
                     if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
                         builder.append(Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]));
                         k += 6;
                         continue;
                     }
-                } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
+                } else if (c[0] == '%' && k <= length - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
                     convertedLChar = LChar(Lexer<LChar>::convertHex(c[1], c[2]));
                     c = &convertedLChar;
                     k += 2;
@@ -840,16 +844,16 @@ EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
         } else {
             const UChar* characters = view.characters16();
 
-            while (k < len) {
+            while (k < length) {
                 const UChar* c = characters + k;
                 UChar convertedUChar;
-                if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
+                if (c[0] == '%' && k <= length - 6 && c[1] == 'u') {
                     if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
                         convertedUChar = Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]);
                         c = &convertedUChar;
                         k += 5;
                     }
-                } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
+                } else if (c[0] == '%' && k <= length - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
                     convertedUChar = UChar(Lexer<UChar>::convertHex(c[1], c[2]));
                     c = &convertedUChar;
                     k += 2;