Optimize string plus smi
authorsgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 12 Feb 2010 11:55:04 +0000 (11:55 +0000)
committersgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 12 Feb 2010 11:55:04 +0000 (11:55 +0000)
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

src/ia32/assembler-ia32.h
src/ia32/codegen-ia32.cc
src/v8-counters.h

index f0cf4f1..3d7af82 100644 (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
 };
 
 
index f196459..9d7319c 100644 (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() ?
index 3d5e845..60b52fc 100644 (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 {