Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 3836) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -7632,7 +7632,7 @@ |
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, ¬_string1); |
@@ -7641,15 +7641,56 @@ |
// 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); |
- // Only first argument is a string. |
+ __ 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); |
+ |
__ bind(&string1); |
__ InvokeBuiltin( |
HasArgsReversed() ? |