Optimizing BuildResultFromMatchInfo, StringReplace and StringSplit.
authorsandholm@chromium.org <sandholm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 13 Dec 2010 12:19:10 +0000 (12:19 +0000)
committersandholm@chromium.org <sandholm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 13 Dec 2010 12:19:10 +0000 (12:19 +0000)
Review URL: http://codereview.chromium.org/5708006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5982 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/regexp.js
src/string.js

index d01d04f..dd27266 100644 (file)
@@ -120,22 +120,28 @@ function DoRegExpExec(regexp, string, index) {
 
 function BuildResultFromMatchInfo(lastMatchInfo, s) {
   var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
-  var result = %_RegExpConstructResult(numResults, lastMatchInfo[CAPTURE0], s);
-  if (numResults === 1) {
-    var matchStart = lastMatchInfo[CAPTURE(0)];
-    var matchEnd = lastMatchInfo[CAPTURE(1)];
-    result[0] = SubString(s, matchStart, matchEnd);
+  var start = lastMatchInfo[CAPTURE0];
+  var end = lastMatchInfo[CAPTURE1];
+  var result = %_RegExpConstructResult(numResults, start, s);
+  if (start + 1 == end) {
+    result[0] = %_StringCharAt(s, start);
   } else {
-    for (var i = 0; i < numResults; i++) {
-      var matchStart = lastMatchInfo[CAPTURE(i << 1)];
-      var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
-      if (matchStart != -1 && matchEnd != -1) {
-        result[i] = SubString(s, matchStart, matchEnd);
+    result[0] = %_SubString(s, start, end);
+  }
+  var j = REGEXP_FIRST_CAPTURE + 2;
+  for (var i = 1; i < numResults; i++) {
+    start = lastMatchInfo[j++];
+    end = lastMatchInfo[j++];
+    if (end != -1) {
+      if (start + 1 == end) {
+        result[i] = %_StringCharAt(s, start);
       } else {
-        // Make sure the element is present. Avoid reading the undefined
-        // property from the global object since this may change.
-        result[i] = void 0;
+        result[i] = %_SubString(s, start, end);
       }
+    } else {
+      // Make sure the element is present. Avoid reading the undefined
+      // property from the global object since this may change.
+      result[i] = void 0;
     }
   }
   return result;
@@ -166,12 +172,7 @@ function RegExpExec(string) {
     }
     string = regExpInput;
   }
-  var s;
-  if (IS_STRING(string)) {
-    s = string;
-  } else {
-    s = ToString(string);
-  }
+  string = TO_STRING_INLINE(string);
   var lastIndex = this.lastIndex;
 
   // Conversion is required by the ES5 specification (RegExp.prototype.exec
@@ -180,7 +181,7 @@ function RegExpExec(string) {
 
   var global = this.global;
   if (global) {
-    if (i < 0 || i > s.length) {
+    if (i < 0 || i > string.length) {
       this.lastIndex = 0;
       return null;
     }
@@ -188,9 +189,9 @@ function RegExpExec(string) {
     i = 0;
   }
 
-  %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
+  %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
   // matchIndices is either null or the lastMatchInfo array.
-  var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
+  var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
 
   if (matchIndices === null) {
     if (global) this.lastIndex = 0;
@@ -202,7 +203,7 @@ function RegExpExec(string) {
   if (global) {
     this.lastIndex = lastMatchInfo[CAPTURE1];
   }
-  return BuildResultFromMatchInfo(matchIndices, s);
+  return BuildResultFromMatchInfo(matchIndices, string);
 }
 
 
@@ -227,12 +228,7 @@ function RegExpTest(string) {
     string = regExpInput;
   }
 
-  var s;
-  if (IS_STRING(string)) {
-    s = string;
-  } else {
-    s = ToString(string);
-  }
+  string = TO_STRING_INLINE(string);
 
   var lastIndex = this.lastIndex;
 
@@ -241,13 +237,13 @@ function RegExpTest(string) {
   var i = TO_INTEGER(lastIndex);
   
   if (this.global) {
-    if (i < 0 || i > s.length) {
+    if (i < 0 || i > string.length) {
       this.lastIndex = 0;
       return false;
     }
-    %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
+    %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
     // matchIndices is either null or the lastMatchInfo array.
-    var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
+    var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
     if (matchIndices === null) {
       this.lastIndex = 0;
       return false;
@@ -269,11 +265,11 @@ function RegExpTest(string) {
                                  (this.ignoreCase ? 'i' : '')
                                  + (this.multiline ? 'm' : ''));
       }
-      if (!regexp_val.test(s)) return false;
+      if (!regexp_val.test(string)) return false;
     }    
-    %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
+    %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
     // matchIndices is either null or the lastMatchInfo array.
-    var matchIndices = %_RegExpExec(this, s, 0, lastMatchInfo);
+    var matchIndices = %_RegExpExec(this, string, 0, lastMatchInfo);
     if (matchIndices === null) return false;
     lastMatchInfoOverride = null;
     return true;
index 3b3c82b..576ffc8 100644 (file)
@@ -101,28 +101,28 @@ function StringConcat() {
 
 
 // ECMA-262 section 15.5.4.7
-function StringIndexOf(searchString /* position */) {  // length == 1
-  var subject_str = TO_STRING_INLINE(this);
-  var pattern_str = TO_STRING_INLINE(searchString);
-  var subject_str_len = subject_str.length;
-  var pattern_str_len = pattern_str.length;
+function StringIndexOf(pattern /* position */) {  // length == 1
+  var subject = TO_STRING_INLINE(this);
+  var pattern = TO_STRING_INLINE(pattern);
+  var subject_len = subject.length;
+  var pattern_len = pattern.length;
   var index = 0;
   if (%_ArgumentsLength() > 1) {
     var arg1 = %_Arguments(1);  // position
     index = TO_INTEGER(arg1);
   }
   if (index < 0) index = 0;
-  if (index > subject_str_len) index = subject_str_len;
-  if (pattern_str_len + index > subject_str_len) return -1;
-  return %StringIndexOf(subject_str, pattern_str, index);
+  if (index > subject_len) index = subject_len;
+  if (pattern_len + index > subject_len) return -1;
+  return %StringIndexOf(subject, pattern, index);
 }
 
 
 // ECMA-262 section 15.5.4.8
-function StringLastIndexOf(searchString /* position */) {  // length == 1
+function StringLastIndexOf(pat /* position */) {  // length == 1
   var sub = TO_STRING_INLINE(this);
   var subLength = sub.length;
-  var pat = TO_STRING_INLINE(searchString);
+  var pat = TO_STRING_INLINE(pat);
   var patLength = pat.length;
   var index = subLength - patLength;
   if (%_ArgumentsLength() > 1) {
@@ -150,10 +150,8 @@ function StringLastIndexOf(searchString /* position */) {  // length == 1
 // do anything locale specific.
 function StringLocaleCompare(other) {
   if (%_ArgumentsLength() === 0) return 0;
-
-  var this_str = TO_STRING_INLINE(this);
-  var other_str = TO_STRING_INLINE(other);
-  return %StringLocaleCompare(this_str, other_str);
+  return %StringLocaleCompare(TO_STRING_INLINE(this), 
+                              TO_STRING_INLINE(other));
 }
 
 
@@ -177,9 +175,7 @@ function StringMatch(regexp) {
 // otherwise we call the runtime system.
 function SubString(string, start, end) {
   // Use the one character string cache.
-  if (start + 1 == end) {
-    return %_StringCharAt(string, start);
-  }
+  if (start + 1 == end) return %_StringCharAt(string, start);
   return %_SubString(string, start, end);
 }
 
@@ -208,7 +204,10 @@ function StringReplace(search, replace) {
                                                         replace);
       }
     } else {
-      return StringReplaceRegExp(subject, search, replace);
+      return %StringReplaceRegExpWithString(subject,
+                                            search,
+                                            TO_STRING_INLINE(replace),
+                                            lastMatchInfo);
     }
   }
 
@@ -224,7 +223,11 @@ function StringReplace(search, replace) {
 
   // Compute the string to replace with.
   if (IS_FUNCTION(replace)) {
-    builder.add(replace.call(null, search, start, subject));
+    builder.add(%_CallFunction(%GetGlobalReceiver(),
+                               search,
+                               start,
+                               subject,
+                               replace));
   } else {
     reusableMatchInfo[CAPTURE0] = start;
     reusableMatchInfo[CAPTURE1] = end;
@@ -239,15 +242,6 @@ function StringReplace(search, replace) {
 }
 
 
-// Helper function for regular expressions in String.prototype.replace.
-function StringReplaceRegExp(subject, regexp, replace) {
-  return %StringReplaceRegExpWithString(subject,
-                                        regexp,
-                                        TO_STRING_INLINE(replace),
-                                        lastMatchInfo);
-}
-
-
 // Expand the $-expressions in the string and return a new string with
 // the result.
 function ExpandReplacement(string, subject, matchInfo, builder) {
@@ -408,9 +402,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
         lastMatchInfoOverride = override;
         var func_result =
             %_CallFunction(receiver, elem, match_start, subject, replace);
-        if (!IS_STRING(func_result)) {
-          func_result = NonStringToString(func_result);
-        }
+        func_result = TO_STRING_INLINE(func_result); 
         res[i] = func_result;
         match_start += elem.length;
       }
@@ -424,9 +416,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
         // Use the apply argument as backing for global RegExp properties.
         lastMatchInfoOverride = elem;
         var func_result = replace.apply(null, elem);
-        if (!IS_STRING(func_result)) {
-          func_result = NonStringToString(func_result);
-        }
+        func_result = TO_STRING_INLINE(func_result); 
         res[i] = func_result;
       }
       i++;
@@ -487,8 +477,7 @@ function StringSearch(re) {
   } else {
     regexp = new $RegExp(re);
   }
-  var s = TO_STRING_INLINE(this);
-  var match = DoRegExpExec(regexp, s, 0);
+  var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
   if (match) {
     return match[CAPTURE0];
   }
@@ -576,14 +565,14 @@ function StringSplit(separator, limit) {
   while (true) {
 
     if (startIndex === length) {
-      result[result.length] = subject.slice(currentIndex, length);
+      result.push(subject.slice(currentIndex, length));
       break;
     }
 
     var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
 
     if (IS_NULL(matchInfo)) {
-      result[result.length] = subject.slice(currentIndex, length);
+      result.push(subject.slice(currentIndex, length));
       break;
     }
 
@@ -595,17 +584,21 @@ function StringSplit(separator, limit) {
       continue;
     }
 
-    result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]);
+    result.push(SubString(subject, currentIndex, matchInfo[CAPTURE0]));
     if (result.length === limit) break;
 
-    var num_captures = NUMBER_OF_CAPTURES(matchInfo);
-    for (var i = 2; i < num_captures; i += 2) {
-      var start = matchInfo[CAPTURE(i)];
-      var end = matchInfo[CAPTURE(i + 1)];
-      if (start != -1 && end != -1) {
-        result[result.length] = SubString(subject, start, end);
+    var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
+    for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
+      var start = matchInfo[i++];
+      var end = matchInfo[i++];
+      if (end != -1) {
+        if (start + 1 == end) {
+          result.push(%_StringCharAt(subject, start));
+        } else {
+          result.push(%_SubString(subject, start, end));
+        }
       } else {
-        result[result.length] = void 0;
+        result.push(void 0);
       }
       if (result.length === limit) break outer_loop;
     }
@@ -656,7 +649,9 @@ function StringSubstring(start, end) {
     }
   }
 
-  return SubString(s, start_i, end_i);
+  return (start_i + 1 == end_i
+          ? %_StringCharAt(s, start_i)
+          : %_SubString(s, start_i, end_i));
 }
 
 
@@ -694,7 +689,9 @@ function StringSubstr(start, n) {
   var end = start + len;
   if (end > s.length) end = s.length;
 
-  return SubString(s, start, end);
+  return (start + 1 == end
+          ? %_StringCharAt(s, start)
+          : %_SubString(s, start, end));
 }