Combine %_SubString and %_StringCharAt.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Feb 2013 14:29:40 +0000 (14:29 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Feb 2013 14:29:40 +0000 (14:29 +0000)
R=ulan@chromium.org
BUG=

Review URL: https://chromiumcodereview.appspot.com/12217071

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

src/arm/code-stubs-arm.cc
src/code-stubs.h
src/ia32/code-stubs-ia32.cc
src/json.js
src/messages.js
src/regexp.js
src/runtime.cc
src/string.js
src/x64/code-stubs-x64.cc

index 62fcc9a981ccd5946ed7946d006d7e6d5224d4d1..b1f3c08b9bfb7595372a948363336be215264109 100644 (file)
@@ -5882,23 +5882,6 @@ void StringCharFromCodeGenerator::GenerateSlow(
 }
 
 
-// -------------------------------------------------------------------------
-// StringCharAtGenerator
-
-void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
-  char_code_at_generator_.GenerateFast(masm);
-  char_from_code_generator_.GenerateFast(masm);
-}
-
-
-void StringCharAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
-    const RuntimeCallHelper& call_helper) {
-  char_code_at_generator_.GenerateSlow(masm, call_helper);
-  char_from_code_generator_.GenerateSlow(masm, call_helper);
-}
-
-
 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
                                           Register dest,
                                           Register src,
@@ -6306,6 +6289,10 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   ASSERT(is_string == eq);
   __ b(NegateCondition(is_string), &runtime);
 
+  Label single_char;
+  __ cmp(r2, Operand(1));
+  __ b(eq, &single_char);
+
   // Short-cut for the case of trivial substring.
   Label return_r0;
   // r0: original string
@@ -6459,12 +6446,25 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   __ bind(&return_r0);
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
-  __ add(sp, sp, Operand(3 * kPointerSize));
+  __ Drop(3);
   __ Ret();
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
   __ TailCallRuntime(Runtime::kSubString, 3, 1);
+
+  __ bind(&single_char);
+  // r0: original string
+  // r1: instance type
+  // r2: length
+  // r3: from index (untagged)
+  __ SmiTag(r3, r3);
+  StringCharAtGenerator generator(
+      r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm);
+  __ Drop(3);
+  __ Ret();
+  generator.SkipSlow(masm, &runtime);
 }
 
 
