diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index efcc1aefce..7fe100d0dc 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -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. diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index 374eff36c0..f3fb6ac63d 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc @@ -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. diff --git a/src/builtins.cc b/src/builtins.cc index 4d2fa0a76e..8b385aae87 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -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); } diff --git a/src/builtins.h b/src/builtins.h index da1ae108d5..13a4b8027f 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -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) \ \ diff --git a/src/code-stubs.h b/src/code-stubs.h index 9f6e9de984..7fa9d61f98 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -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) {} diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 39bef3065b..35ea821b60 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -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_); + 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_); + // 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); diff --git a/src/ic/arm/ic-arm.cc b/src/ic/arm/ic-arm.cc index d26dc491eb..9465257bbe 100644 --- a/src/ic/arm/ic-arm.cc +++ b/src/ic/arm/ic-arm.cc @@ -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(), diff --git a/src/ic/arm64/ic-arm64.cc b/src/ic/arm64/ic-arm64.cc index 4ec76b6655..d25dd07a1c 100644 --- a/src/ic/arm64/ic-arm64.cc +++ b/src/ic/arm64/ic-arm64.cc @@ -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"); diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc index 6180b5f6f1..7f440c07ca 100644 --- a/src/ic/handler-compiler.cc +++ b/src/ic/handler-compiler.cc @@ -415,8 +415,8 @@ void ElementHandlerCompiler::CompileElementHandlers( Handle receiver_map = receiver_maps->at(i); Handle 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 { diff --git a/src/ic/ia32/ic-ia32.cc b/src/ic/ia32/ic-ia32.cc index 13f17eb80c..f6dac32b13 100644 --- a/src/ic/ia32/ic-ia32.cc +++ b/src/ic/ia32/ic-ia32.cc @@ -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; diff --git a/src/ic/ic-compiler.cc b/src/ic/ic-compiler.cc index 24715645da..9ba566364b 100644 --- a/src/ic/ic-compiler.cc +++ b/src/ic/ic-compiler.cc @@ -96,6 +96,9 @@ Handle PropertyICCompiler::ComputeKeyedLoadMonomorphic( Handle 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() || diff --git a/src/ic/ic.cc b/src/ic/ic.cc index ca9e00a596..8730a3fa03 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -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 TryConvertKey(Handle key, Isolate* isolate) { } -Handle KeyedLoadIC::LoadElementStub(Handle receiver) { +Handle KeyedLoadIC::LoadElementStub(Handle receiver) { Handle 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 KeyedLoadIC::LoadElementStub(Handle 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::cast(receiver)->GetElementsKind())) { return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map); } @@ -1231,11 +1224,9 @@ MaybeHandle KeyedLoadIC::Load(Handle object, LoadIC::Load(object, Handle::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 receiver = Handle::cast(object); - if (!Object::ToSmi(isolate(), key).is_null()) { + if (object->IsJSObject() || (object->IsString() && key->IsNumber())) { + Handle receiver = Handle::cast(object); + if (object->IsString() || !Object::ToSmi(isolate(), key).is_null()) { stub = LoadElementStub(receiver); } } diff --git a/src/ic/ic.h b/src/ic/ic.h index 7124638bcb..44df480f55 100644 --- a/src/ic/ic.h +++ b/src/ic/ic.h @@ -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 pre_monomorphic_stub(Isolate* isolate); protected: - Handle LoadElementStub(Handle receiver); + // receiver is HeapObject because it could be a String or a JSObject + Handle LoadElementStub(Handle receiver); virtual Handle pre_monomorphic_stub() const { return pre_monomorphic_stub(isolate()); } private: Handle generic_stub() const { return generic_stub(isolate()); } - Handle string_stub() { - return isolate()->builtins()->KeyedLoadIC_String(); - } static void Clear(Isolate* isolate, Address address, Code* target, ConstantPoolArray* constant_pool); diff --git a/src/ic/mips/ic-mips.cc b/src/ic/mips/ic-mips.cc index 559786d42e..01b9bb64e5 100644 --- a/src/ic/mips/ic-mips.cc +++ b/src/ic/mips/ic-mips.cc @@ -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, diff --git a/src/ic/x64/ic-x64.cc b/src/ic/x64/ic-x64.cc index db540b811c..b945d207d0 100644 --- a/src/ic/x64/ic-x64.cc +++ b/src/ic/x64/ic-x64.cc @@ -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) { diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 9dd8bdc07f..bebb15f70c 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -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. diff --git a/src/objects.h b/src/objects.h index 76d79aad9d..0e4247e3c7 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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; diff --git a/src/type-info.cc b/src/type-info.cc index 6594bdb593..6cb8e9576d 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -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; } diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 7d1e4f5e0d..a12e92eab6 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -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