}
-// -------------------------------------------------------------------------
-// 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,
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
__ 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);
}
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_;
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_;
// 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_;
}
-// -------------------------------------------------------------------------
-// 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;
__ ret(3 * kPointerSize);
__ bind(¬_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)
// 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);
}
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;
}
%_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;
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++;
}
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" : ""));
}
return OVERRIDE_MATCH(lastMatchInfoOverride);
}
var regExpSubject = LAST_SUBJECT(lastMatchInfo);
- return SubString(regExpSubject,
- lastMatchInfo[CAPTURE0],
- lastMatchInfo[CAPTURE1]);
+ return %_SubString(regExpSubject,
+ lastMatchInfo[CAPTURE0],
+ lastMatchInfo[CAPTURE1]);
}
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 "";
}
start_index = OVERRIDE_POS(override);
subject = OVERRIDE_SUBJECT(override);
}
- return SubString(subject, 0, start_index);
+ return %_SubString(subject, 0, start_index);
}
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);
}
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);
};
}
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);
}
}
-// 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
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)) {
result = ExpandReplacement(replace, subject, reusableMatchInfo, result);
}
- return result + SubString(subject, end, subject.length);
+ return result + %_SubString(subject, end, subject.length);
}
return result;
}
- if (next > 0) result += SubString(string, 0, next);
+ if (next > 0) result += %_SubString(string, 0, next);
while (true) {
var expansion = '$';
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 += '$';
}
// 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;
// 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);
}
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.
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 {
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);
}
return '';
}
- return SubString(s, start_i, end_i);
+ return %_SubString(s, start_i, end_i);
}
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];
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;
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);
}
}
}
- return ((start_i + 1 == end_i)
- ? %_StringCharAt(s, start_i)
- : %_SubString(s, start_i, end_i));
+ return %_SubString(s, start_i, end_i);
}
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);
}
}
-// -------------------------------------------------------------------------
-// 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;
__ IncrementCounter(counters->sub_string_native(), 1);
__ ret(kArgumentsSize);
__ bind(¬_original_string);
+
+ Label single_char;
+ __ SmiCompare(rcx, Smi::FromInt(1));
+ __ j(equal, &single_char);
+
__ SmiToInteger32(rcx, rcx);
// rax: string
// 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);
}