Revision: 3556
Author: [email protected]
Date: Thu Jan  7 02:25:20 2010
Log: Improve keyed loads on strings by using a new stub.

Instead of going through a runtime function for keyed loads
on strings we invoke a separate specialized stub that
assumes string as receiver type and the key to be a number.

The stub calls a JS builtin function to return the corresponding one-character string.


Review URL: http://codereview.chromium.org/521041
http://code.google.com/p/v8/source/detail?r=3556

Modified:
 /branches/bleeding_edge/src/builtins.cc
 /branches/bleeding_edge/src/builtins.h
 /branches/bleeding_edge/src/ia32/ic-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/ic.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/src/runtime.js

=======================================
--- /branches/bleeding_edge/src/builtins.cc     Mon Nov 23 06:43:00 2009
+++ /branches/bleeding_edge/src/builtins.cc     Thu Jan  7 02:25:20 2010
@@ -542,6 +542,11 @@
 static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
   KeyedLoadIC::GenerateGeneric(masm);
 }
+
+
+static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
+  KeyedLoadIC::GenerateString(masm);
+}


 static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
=======================================
--- /branches/bleeding_edge/src/builtins.h      Tue Oct 20 08:26:17 2009
+++ /branches/bleeding_edge/src/builtins.h      Thu Jan  7 02:25:20 2010
@@ -74,6 +74,7 @@
   V(KeyedLoadIC_Initialize,     KEYED_LOAD_IC, UNINITIALIZED)             \
   V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC)            \
   V(KeyedLoadIC_Generic,        KEYED_LOAD_IC, MEGAMORPHIC)               \
+  V(KeyedLoadIC_String,         KEYED_LOAD_IC, MEGAMORPHIC)               \
   V(KeyedLoadIC_ExternalByteArray,          KEYED_LOAD_IC, MEGAMORPHIC)   \
   V(KeyedLoadIC_ExternalUnsignedByteArray,  KEYED_LOAD_IC, MEGAMORPHIC)   \
   V(KeyedLoadIC_ExternalShortArray,         KEYED_LOAD_IC, MEGAMORPHIC)   \
@@ -147,7 +148,8 @@
   V(STRING_ADD_LEFT, 1)                  \
   V(STRING_ADD_RIGHT, 1)                 \
   V(APPLY_PREPARE, 1)                    \
-  V(APPLY_OVERFLOW, 1)
+  V(APPLY_OVERFLOW, 1)                   \
+  V(STRING_CHAR_AT, 1)


 class ObjectVisitor;
=======================================
--- /branches/bleeding_edge/src/ia32/ic-ia32.cc Thu Dec 17 02:23:20 2009
+++ /branches/bleeding_edge/src/ia32/ic-ia32.cc Thu Jan  7 02:25:20 2010
@@ -389,6 +389,48 @@
   __ shr(eax, String::kHashShift);
   __ jmp(&index_int);
 }
+
+
+void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : key
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  Label miss, index_ok;
+
+  // Pop return address.
+  // Performing the load early is better in the common case.
+  __ pop(eax);
+
+  __ mov(ebx, Operand(esp, 1 * kPointerSize));
+  __ test(ebx, Immediate(kSmiTagMask));
+  __ j(zero, &miss);
+  __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ test(ecx, Immediate(kIsNotStringMask));
+  __ j(not_zero, &miss);
+
+  // Check if key is a smi or a heap number.
+  __ mov(edx, Operand(esp, 0));
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &index_ok);
+  __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
+  __ cmp(ecx, Factory::heap_number_map());
+  __ j(not_equal, &miss);
+
+  __ bind(&index_ok);
+  // Duplicate receiver and key since they are expected on the stack after
+  // the KeyedLoadIC call.
+  __ push(ebx);  // receiver
+  __ push(edx);  // key
+  __ push(eax);  // return address
+  __ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION);
+
+  __ bind(&miss);
+  __ push(eax);
+  GenerateMiss(masm);
+}


 void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
=======================================
--- /branches/bleeding_edge/src/ic.cc   Thu Dec 17 02:23:20 2009
+++ /branches/bleeding_edge/src/ic.cc   Thu Jan  7 02:25:20 2010
@@ -874,7 +874,9 @@

   if (use_ic) {
     Code* stub = generic_stub();
-    if (object->IsJSObject()) {
+    if (object->IsString() && key->IsNumber()) {
+      stub = string_stub();
+    } else if (object->IsJSObject()) {
       Handle<JSObject> receiver = Handle<JSObject>::cast(object);
       if (receiver->HasExternalArrayElements()) {
         stub = external_array_stub(receiver->GetElementsKind());
=======================================
--- /branches/bleeding_edge/src/ic.h    Thu Dec 17 02:23:20 2009
+++ /branches/bleeding_edge/src/ic.h    Thu Jan  7 02:25:20 2010
@@ -280,6 +280,7 @@
   static void GenerateInitialize(MacroAssembler* masm);
   static void GeneratePreMonomorphic(MacroAssembler* masm);
   static void GenerateGeneric(MacroAssembler* masm);
+  static void GenerateString(MacroAssembler* masm);

   // Generators for external array types. See objects.h.
   // These are similar to the generic IC; they optimize the case of
@@ -313,6 +314,9 @@
   static Code* pre_monomorphic_stub() {
     return Builtins::builtin(Builtins::KeyedLoadIC_PreMonomorphic);
   }
+  static Code* string_stub() {
+    return Builtins::builtin(Builtins::KeyedLoadIC_String);
+  }
   static Code* external_array_stub(JSObject::ElementsKind elements_kind);

   static void Clear(Address address, Code* target);
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Thu Jan  7 01:59:37 2010
+++ /branches/bleeding_edge/src/runtime.cc      Thu Jan  7 02:25:20 2010
@@ -1382,6 +1382,17 @@
   }
   return Smi::FromInt(subject->Get(i));
 }
+
+
+static Object* CharFromCode(Object* char_code) {
+  uint32_t code;
+  if (Array::IndexFromObject(char_code, &code)) {
+    if (code <= 0xffff) {
+      return Heap::LookupSingleCharacterStringFromCode(code);
+    }
+  }
+  return Heap::empty_string();
+}


 static Object* Runtime_StringCharCodeAt(Arguments args) {
@@ -1392,18 +1403,19 @@
   Object* index = args[1];
   return CharCodeAt(subject, index);
 }
+
+
+static Object* Runtime_StringCharAt(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+  return CharFromCode(Runtime_StringCharCodeAt(args));
+}


 static Object* Runtime_CharFromCode(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
-  uint32_t code;
-  if (Array::IndexFromObject(args[0], &code)) {
-    if (code <= 0xffff) {
-      return Heap::LookupSingleCharacterStringFromCode(code);
-    }
-  }
-  return Heap::empty_string();
+  return CharFromCode(args[0]);
 }

 // Forward declarations.
=======================================
--- /branches/bleeding_edge/src/runtime.h       Wed Jan  6 06:40:21 2010
+++ /branches/bleeding_edge/src/runtime.h       Thu Jan  7 02:25:20 2010
@@ -146,6 +146,7 @@
   \
   /* Strings */ \
   F(StringCharCodeAt, 2, 1) \
+  F(StringCharAt, 2, 1) \
   F(StringIndexOf, 3, 1) \
   F(StringLastIndexOf, 3, 1) \
   F(StringLocaleCompare, 2, 1) \
=======================================
--- /branches/bleeding_edge/src/runtime.js      Thu Jan  7 01:40:50 2010
+++ /branches/bleeding_edge/src/runtime.js      Thu Jan  7 02:25:20 2010
@@ -475,6 +475,17 @@
 function TO_STRING() {
   return %ToString(this);
 }
+
+
+// Specialized version of String.charAt. It assumes string as
+// the receiver type and that the index is a number.
+function STRING_CHAR_AT(pos) {
+  var char_code = %_FastCharCodeAt(this, pos);
+  if (!%_IsSmi(char_code)) {
+    return %StringCharAt(this, pos);
+  }
+  return %CharFromCode(char_code);
+}


 /* -------------------------------------
-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to