index 5eea0a4fe0e4eed8695246e018d2b7c052856cf2..c06502aa2294ba9e8549d50905e501ce4625373a 100644 (file)
@@ -1060,6 +1060,13 @@ class StringCharCodeAtGenerator {
   void GenerateSlow(MacroAssembler* masm,
                     const RuntimeCallHelper& call_helper);
 
+  // Skip handling slow case and directly jump to bailout.
+  void SkipSlow(MacroAssembler* masm, Label* bailout) {
+    masm->bind(&index_not_smi_);
+    masm->bind(&call_runtime_);
+    masm->jmp(bailout);
+  }
+
  private:
   Register object_;
   Register index_;
@@ -1100,6 +1107,12 @@ class StringCharFromCodeGenerator {
   void GenerateSlow(MacroAssembler* masm,
                     const RuntimeCallHelper& call_helper);
 
+  // Skip handling slow case and directly jump to bailout.
+  void SkipSlow(MacroAssembler* masm, Label* bailout) {
+    masm->bind(&slow_case_);
+    masm->jmp(bailout);
+  }
+
  private:
   Register code_;
   Register result_;
@@ -1142,13 +1155,25 @@ class StringCharAtGenerator {
 
   // Generates the fast case code. On the fallthrough path |result|
   // register contains the result.
-  void GenerateFast(MacroAssembler* masm);
+  void GenerateFast(MacroAssembler* masm) {
+    char_code_at_generator_.GenerateFast(masm);
+    char_from_code_generator_.GenerateFast(masm);
+  }
 
   // Generates the slow case code. Must not be naturally
   // reachable. Expected to be put after a ret instruction (e.g., in
   // deferred code). Always jumps back to the fast case.
   void GenerateSlow(MacroAssembler* masm,
-                    const RuntimeCallHelper& call_helper);
+                    const RuntimeCallHelper& call_helper) {
+    char_code_at_generator_.GenerateSlow(masm, call_helper);
+    char_from_code_generator_.GenerateSlow(masm, call_helper);
+  }
+
+  // Skip handling slow case and directly jump to bailout.
+  void SkipSlow(MacroAssembler* masm, Label* bailout) {
+    char_code_at_generator_.SkipSlow(masm, bailout);
+    char_from_code_generator_.SkipSlow(masm, bailout);
+  }
 
  private:
   StringCharCodeAtGenerator char_code_at_generator_;
index d9a46cb9e59538010cce406d8b873a2329749023..e7e4d4fe58f201f4b5c66f48638dad7431b1dad4 100644 (file)
@@ -5692,23 +5692,6 @@ void StringCharFromCodeGenerator::GenerateSlow(
 }
 
 
-// -------------------------------------------------------------------------
-// StringCharAtGenerator
-
-void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
-  char_code_at_generator_.GenerateFast(masm);
-  char_from_code_generator_.GenerateFast(masm);
-}
-
-
-void StringCharAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
-    const RuntimeCallHelper& call_helper) {
-  char_code_at_generator_.GenerateSlow(masm, call_helper);
-  char_from_code_generator_.GenerateSlow(masm, call_helper);
-}
-
-
 void StringAddStub::Generate(MacroAssembler* masm) {
   Label call_runtime, call_builtin;
   Builtins::JavaScript builtin_id = Builtins::ADD;
@@ -6375,6 +6358,10 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   __ ret(3 * kPointerSize);
   __ bind(&not_original_string);
 
+  Label single_char;
+  __ cmp(ecx, Immediate(Smi::FromInt(1)));
+  __ j(equal, &single_char);
+
   // eax: string
   // ebx: instance type
   // ecx: sub string length (smi)
@@ -6545,6 +6532,17 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
   __ TailCallRuntime(Runtime::kSubString, 3, 1);
+
+  __ bind(&single_char);
+  // eax: string
+  // ebx: instance type
+  // ecx: sub string length (smi)
+  // edx: from index (smi)
+  StringCharAtGenerator generator(
+      eax, edx, ecx, eax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm);
+  __ ret(3 * kPointerSize);
+  generator.SkipSlow(masm, &runtime);
 }
 
 
index 9ab1a31e59c1b0b25226160402b7ef9bfd804454..e94d3c8e3e907f081891f2517b91de7de13b3f89 100644 (file)
@@ -193,10 +193,10 @@ function JSONStringify(value, replacer, space) {
   var gap;
   if (IS_NUMBER(space)) {
     space = MathMax(0, MathMin(ToInteger(space), 10));
-    gap = SubString("          ", 0, space);
+    gap = %_SubString("          ", 0, space);
   } else if (IS_STRING(space)) {
     if (space.length > 10) {
-      gap = SubString(space, 0, 10);
+      gap = %_SubString(space, 0, 10);
     } else {
       gap = space;
     }
index 4a8143e611162a447436ecb64aefb670e10c14fb..e274f50ea6af0ac9c560ea082b5f827af9b5ed3f 100644 (file)
@@ -562,7 +562,7 @@ function ScriptNameOrSourceURL() {
         %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
     if (match) {
       this.cachedNameOrSourceURL =
-          SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
+          %_SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
     }
   }
   return this.cachedNameOrSourceURL;
index a8390b0c312b1c652fcd242ba72088f3e4ea9b9f..2349ca7fbc92a9973484bc9645420e645ad98d31 100644 (file)
@@ -132,21 +132,13 @@ function BuildResultFromMatchInfo(lastMatchInfo, s) {
   var start = lastMatchInfo[CAPTURE0];
   var end = lastMatchInfo[CAPTURE1];
   var result = %_RegExpConstructResult(numResults, start, s);
-  if (start + 1 == end) {
-    result[0] = %_StringCharAt(s, start);
-  } else {
-    result[0] = %_SubString(s, start, end);
-  }
+  result[0] = %_SubString(s, start, end);
   var j = REGEXP_FIRST_CAPTURE + 2;
   for (var i = 1; i < numResults; i++) {
     start = lastMatchInfo[j++];
     if (start != -1) {
       end = lastMatchInfo[j];
-      if (start + 1 == end) {
-        result[i] = %_StringCharAt(s, start);
-      } else {
-        result[i] = %_SubString(s, start, end);
-      }
+      result[i] = %_SubString(s, start, end);
     }
     j++;
   }
@@ -270,7 +262,7 @@ function TrimRegExp(regexp) {
   if (!%_ObjectEquals(regexp_key, regexp)) {
     regexp_key = regexp;
     regexp_val =
-      new $RegExp(SubString(regexp.source, 2, regexp.source.length),
+      new $RegExp(%_SubString(regexp.source, 2, regexp.source.length),
                   (regexp.ignoreCase ? regexp.multiline ? "im" : "i"
                                      : regexp.multiline ? "m" : ""));
   }
@@ -300,9 +292,9 @@ function RegExpGetLastMatch() {
     return OVERRIDE_MATCH(lastMatchInfoOverride);
   }
   var regExpSubject = LAST_SUBJECT(lastMatchInfo);
-  return SubString(regExpSubject,
-                   lastMatchInfo[CAPTURE0],
-                   lastMatchInfo[CAPTURE1]);
+  return %_SubString(regExpSubject,
+                     lastMatchInfo[CAPTURE0],
+                     lastMatchInfo[CAPTURE1]);
 }
 
 
@@ -321,7 +313,7 @@ function RegExpGetLastParen() {
   var start = lastMatchInfo[CAPTURE(length - 2)];
   var end = lastMatchInfo[CAPTURE(length - 1)];
   if (start != -1 && end != -1) {
-    return SubString(regExpSubject, start, end);
+    return %_SubString(regExpSubject, start, end);
   }
   return "";
 }
@@ -338,7 +330,7 @@ function RegExpGetLeftContext() {
     start_index = OVERRIDE_POS(override);
     subject = OVERRIDE_SUBJECT(override);
   }
-  return SubString(subject, 0, start_index);
+  return %_SubString(subject, 0, start_index);
 }
 
 
@@ -354,7 +346,7 @@ function RegExpGetRightContext() {
     var match = OVERRIDE_MATCH(override);
     start_index = OVERRIDE_POS(override) + match.length;
   }
-  return SubString(subject, start_index, subject.length);
+  return %_SubString(subject, start_index, subject.length);
 }
 
 
@@ -374,7 +366,7 @@ function RegExpMakeCaptureGetter(n) {
     var matchStart = lastMatchInfo[CAPTURE(index)];
     var matchEnd = lastMatchInfo[CAPTURE(index + 1)];
     if (matchStart == -1 || matchEnd == -1) return '';
-    return SubString(LAST_SUBJECT(lastMatchInfo), matchStart, matchEnd);
+    return %_SubString(LAST_SUBJECT(lastMatchInfo), matchStart, matchEnd);
   };
 }
 
index 7b13f05f89d251729e5b2e8f18695cb4fc0624ff..d804979d2e3927e1affde0146643f534e96fdf07 100644 (file)
@@ -3547,6 +3547,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
   RUNTIME_ASSERT(start >= 0);
   RUNTIME_ASSERT(end <= value->length());
   isolate->counters()->sub_string_runtime()->Increment();
+  if (end - start == 1) {
+     return isolate->heap()->LookupSingleCharacterStringFromCode(
+         value->Get(start));
+  }
   return value->SubString(start, end);
 }
 
