Turn StringLengthStub (used by string wrappers only) into a hydrogen stub.

BUG=
R=yangguo@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19889 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2014-03-13 10:57:07 +00:00
parent 717c4d3bb5
commit c2af96ba7b
12 changed files with 138 additions and 368 deletions

View File

@ -187,6 +187,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
}
void StringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { x0, x2 };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { x1, x0 };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@ -1969,38 +1989,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
}
void StringLengthStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
if (kind() == Code::KEYED_LOAD_IC) {
// ----------- S t a t e -------------
// -- lr : return address
// -- x1 : receiver
// -- x0 : key
// -----------------------------------
Register key = x0;
receiver = x1;
__ Cmp(key, Operand(masm->isolate()->factory()->length_string()));
__ B(ne, &miss);
} else {
ASSERT(kind() == Code::LOAD_IC);
// ----------- S t a t e -------------
// -- lr : return address
// -- x2 : name
// -- x0 : receiver
// -- sp[0] : receiver
// -----------------------------------
receiver = x0;
}
StubCompiler::GenerateLoadStringLength(masm, receiver, x10, x11, &miss);
__ Bind(&miss);
StubCompiler::TailCallBuiltin(masm,
BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
ASM_LOCATION("StoreArrayLengthStub::Generate");
// This accepts as a receiver anything JSArray::SetElementsLength accepts

View File

@ -306,60 +306,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
}
// Generate code to check if an object is a string. If the object is a
// heap object, its map's instance type is left in the scratch1 register.
static void GenerateStringCheck(MacroAssembler* masm,
Register receiver,
Register scratch1,
Label* smi,
Label* non_string_object) {
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, smi);
// Get the object's instance type filed.
__ Ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
// Check if the "not string" bit is set.
__ Tbnz(scratch1, MaskToBit(kNotStringTag), non_string_object);
}
// Generate code to load the length from a string object and return the length.
// If the receiver object is not a string or a wrapped string object the
// execution continues at the miss label. The register containing the
// receiver is not clobbered if the receiver is not a string.
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss) {
// Input registers can't alias because we don't want to clobber the
// receiver register if the object is not a string.
ASSERT(!AreAliased(receiver, scratch1, scratch2));
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch1 register.
GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
// Load length directly from the string.
__ Ldr(x0, FieldMemOperand(receiver, String::kLengthOffset));
__ Ret();
// Check if the object is a JSValue wrapper.
__ Bind(&check_wrapper);
__ Cmp(scratch1, Operand(JS_VALUE_TYPE));
__ B(ne, miss);
// Unwrap the value and check if the wrapped value is a string.
__ Ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, scratch1, scratch2, miss, miss);
__ Ldr(x0, FieldMemOperand(scratch1, String::kLengthOffset));
__ Ret();
}
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register scratch1,

View File

@ -165,6 +165,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
}
void StringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { r0, r2 };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { r1, r0 };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@ -2100,37 +2120,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
}
void StringLengthStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
if (kind() == Code::KEYED_LOAD_IC) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
__ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
__ b(ne, &miss);
receiver = r1;
} else {
ASSERT(kind() == Code::LOAD_IC);
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- r0 : receiver
// -- sp[0] : receiver
// -----------------------------------
receiver = r0;
}
StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
// This accepts as a receiver anything JSArray::SetElementsLength accepts
// (currently anything except for external arrays which means anything with

View File

@ -351,60 +351,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
}
// Generate code to check if an object is a string. If the object is a
// heap object, its map's instance type is left in the scratch1 register.
// If this is not needed, scratch1 and scratch2 may be the same register.
static void GenerateStringCheck(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Label* smi,
Label* non_string_object) {
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, smi);
// Check that the object is a string.
__ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
__ and_(scratch2, scratch1, Operand(kIsNotStringMask));
// The cast is to resolve the overload for the argument of 0x0.
__ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
__ b(ne, non_string_object);
}
// Generate code to load the length from a string object and return the length.
// If the receiver object is not a string or a wrapped string object the
// execution continues at the miss label. The register containing the
// receiver is potentially clobbered.
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch1 register.
GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
// Load length directly from the string.
__ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
__ Ret();
// Check if the object is a JSValue wrapper.
__ bind(&check_wrapper);
__ cmp(scratch1, Operand(JS_VALUE_TYPE));
__ b(ne, miss);
// Unwrap the value and check if the wrapped value is a string.
__ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
__ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
__ Ret();
}
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register scratch1,

View File

@ -608,15 +608,15 @@ Handle<Code> LoadFieldStub::GenerateCode(Isolate* isolate) {
template<>
HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
return BuildLoadNamedField(GetParameter(0),
casted_stub()->representation(),
casted_stub()->offset(),
casted_stub()->is_inobject());
HValue* CodeStubGraphBuilder<StringLengthStub>::BuildCodeStub() {
HValue* string = BuildLoadNamedField(
GetParameter(0), Representation::Tagged(), JSValue::kValueOffset, true);
return BuildLoadNamedField(
string, Representation::Tagged(), String::kLengthOffset, true);
}
Handle<Code> KeyedLoadFieldStub::GenerateCode(Isolate* isolate) {
Handle<Code> StringLengthStub::GenerateCode(Isolate* isolate) {
return DoGenerateCode(isolate, this);
}

View File

@ -51,7 +51,6 @@ namespace internal {
V(CompareIC) \
V(CompareNilIC) \
V(MathPow) \
V(StringLength) \
V(FunctionPrototype) \
V(StoreArrayLength) \
V(RecordWrite) \
@ -98,7 +97,9 @@ namespace internal {
V(CallApiGetter) \
/* IC Handler stubs */ \
V(LoadField) \
V(KeyedLoadField)
V(KeyedLoadField) \
V(StringLength) \
V(KeyedStringLength)
// List of code stubs only used on ARM platforms.
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_A64)
@ -833,17 +834,6 @@ class FunctionPrototypeStub: public ICStub {
};
class StringLengthStub: public ICStub {
public:
explicit StringLengthStub(Code::Kind kind) : ICStub(kind) { }
virtual void Generate(MacroAssembler* masm);
private:
STATIC_ASSERT(KindBits::kSize == 4);
virtual CodeStub::Major MajorKey() { return StringLength; }
};
class StoreICStub: public ICStub {
public:
StoreICStub(Code::Kind kind, StrictMode strict_mode)
@ -959,6 +949,44 @@ class LoadFieldStub: public HandlerStub {
};
class StringLengthStub: public HandlerStub {
public:
explicit StringLengthStub() : HandlerStub() {
Initialize(Code::LOAD_IC);
}
virtual Handle<Code> GenerateCode(Isolate* isolate);
virtual void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);
protected:
virtual Code::Kind kind() const {
return KindBits::decode(bit_field_);
}
void Initialize(Code::Kind kind) {
bit_field_ = KindBits::encode(kind);
}
private:
virtual CodeStub::Major MajorKey() { return StringLength; }
};
class KeyedStringLengthStub: public StringLengthStub {
public:
explicit KeyedStringLengthStub() : StringLengthStub() {
Initialize(Code::KEYED_LOAD_IC);
}
virtual void InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);
private:
virtual CodeStub::Major MajorKey() { return KeyedStringLength; }
};
class StoreGlobalStub : public HandlerStub {
public:
explicit StoreGlobalStub(bool is_constant, bool check_global) {
@ -1072,8 +1100,6 @@ class KeyedLoadFieldStub: public LoadFieldStub {
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor);
virtual Handle<Code> GenerateCode(Isolate* isolate);
private:
virtual CodeStub::Major MajorKey() { return KeyedLoadField; }
};

View File

@ -170,6 +170,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
}
void StringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { edx, ecx };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { edx, ecx };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@ -1046,26 +1066,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
}
void StringLengthStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ecx : name
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
if (kind() == Code::KEYED_LOAD_IC) {
__ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
__ j(not_equal, &miss);
}
StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value

View File

@ -306,54 +306,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
}
// Generate code to check if an object is a string. If the object is
// a string, the map's instance type is left in the scratch register.
static void GenerateStringCheck(MacroAssembler* masm,
Register receiver,
Register scratch,
Label* smi,
Label* non_string_object) {
// Check that the object isn't a smi.
__ JumpIfSmi(receiver, smi);
// Check that the object is a string.
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
STATIC_ASSERT(kNotStringTag != 0);
__ test(scratch, Immediate(kNotStringTag));
__ j(not_zero, non_string_object);
}
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch register.
GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
// Load length from the string and convert to a smi.
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
__ ret(0);
// Check if the object is a JSValue wrapper.
__ bind(&check_wrapper);
__ cmp(scratch1, JS_VALUE_TYPE);
__ j(not_equal, miss);
// Check if the wrapped value is a string and load the length
// directly if it is.
__ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
__ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
__ ret(0);
}
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register scratch1,

View File

@ -536,31 +536,6 @@ MaybeObject* LoadIC::Load(Handle<Object> object,
}
if (FLAG_use_ic) {
// Use specialized code for getting the length of strings and
// string wrapper objects. The length property of string wrapper
// objects is read-only and therefore always returns the length of
// the underlying string value. See ECMA-262 15.5.5.1.
if (object->IsStringWrapper() &&
name->Equals(isolate()->heap()->length_string())) {
Handle<Code> stub;
if (state() == UNINITIALIZED) {
stub = pre_monomorphic_stub();
} else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) {
StringLengthStub string_length_stub(kind());
stub = string_length_stub.GetCode(isolate());
} else if (state() != MEGAMORPHIC) {
ASSERT(state() != GENERIC);
stub = megamorphic_stub();
}
if (!stub.is_null()) {
set_target(*stub);
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
}
// Get the string if we have a string wrapper object.
String* string = String::cast(JSValue::cast(*object)->value());
return Smi::FromInt(string->length());
}
// Use specialized code for getting prototype of functions.
if (object->IsJSFunction() &&
name->Equals(isolate()->heap()->prototype_string()) &&
@ -910,6 +885,17 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
return SimpleFieldLoad(length_index);
}
if (object->IsStringWrapper() &&
name->Equals(isolate()->heap()->length_string())) {
if (kind() == Code::LOAD_IC) {
StringLengthStub string_length_stub;
return string_length_stub.GetCode(isolate());
} else {
KeyedStringLengthStub string_length_stub;
return string_length_stub.GetCode(isolate());
}
}
Handle<HeapType> type = CurrentTypeOf(object, isolate());
Handle<JSObject> holder(lookup->holder());
LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind());

View File

@ -360,12 +360,6 @@ class StubCompiler BASE_EMBEDDED {
Register scratch,
Label* miss_label);
static void GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss_label);
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register scratch1,

View File

@ -166,6 +166,26 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
}
void StringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { rax, rcx };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStringLengthStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { rdx, rax };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ = NULL;
}
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@ -913,35 +933,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
}
void StringLengthStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
if (kind() == Code::KEYED_LOAD_IC) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
__ Cmp(rax, masm->isolate()->factory()->length_string());
__ j(not_equal, &miss);
receiver = rdx;
} else {
ASSERT(kind() == Code::LOAD_IC);
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
// -- rsp[0] : return address
// -----------------------------------
receiver = rax;
}
StubCompiler::GenerateLoadStringLength(masm, receiver, r8, r9, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(
masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value

View File

@ -281,54 +281,6 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
}
// Generate code to check if an object is a string. If the object is
// a string, the map's instance type is left in the scratch register.
static void GenerateStringCheck(MacroAssembler* masm,
Register receiver,
Register scratch,
Label* smi,
Label* non_string_object) {
// Check that the object isn't a smi.
__ JumpIfSmi(receiver, smi);
// Check that the object is a string.
__ movp(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
STATIC_ASSERT(kNotStringTag != 0);
__ testl(scratch, Immediate(kNotStringTag));
__ j(not_zero, non_string_object);
}
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss) {
Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch register.
GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
// Load length directly from the string.
__ movp(rax, FieldOperand(receiver, String::kLengthOffset));
__ ret(0);
// Check if the object is a JSValue wrapper.
__ bind(&check_wrapper);
__ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
__ j(not_equal, miss);
// Check if the wrapped value is a string and load the length
// directly if it is.
__ movp(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
__ movp(rax, FieldOperand(scratch2, String::kLengthOffset));
__ ret(0);
}
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register result,