Commit 721b7298 authored by ager@chromium.org's avatar ager@chromium.org

Allow inline caching for getting the length of string wrapper objects.

Review URL: http://codereview.chromium.org/8620

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@608 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2dcb4d2c
...@@ -157,6 +157,28 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) { ...@@ -157,6 +157,28 @@ void LoadIC::GenerateArrayLength(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 scratch1 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.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, 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);
}
void LoadIC::GenerateStringLength(MacroAssembler* masm) { void LoadIC::GenerateStringLength(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : name // -- r2 : name
...@@ -164,30 +186,33 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) { ...@@ -164,30 +186,33 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) {
// -- [sp] : receiver // -- [sp] : receiver
// ----------------------------------- // -----------------------------------
Label miss; Label miss, load_length, check_wrapper;
__ ldr(r0, MemOperand(sp, 0)); __ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi. // Check if the object is a string.
__ tst(r0, Operand(kSmiTagMask)); GenerateStringCheck(masm, r0, r1, r3, &miss, &check_wrapper);
__ b(eq, &miss);
// Check that the object is a string.
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
__ and_(r3, r1, Operand(kIsNotStringMask));
// The cast is to resolve the overload for the argument of 0x0.
__ cmp(r3, Operand(static_cast<int32_t>(kStringTag)));
__ b(ne, &miss);
// Load length directly from the string.
__ bind(&load_length);
__ and_(r1, r1, Operand(kStringSizeMask)); __ and_(r1, r1, Operand(kStringSizeMask));
__ add(r1, r1, Operand(String::kHashShift)); __ add(r1, r1, Operand(String::kHashShift));
// Load length directly from the string.
__ ldr(r0, FieldMemOperand(r0, String::kLengthOffset)); __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset));
__ mov(r0, Operand(r0, LSR, r1)); __ mov(r0, Operand(r0, LSR, r1));
__ mov(r0, Operand(r0, LSL, kSmiTagSize)); __ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ Ret(); __ Ret();
// Check if the object is a JSValue wrapper.
__ bind(&check_wrapper);
__ cmp(r0, Operand(JS_VALUE_TYPE));
__ b(ne, &miss);
// Check if the wrapped value is a string and load the length
// directly if it is.
__ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
GenerateStringCheck(masm, r0, r1, r3, &miss, &miss);
__ b(&load_length);
// Cache miss: Jump to runtime. // Cache miss: Jump to runtime.
__ bind(&miss); __ bind(&miss);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
......
...@@ -453,8 +453,17 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { ...@@ -453,8 +453,17 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
} }
if (FLAG_use_ic) { if (FLAG_use_ic) {
// Use specialized code for getting the length of strings. // Use specialized code for getting the length of strings and
if (object->IsString() && name->Equals(Heap::length_symbol())) { // 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->IsString() || object->IsStringWrapper()) &&
name->Equals(Heap::length_symbol())) {
HandleScope scope;
// Get the string if we have a string wrapper object.
if (object->IsJSValue()) {
object = Handle<Object>(Handle<JSValue>::cast(object)->value());
}
#ifdef DEBUG #ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
#endif #endif
......
...@@ -301,6 +301,11 @@ bool Object::IsJSValue() { ...@@ -301,6 +301,11 @@ bool Object::IsJSValue() {
} }
bool Object::IsStringWrapper() {
return IsJSValue() && JSValue::cast(this)->value()->IsString();
}
bool Object::IsProxy() { bool Object::IsProxy() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE; && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE;
......
...@@ -626,6 +626,7 @@ class Object BASE_EMBEDDED { ...@@ -626,6 +626,7 @@ class Object BASE_EMBEDDED {
inline bool IsOddball(); inline bool IsOddball();
inline bool IsSharedFunctionInfo(); inline bool IsSharedFunctionInfo();
inline bool IsJSValue(); inline bool IsJSValue();
inline bool IsStringWrapper();
inline bool IsProxy(); inline bool IsProxy();
inline bool IsBoolean(); inline bool IsBoolean();
inline bool IsJSArray(); inline bool IsJSArray();
......
...@@ -159,31 +159,55 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, ...@@ -159,31 +159,55 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
} }
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, // Generate code to check if an object is a string. If the object is
Register receiver, // a string, the map's instance type is left in the scratch register.
Register scratch, static void GenerateStringCheck(MacroAssembler* masm,
Label* miss_label) { Register receiver,
// Check that the receiver isn't a smi. Register scratch,
Label* smi,
Label* non_string_object) {
// Check that the object isn't a smi.
__ test(receiver, Immediate(kSmiTagMask)); __ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss_label, not_taken); __ j(zero, smi, not_taken);
// Check that the object is a string. // Check that the object is a string.
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0); ASSERT(kNotStringTag != 0);
__ test(scratch, Immediate(kNotStringTag)); __ test(scratch, Immediate(kNotStringTag));
__ j(not_zero, miss_label, not_taken); __ j(not_zero, non_string_object, not_taken);
}
__ and_(scratch, kStringSizeMask);
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
Register scratch,
Label* miss) {
Label load_length, check_wrapper;
// Check if the object is a string.
GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
// Load length directly from the string. // Load length directly from the string.
__ bind(&load_length);
__ and_(scratch, kStringSizeMask);
__ mov(eax, FieldOperand(receiver, String::kLengthOffset)); __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
// ecx is also the receiver. // ecx is also the receiver.
__ lea(ecx, Operand(scratch, String::kLongLengthShift)); __ lea(ecx, Operand(scratch, String::kLongLengthShift));
__ shr(eax); // ecx is implicit shift register. __ shr(eax); // ecx is implicit shift register.
__ shl(eax, kSmiTagSize); __ shl(eax, kSmiTagSize);
__ ret(0); __ ret(0);
// Check if the object is a JSValue wrapper.
__ bind(&check_wrapper);
__ cmp(receiver, JS_VALUE_TYPE);
__ j(not_equal, miss, not_taken);
// Check if the wrapped value is a string and load the length
// directly if it is.
__ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
GenerateStringCheck(masm, receiver, scratch, miss, miss);
__ jmp(&load_length);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment