Eliminate special keyed load string stub in favor of uniform handlers.
authormvstanton@chromium.org <mvstanton@chromium.org>
Thu, 16 Oct 2014 11:42:47 +0000 (11:42 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org>
Thu, 16 Oct 2014 11:42:47 +0000 (11:42 +0000)
KeyedLoadIC installs a special case if the receiver is a string.
Although there are several maps for strings, in practice we seem to
be able to treat them individually because a given KeyedLoad site
only sees 1-2 string types.

R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/602773003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24661 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

19 files changed:
src/arm/code-stubs-arm.cc
src/arm64/code-stubs-arm64.cc
src/builtins.cc
src/builtins.h
src/code-stubs.h
src/ia32/code-stubs-ia32.cc
src/ic/arm/ic-arm.cc
src/ic/arm64/ic-arm64.cc
src/ic/handler-compiler.cc
src/ic/ia32/ic-ia32.cc
src/ic/ic-compiler.cc
src/ic/ic.cc
src/ic/ic.h
src/ic/mips/ic-mips.cc
src/ic/x64/ic-x64.cc
src/mips/code-stubs-mips.cc
src/objects.h
src/type-info.cc
src/x64/code-stubs-x64.cc

index efcc1ae..7fe100d 100644 (file)
@@ -1503,6 +1503,34 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in lr.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = r3;
+  Register result = r0;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The displacement is the offset of the last parameter (if any)
   // relative to the frame pointer.
index 374eff3..f3fb6ac 100644 (file)
@@ -1422,6 +1422,34 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in lr.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register result = x0;
+  Register scratch = x3;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ Bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void InstanceofStub::Generate(MacroAssembler* masm) {
   // Stack on entry:
   // jssp[0]: function.
index 4d2fa0a..8b385aa 100644 (file)
@@ -1279,11 +1279,6 @@ static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
 }
 
 
-static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
-  KeyedLoadIC::GenerateString(masm);
-}
-
-
 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
   KeyedLoadIC::GeneratePreMonomorphic(masm);
 }
index da1ae10..13a4b80 100644 (file)
@@ -88,7 +88,6 @@ enum BuiltinExtraArguments {
   V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC,                 \
     kNoExtraICState)                                                           \
   V(KeyedLoadIC_Generic, KEYED_LOAD_IC, GENERIC, kNoExtraICState)              \
-  V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, kNoExtraICState)           \
                                                                                \
   V(StoreIC_Setter_ForDeopt, STORE_IC, MONOMORPHIC, StoreIC::kStrictModeState) \
                                                                                \
index 9f6e9de..7fa9d61 100644 (file)
@@ -39,6 +39,7 @@ namespace internal {
   V(KeyedLoadICTrampoline)                  \
   V(LoadICTrampoline)                       \
   V(LoadIndexedInterceptor)                 \
+  V(LoadIndexedString)                      \
   V(MathPow)                                \
   V(ProfileEntryHook)                       \
   V(RecordWrite)                            \
@@ -882,6 +883,19 @@ class LoadIndexedInterceptorStub : public PlatformCodeStub {
 };
 
 
+class LoadIndexedStringStub : public PlatformCodeStub {
+ public:
+  explicit LoadIndexedStringStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
+
+  virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
+  virtual Code::StubType GetStubType() { return Code::FAST; }
+
+  DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+  DEFINE_PLATFORM_CODE_STUB(LoadIndexedString, PlatformCodeStub);
+};
+
+
 class HandlerStub : public HydrogenCodeStub {
  public:
   virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
@@ -1657,6 +1671,15 @@ enum StringIndexFlags {
 };
 
 
+enum ReceiverCheckMode {
+  // We don't know anything about the receiver.
+  RECEIVER_IS_UNKNOWN,
+
+  // We know the receiver is a string.
+  RECEIVER_IS_STRING
+};
+
+
 // Generates code implementing String.prototype.charCodeAt.
 //
 // Only supports the case when the receiver is a string and the index
@@ -1669,20 +1692,19 @@ enum StringIndexFlags {
 // preserved, |scratch| and |result| are clobbered.
 class StringCharCodeAtGenerator {
  public:
-  StringCharCodeAtGenerator(Register object,
-                            Register index,
-                            Register result,
-                            Label* receiver_not_string,
-                            Label* index_not_number,
+  StringCharCodeAtGenerator(Register object, Register index, Register result,
+                            Label* receiver_not_string, Label* index_not_number,
                             Label* index_out_of_range,
-                            StringIndexFlags index_flags)
+                            StringIndexFlags index_flags,
+                            ReceiverCheckMode check_mode = RECEIVER_IS_UNKNOWN)
       : object_(object),
         index_(index),
         result_(result),
         receiver_not_string_(receiver_not_string),
         index_not_number_(index_not_number),
         index_out_of_range_(index_out_of_range),
-        index_flags_(index_flags) {
+        index_flags_(index_flags),
+        check_mode_(check_mode) {
     DCHECK(!result_.is(object_));
     DCHECK(!result_.is(index_));
   }
@@ -1714,6 +1736,7 @@ class StringCharCodeAtGenerator {
   Label* index_out_of_range_;
 
   StringIndexFlags index_flags_;
+  ReceiverCheckMode check_mode_;
 
   Label call_runtime_;
   Label index_not_smi_;
@@ -1773,20 +1796,13 @@ class StringCharFromCodeGenerator {
 // preserved, |scratch1|, |scratch2|, and |result| are clobbered.
 class StringCharAtGenerator {
  public:
-  StringCharAtGenerator(Register object,
-                        Register index,
-                        Register scratch,
-                        Register result,
-                        Label* receiver_not_string,
-                        Label* index_not_number,
-                        Label* index_out_of_range,
-                        StringIndexFlags index_flags)
-      : char_code_at_generator_(object,
-                                index,
-                                scratch,
-                                receiver_not_string,
-                                index_not_number,
-                                index_out_of_range,
+  StringCharAtGenerator(Register object, Register index, Register scratch,
+                        Register result, Label* receiver_not_string,
+                        Label* index_not_number, Label* index_out_of_range,
+                        StringIndexFlags index_flags,
+                        ReceiverCheckMode check_mode = RECEIVER_IS_UNKNOWN)
+      : char_code_at_generator_(object, index, scratch, receiver_not_string,
+                                index_not_number, index_out_of_range,
                                 index_flags),
         char_from_code_generator_(scratch, result) {}
 
index 39bef30..35ea821 100644 (file)
@@ -691,6 +691,37 @@ void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is on the stack.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = ebx;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  Register result = eax;
+  DCHECK(!result.is(scratch));
+
+  // TODO(mvstanton): the generator doesn't need to verify that
+  // receiver is a string map, that is done outside the handler.
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ ret(0);
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The key is in edx and the parameter count is in eax.
   DCHECK(edx.is(ArgumentsAccessReadDescriptor::index()));
@@ -2747,14 +2778,16 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   // If the receiver is a smi trigger the non-string case.
   STATIC_ASSERT(kSmiTag == 0);
-  __ JumpIfSmi(object_, receiver_not_string_);
-
-  // Fetch the instance type of the receiver into result register.
-  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
-  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
-  // If the receiver is not a string trigger the non-string case.
-  __ test(result_, Immediate(kIsNotStringMask));
-  __ j(not_zero, receiver_not_string_);
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
+
+    // Fetch the instance type of the receiver into result register.
+    __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
+    __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ test(result_, Immediate(kIsNotStringMask));
+    __ j(not_zero, receiver_not_string_);
+  }
 
   // If the index is non-smi trigger the non-smi case.
   STATIC_ASSERT(kSmiTag == 0);
index d26dc49..9465257 100644 (file)
@@ -587,32 +587,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is in lr.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = r3;
-  Register result = r0;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ Ret();
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   // Push receiver, key and value for runtime call.
   __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
index 4ec76b6..d25dd07 100644 (file)
@@ -627,32 +627,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is in lr.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register result = x0;
-  Register scratch = x3;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ Ret();
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ Bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   ASM_LOCATION("KeyedStoreIC::GenerateMiss");
 
index 6180b5f..7f440c0 100644 (file)
@@ -415,8 +415,8 @@ void ElementHandlerCompiler::CompileElementHandlers(
     Handle<Map> receiver_map = receiver_maps->at(i);
     Handle<Code> cached_stub;
 
-    if ((receiver_map->instance_type() & kNotStringTag) == 0) {
-      cached_stub = isolate()->builtins()->KeyedLoadIC_String();
+    if (receiver_map->IsStringMap()) {
+      cached_stub = LoadIndexedStringStub(isolate()).GetCode();
     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
     } else {
index 13f17eb..f6dac32 100644 (file)
@@ -476,33 +476,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is on the stack.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = ebx;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-  Register result = eax;
-  DCHECK(!result.is(scratch));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ ret(0);
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
   // Return address is on the stack.
   Label slow, notin;
index 2471564..9ba5663 100644 (file)
@@ -96,6 +96,9 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
   Handle<Code> stub;
   if (receiver_map->has_indexed_interceptor()) {
     stub = LoadIndexedInterceptorStub(isolate).GetCode();
+  } else if (receiver_map->IsStringMap()) {
+    // We have a string.
+    stub = LoadIndexedStringStub(isolate).GetCode();
   } else if (receiver_map->has_sloppy_arguments_elements()) {
     stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
   } else if (receiver_map->has_fast_elements() ||
index ca9e00a..8730a3f 100644 (file)
@@ -512,15 +512,10 @@ void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
                         ConstantPoolArray* constant_pool) {
   if (IsCleared(target)) return;
 
-  // If the target is the string_stub, then don't clear it. It is the
-  // perfect stub if we continue to see strings. Holding this
-  // state is not preventing learning new information.
-  if (target != *isolate->builtins()->KeyedLoadIC_String()) {
-    // Make sure to also clear the map used in inline fast cases.  If we
-    // do not clear these maps, cached code can keep objects alive
-    // through the embedded maps.
-    SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool);
-  }
+  // Make sure to also clear the map used in inline fast cases.  If we
+  // do not clear these maps, cached code can keep objects alive
+  // through the embedded maps.
+  SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool);
 }
 
 
@@ -1162,14 +1157,11 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
 }
 
 
-Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
+Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
   Handle<Map> receiver_map(receiver->map(), isolate());
   MapHandleList target_receiver_maps;
-  if (target().is_identical_to(string_stub())) {
-    target_receiver_maps.Add(isolate()->factory()->string_map());
-  } else {
-    TargetMaps(&target_receiver_maps);
-  }
+  TargetMaps(&target_receiver_maps);
+
   if (target_receiver_maps.length() == 0) {
     return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
   }
@@ -1181,9 +1173,10 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
   // monomorphic. If this optimistic assumption is not true, the IC will
   // miss again and it will become polymorphic and support both the
   // untransitioned and transitioned maps.
-  if (state() == MONOMORPHIC && IsMoreGeneralElementsKindTransition(
-                                    target_receiver_maps.at(0)->elements_kind(),
-                                    receiver->GetElementsKind())) {
+  if (state() == MONOMORPHIC && !receiver->IsString() &&
+      IsMoreGeneralElementsKindTransition(
+          target_receiver_maps.at(0)->elements_kind(),
+          Handle<JSObject>::cast(receiver)->GetElementsKind())) {
     return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
   }
 
@@ -1231,11 +1224,9 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
                                LoadIC::Load(object, Handle<Name>::cast(key)),
                                Object);
   } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
-    if (object->IsString() && key->IsNumber()) {
-      if (state() == UNINITIALIZED) stub = string_stub();
-    } else if (object->IsJSObject()) {
-      Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-      if (!Object::ToSmi(isolate(), key).is_null()) {
+    if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
+      Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
+      if (object->IsString() || !Object::ToSmi(isolate(), key).is_null()) {
         stub = LoadElementStub(receiver);
       }
     }
index 7124638..44df480 100644 (file)
@@ -413,7 +413,6 @@ class KeyedLoadIC : public LoadIC {
     GenerateMiss(masm);
   }
   static void GenerateGeneric(MacroAssembler* masm);
-  static void GenerateString(MacroAssembler* masm);
 
   // Bit mask to be tested against bit field for the cases when
   // generic stub should go into slow case.
@@ -428,16 +427,14 @@ class KeyedLoadIC : public LoadIC {
   static Handle<Code> pre_monomorphic_stub(Isolate* isolate);
 
  protected:
-  Handle<Code> LoadElementStub(Handle<JSObject> receiver);
+  // receiver is HeapObject because it could be a String or a JSObject
+  Handle<Code> LoadElementStub(Handle<HeapObject> receiver);
   virtual Handle<Code> pre_monomorphic_stub() const {
     return pre_monomorphic_stub(isolate());
   }
 
  private:
   Handle<Code> generic_stub() const { return generic_stub(isolate()); }
-  Handle<Code> string_stub() {
-    return isolate()->builtins()->KeyedLoadIC_String();
-  }
 
   static void Clear(Isolate* isolate, Address address, Code* target,
                     ConstantPoolArray* constant_pool);
index 559786d..01b9bb6 100644 (file)
@@ -594,32 +594,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is in ra.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = a3;
-  Register result = v0;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ Ret();
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 static void KeyedStoreGenerateGenericHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
index db540b8..b945d20 100644 (file)
@@ -403,32 +403,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is on the stack.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = rbx;
-  Register result = rax;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ ret(0);
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 static void KeyedStoreGenerateGenericHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
index 9dd8bdc..bebb15f 100644 (file)
@@ -1403,6 +1403,34 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in ra.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = a3;
+  Register result = v0;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 // Uses registers a0 to t0.
 // Expected input (depending on whether args are in registers or on the stack):
 // * object: a0 or at sp + 1 * kPointerSize.
index 76d79aa..0e4247e 100644 (file)
@@ -6140,6 +6140,7 @@ class Map: public HeapObject {
   bool IsJSObjectMap() {
     return instance_type() >= FIRST_JS_OBJECT_TYPE;
   }
+  bool IsStringMap() { return instance_type() < FIRST_NONSTRING_TYPE; }
   bool IsJSProxyMap() {
     InstanceType type = instance_type();
     return FIRST_JS_PROXY_TYPE <= type && type <= LAST_JS_PROXY_TYPE;
index 6594bdb..6cb8e95 100644 (file)
@@ -260,12 +260,14 @@ void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id,
 void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
     TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) {
   receiver_types->Clear();
-  *is_string = false;
-  if (LoadIsBuiltin(id, Builtins::kKeyedLoadIC_String)) {
-    *is_string = true;
-  } else {
-    CollectReceiverTypes(id, receiver_types);
+  CollectReceiverTypes(id, receiver_types);
+
+  // Are all the receiver maps string maps?
+  bool all_strings = receiver_types->length() > 0;
+  for (int i = 0; i < receiver_types->length(); i++) {
+    all_strings &= receiver_types->at(i)->IsStringMap();
   }
+  *is_string = all_strings;
 }
 
 
index 7d1e4f5..a12e92e 100644 (file)
@@ -867,6 +867,34 @@ void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is on the stack.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = rbx;
+  Register result = rax;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ ret(0);
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   // rsp[0]  : return address
   // rsp[8]  : number of parameters