index 975f8f65647d1c9b76a0cccadcd14182204796e4..0349837ccb2d855edcfd389186c96f76b14d2743 100644 (file)
@@ -203,16 +203,6 @@ function StringMatch(regexp) {
 }
 
 
-// SubString is an internal function that returns the sub string of 'string'.
-// If resulting string is of length 1, we use the one character cache
-// 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);
-  return %_SubString(string, start, end);
-}
-
-
 // This has the same size as the lastMatchInfo array, and can be used for
 // functions that expect that structure to be returned.  It is used when the
 // needle is a string rather than a regexp.  In this case we can't update
@@ -296,7 +286,7 @@ function StringReplace(search, replace) {
   if (start < 0) return subject;
   var end = start + search.length;
 
-  var result = SubString(subject, 0, start);
+  var result = %_SubString(subject, 0, start);
 
   // Compute the string to replace with.
   if (IS_SPEC_FUNCTION(replace)) {
@@ -309,7 +299,7 @@ function StringReplace(search, replace) {
     result = ExpandReplacement(replace, subject, reusableMatchInfo, result);
   }
 
-  return result + SubString(subject, end, subject.length);
+  return result + %_SubString(subject, end, subject.length);
 }
 
 
@@ -323,7 +313,7 @@ function ExpandReplacement(string, subject, matchInfo, result) {
     return result;
   }
 
-  if (next > 0) result += SubString(string, 0, next);
+  if (next > 0) result += %_SubString(string, 0, next);
 
   while (true) {
     var expansion = '$';
@@ -335,13 +325,14 @@ function ExpandReplacement(string, subject, matchInfo, result) {
         result += '$';
       } else if (peek == 38) {  // $& - match
         ++position;
-        result += SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]);
+        result +=
+          %_SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]);
       } else if (peek == 96) {  // $` - prefix
         ++position;
-        result += SubString(subject, 0, matchInfo[CAPTURE0]);
+        result += %_SubString(subject, 0, matchInfo[CAPTURE0]);
       } else if (peek == 39) {  // $' - suffix
         ++position;
-        result += SubString(subject, matchInfo[CAPTURE1], subject.length);
+        result += %_SubString(subject, matchInfo[CAPTURE1], subject.length);
       } else {
         result += '$';
       }
@@ -356,14 +347,14 @@ function ExpandReplacement(string, subject, matchInfo, result) {
     // haven't reached the end, we need to append the suffix.
     if (next < 0) {
       if (position < length) {
-        result += SubString(string, position, length);
+        result += %_SubString(string, position, length);
       }
       return result;
     }
 
     // Append substring between the previous and the next $ character.
     if (next > position) {
-      result += SubString(string, position, next);
+      result += %_SubString(string, position, next);
     }
   }
   return result;
@@ -379,7 +370,7 @@ function CaptureString(string, lastCaptureInfo, index) {
   // If start isn't valid, return undefined.
   if (start < 0) return;
   var end = lastCaptureInfo[CAPTURE(scaled + 1)];
-  return SubString(string, start, end);
+  return %_SubString(string, start, end);
 }
 
 
@@ -475,7 +466,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
     return subject;
   }
   var index = matchInfo[CAPTURE0];
-  var result = SubString(subject, 0, index);
+  var result = %_SubString(subject, 0, index);
   var endOfMatch = matchInfo[CAPTURE1];
   // Compute the parameter list consisting of the match, captures, index,
   // and subject for the replace function invocation.
@@ -485,7 +476,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
   var receiver = %GetDefaultReceiver(replace);
   if (m == 1) {
     // No captures, only the match, which is always valid.
-    var s = SubString(subject, index, endOfMatch);
+    var s = %_SubString(subject, index, endOfMatch);
     // Don't call directly to avoid exposing the built-in global object.
     replacement = %_CallFunction(receiver, s, index, subject, replace);
   } else {
@@ -502,7 +493,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
   result += replacement;  // The add method converts to string if necessary.
   // Can't use matchInfo any more from here, since the function could
   // overwrite it.
-  return result + SubString(subject, endOfMatch, subject.length);
+  return result + %_SubString(subject, endOfMatch, subject.length);
 }
 
 
@@ -568,7 +559,7 @@ function StringSlice(start, end) {
     return '';
   }
 
-  return SubString(s, start_i, end_i);
+  return %_SubString(s, start_i, end_i);
 }
 
 
@@ -629,13 +620,13 @@ function StringSplitOnRegExp(subject, separator, limit, length) {
   while (true) {
 
     if (startIndex === length) {
-      result.push(SubString(subject, currentIndex, length));
+      result.push(%_SubString(subject, currentIndex, length));
       break;
     }
 
     var matchInfo = DoRegExpExec(separator, subject, startIndex);
     if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
-      result.push(SubString(subject, currentIndex, length));
+      result.push(%_SubString(subject, currentIndex, length));
       break;
     }
     var endIndex = matchInfo[CAPTURE1];
@@ -646,11 +637,7 @@ function StringSplitOnRegExp(subject, separator, limit, length) {
       continue;
     }
 
-    if (currentIndex + 1 == startMatch) {
-      result.push(%_StringCharAt(subject, currentIndex));
-    } else {
-      result.push(%_SubString(subject, currentIndex, startMatch));
-    }
+    result.push(%_SubString(subject, currentIndex, startMatch));
 
     if (result.length === limit) break;
 
@@ -659,11 +646,7 @@ function StringSplitOnRegExp(subject, separator, limit, length) {
       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));
-        }
+        result.push(%_SubString(subject, start, end));
       } else {
         result.push(void 0);
       }
@@ -707,9 +690,7 @@ function StringSubstring(start, end) {
     }
   }
 
-  return ((start_i + 1 == end_i)
-          ? %_StringCharAt(s, start_i)
-          : %_SubString(s, start_i, end_i));
+  return %_SubString(s, start_i, end_i);
 }
 
 
@@ -751,9 +732,7 @@ function StringSubstr(start, n) {
   var end = start + len;
   if (end > s.length) end = s.length;
 
-  return ((start + 1 == end)
-          ? %_StringCharAt(s, start)
-          : %_SubString(s, start, end));
+  return %_SubString(s, start, end);
 }
 
 
index 5b7fc81a8dec7c5bbf034e76f737480f45f441e0..21fa4f840bc29c4934c3cec55b2b4f986d408cca 100644 (file)
@@ -4757,23 +4757,6 @@ void StringCharFromCodeGenerator::GenerateSlow(
 }
 
 
-// -------------------------------------------------------------------------
-// StringCharAtGenerator
-
-void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
-  char_code_at_generator_.GenerateFast(masm);
-  char_from_code_generator_.GenerateFast(masm);
-}
-
-
-void StringCharAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
-    const RuntimeCallHelper& call_helper) {
-  char_code_at_generator_.GenerateSlow(masm, call_helper);
-  char_from_code_generator_.GenerateSlow(masm, call_helper);
-}
-
-
 void StringAddStub::Generate(MacroAssembler* masm) {
   Label call_runtime, call_builtin;
   Builtins::JavaScript builtin_id = Builtins::ADD;
@@ -5394,6 +5377,11 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   __ IncrementCounter(counters->sub_string_native(), 1);
   __ ret(kArgumentsSize);
   __ bind(&not_original_string);
+
+  Label single_char;
+  __ SmiCompare(rcx, Smi::FromInt(1));
+  __ j(equal, &single_char);
+
   __ SmiToInteger32(rcx, rcx);
 
   // rax: string
@@ -5554,6 +5542,17 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
   __ TailCallRuntime(Runtime::kSubString, 3, 1);
+
+  __ bind(&single_char);
+  // rax: string
+  // rbx: instance type
+  // rcx: sub string length (smi)
+  // rdx: from index (smi)
+  StringCharAtGenerator generator(
+      rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm);
+  __ ret(kArgumentsSize);
+  generator.SkipSlow(masm, &runtime);
 }