Eliminate special keyed load string stub in favor of uniform handlers.
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
This commit is contained in:
parent
fe3a8845f0
commit
ecac8b0877
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) \
|
||||
\
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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() ||
|
||||
|
37
src/ic/ic.cc
37
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<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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user