Commit 215ba8cf authored by yangguo@chromium.org's avatar yangguo@chromium.org

Combine %_SubString and %_StringCharAt.

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
parent b62de7c0
......@@ -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);
}
......
......@@ -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_;
......
......@@ -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);
}
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
};
}
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment