Optimize string plus smi

When adding a string with a smi value the number string cache is checked in generated code. If the there is a string value in the number string cache the resulting string is produced in generated code.
Review URL: http://codereview.chromium.org/596082

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3843 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
sgjesse@chromium.org 2010-02-12 11:55:04 +00:00
parent 46020b3169
commit e60efbff28
3 changed files with 51 additions and 7 deletions

View File

@ -231,7 +231,8 @@ enum ScaleFactor {
times_8 = 3,
times_int_size = times_4,
times_half_pointer_size = times_2,
times_pointer_size = times_4
times_pointer_size = times_4,
times_twice_pointer_size = times_8
};

View File

@ -7639,7 +7639,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
switch (op_) {
case Token::ADD: {
// Test for string arguments before calling runtime.
Label not_strings, not_string1, string1;
Label not_strings, not_string1, string1, string1_smi2;
Result answer;
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &not_string1);
@ -7648,15 +7648,56 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
// First argument is a string, test second.
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &string1);
__ j(zero, &string1_smi2);
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
__ j(above_equal, &string1);
// First and second argument are strings. Jump to the string add stub.
StringAddStub stub(NO_STRING_CHECK_IN_STUB);
__ TailCallStub(&stub);
StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
__ TailCallStub(&string_add_stub);
__ bind(&string1_smi2);
// First argument is a string, second is a smi. Try to lookup the number
// string for the smi in the number string cache.
// Load the number string cache.
ExternalReference roots_address = ExternalReference::roots_address();
__ mov(ecx, Immediate(Heap::kNumberStringCacheRootIndex));
__ mov(ebx,
Operand::StaticArray(ecx, times_pointer_size, roots_address));
// Make the hash mask from the length of the number string cache. It
// contains two elements (number and string) for each cache entry.
__ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
__ shr(ecx, 1); // Divide length by two (length is not a smi).
__ sub(Operand(ecx), Immediate(1)); // Make mask.
// Calculate the entry in the number string cache. The hash value in the
// number string cache for smis is just the smi value.
__ mov(edi, eax);
__ SmiUntag(edi);
__ and_(edi, Operand(ecx));
// Check if the entry is the smi we are looking for.
__ cmp(eax,
FieldOperand(ebx,
edi,
times_twice_pointer_size,
FixedArray::kHeaderSize));
__ IncrementCounter(equal, &Counters::string_plus_smi_hit, 1);
__ IncrementCounter(not_equal, &Counters::string_plus_smi_miss, 1);
__ j(not_equal, &string1);
// Get the string from the cache and call the string add stub to make the
// result.
__ mov(edi,
FieldOperand(ebx,
edi,
times_twice_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ EnterInternalFrame();
__ push(edx); // Original first argument.
__ push(edi); // Number to string result for second argument.
__ CallStub(&string_add_stub);
__ LeaveInternalFrame();
__ ret(2 * kPointerSize);
// Only first argument is a string.
__ bind(&string1);
__ InvokeBuiltin(
HasArgsReversed() ?

View File

@ -167,7 +167,9 @@ namespace internal {
SC(string_compare_native, V8.StringCompareNative) \
SC(string_compare_runtime, V8.StringCompareRuntime) \
SC(regexp_entry_runtime, V8.RegExpEntryRuntime) \
SC(regexp_entry_native, V8.RegExpEntryNative)
SC(regexp_entry_native, V8.RegExpEntryNative) \
SC(string_plus_smi_hit, V8.StringPlusSmiHit) \
SC(string_plus_smi_miss, V8.StringPlusSmiMiss)
// This file contains all the v8 counters that are in use.
class Counters : AllStatic {