2010-05-13 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 May 2010 09:36:54 +0000 (09:36 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 May 2010 09:36:54 +0000 (09:36 +0000)
        Reviewed by Mark Rowe.

        Various JavaScript string optimizations
        https://bugs.webkit.org/show_bug.cgi?id=39051

        Approximately 1% SunSpider speedup.

        * runtime/ArrayPrototype.cpp:
        (JSC::arrayProtoFuncJoin): Remove branches from the hot code path
        by moving the first pass outside the loop, and duplicating the hot loop
        to extract the loop-invariant branch.
        * runtime/RegExp.cpp:
        (JSC::RegExp::match): resize ovector to 0 instead of clearing to avoid
        thrash in case of large matches.
        * runtime/RegExpConstructor.h:
        (JSC::RegExpConstructor::performMatch): Mark ALWAYS_INLINE to make the
        compiler respect our authority.
        * runtime/StringPrototype.cpp:
        (JSC::jsSpliceSubstringsWithSeparators): Inline.
        (JSC::stringProtoFuncSubstring): Rewrite boundary condition checks to
        reduce the number of floating point comparisons and branches.

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

JavaScriptCore/ChangeLog
JavaScriptCore/runtime/ArrayPrototype.cpp
JavaScriptCore/runtime/RegExp.cpp
JavaScriptCore/runtime/RegExpConstructor.h
JavaScriptCore/runtime/StringPrototype.cpp

index 78160b7fca383032d95238d1bb3257a5ae6d703f..61b609f86d978e70ba5b19fbe9367c043986b0b0 100644 (file)
@@ -1,3 +1,27 @@
+2010-05-13  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Mark Rowe.
+
+        Various JavaScript string optimizations
+        https://bugs.webkit.org/show_bug.cgi?id=39051
+
+        Approximately 1% SunSpider speedup.
+        
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncJoin): Remove branches from the hot code path
+        by moving the first pass outside the loop, and duplicating the hot loop
+        to extract the loop-invariant branch.
+        * runtime/RegExp.cpp:
+        (JSC::RegExp::match): resize ovector to 0 instead of clearing to avoid
+        thrash in case of large matches.
+        * runtime/RegExpConstructor.h:
+        (JSC::RegExpConstructor::performMatch): Mark ALWAYS_INLINE to make the
+        compiler respect our authority.
+        * runtime/StringPrototype.cpp:
+        (JSC::jsSpliceSubstringsWithSeparators): Inline.
+        (JSC::stringProtoFuncSubstring): Rewrite boundary condition checks to
+        reduce the number of floating point comparisons and branches.
+
 2010-05-12  Gavin Barraclough  <barraclough@apple.com>
 
         Reviewed by Oliver Hunt.
index 2f0053af42851e100b25f0a0d28d9c5f3b9c4f42..99564a8b5adf70a881376fe093ba869fcd82e41b 100644 (file)
@@ -271,20 +271,37 @@ JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thi
     unsigned k = 0;
     if (isJSArray(&exec->globalData(), thisObj)) {
         JSArray* array = asArray(thisObj);
-        for (; k < length; k++) {
-            if (!array->canGetIndex(k))
-                break;
-            if (k >= 1) {
-                if (separator.isNull())
-                    strBuffer.append(',');
-                else
-                    strBuffer.append(separator);
-            }
+
+        if (length) {
+            if (!array->canGetIndex(k)) 
+                goto skipFirstLoop;
             JSValue element = array->getIndex(k);
             if (!element.isUndefinedOrNull())
                 strBuffer.append(element.toString(exec));
+            k++;
+        }
+
+        if (separator.isNull()) {
+            for (; k < length; k++) {
+                if (!array->canGetIndex(k))
+                    break;
+                strBuffer.append(',');
+                JSValue element = array->getIndex(k);
+                if (!element.isUndefinedOrNull())
+                    strBuffer.append(element.toString(exec));
+            }
+        } else {
+            for (; k < length; k++) {
+                if (!array->canGetIndex(k))
+                    break;
+                strBuffer.append(separator);
+                JSValue element = array->getIndex(k);
+                if (!element.isUndefinedOrNull())
+                    strBuffer.append(element.toString(exec));
+            }
         }
     }
+ skipFirstLoop:
     for (; k < length; k++) {
         if (k >= 1) {
             if (separator.isNull())
index f0979432c5ab7e1a5ab02fa40a2abca0394a8163..07809843206ee78754b25a9d910fc0e923c76639 100644 (file)
@@ -107,7 +107,7 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector)
     if (startOffset < 0)
         startOffset = 0;
     if (ovector)
-        ovector->clear();
+        ovector->resize(0);
 
     if (static_cast<unsigned>(startOffset) > s.size() || s.isNull())
         return -1;
@@ -132,7 +132,6 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector)
         for (int j = 0; j < offsetVectorSize; ++j)
             offsetVector[j] = -1;
 
-
 #if ENABLE(YARR_JIT)
         int result = Yarr::executeRegex(m_regExpJITCode, s.data(), startOffset, s.size(), offsetVector, offsetVectorSize);
 #else
index 8f4be71687a0f3177738060bcdbb9bcea02fca65..bb0671aa14620b59dab4ae531837112c99151379 100644 (file)
@@ -109,7 +109,7 @@ namespace JSC {
       expression matching through the performMatch function. We use cached results to calculate, 
       e.g., RegExp.lastMatch and RegExp.leftParen.
     */
-    inline void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
+    ALWAYS_INLINE void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
     {
         position = r->match(s, startOffset, &d->tempOvector());
 
index b1c58ec7141d13bf6bb76a2f1021a39f301d5e36..b385e70dff3ef082b05262bb2cdef2d63b44c958 100644 (file)
@@ -245,8 +245,7 @@ public:
     int length;
 };
 
-JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount);
-JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount)
+static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount)
 {
     if (rangeCount == 1 && separatorCount == 0) {
         int sourceSize = source.size();
@@ -754,21 +753,20 @@ JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec, JSObject*, JSVal
     JSValue a1 = args.at(1);
 
     double start = a0.toNumber(exec);
-    double end = a1.toNumber(exec);
-    if (isnan(start))
+    double end;
+    if (!(start >= 0)) // check for negative values or NaN
         start = 0;
-    if (isnan(end))
-        end = 0;
-    if (start < 0)
-        start = 0;
-    if (end < 0)
-        end = 0;
-    if (start > len)
+    else if (start > len)
         start = len;
-    if (end > len)
-        end = len;
     if (a1.isUndefined())
         end = len;
+    else { 
+        end = a1.toNumber(exec);
+        if (!(end >= 0)) // check for negative values or NaN
+            end = 0;
+        else if (end > len)
+            end = len;
+    }
     if (start > end) {
         double temp = end;
         end = start;