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
This commit is contained in:
ager@chromium.org 2008-10-27 14:36:08 +00:00
parent 2dcb4d2c59
commit 721b7298e2
5 changed files with 88 additions and 24 deletions

View File

@ -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) {
// ----------- S t a t e -------------
// -- r2 : name
@ -164,30 +186,33 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) {
// -- [sp] : receiver
// -----------------------------------
Label miss;
Label miss, load_length, check_wrapper;
__ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi.
__ tst(r0, Operand(kSmiTagMask));
__ 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);
// Check if the object is a string.
GenerateStringCheck(masm, r0, r1, r3, &miss, &check_wrapper);
// Load length directly from the string.
__ bind(&load_length);
__ and_(r1, r1, Operand(kStringSizeMask));
__ add(r1, r1, Operand(String::kHashShift));
// Load length directly from the string.
__ ldr(r0, FieldMemOperand(r0, String::kLengthOffset));
__ mov(r0, Operand(r0, LSR, r1));
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ 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.
__ bind(&miss);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));

View File

@ -453,8 +453,17 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
}
if (FLAG_use_ic) {
// Use specialized code for getting the length of strings.
if (object->IsString() && name->Equals(Heap::length_symbol())) {
// 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->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
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
#endif

View File

@ -301,6 +301,11 @@ bool Object::IsJSValue() {
}
bool Object::IsStringWrapper() {
return IsJSValue() && JSValue::cast(this)->value()->IsString();
}
bool Object::IsProxy() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE;

View File

@ -626,6 +626,7 @@ class Object BASE_EMBEDDED {
inline bool IsOddball();
inline bool IsSharedFunctionInfo();
inline bool IsJSValue();
inline bool IsStringWrapper();
inline bool IsProxy();
inline bool IsBoolean();
inline bool IsJSArray();

View File

@ -159,31 +159,55 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
}
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
Register scratch,
Label* miss_label) {
// Check that the receiver isn't a smi.
// 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.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss_label, not_taken);
__ j(zero, smi, not_taken);
// Check that the object is a string.
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0);
__ 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.
__ bind(&load_length);
__ and_(scratch, kStringSizeMask);
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
// ecx is also the receiver.
__ lea(ecx, Operand(scratch, String::kLongLengthShift));
__ shr(eax); // ecx is implicit shift register.
__ shl(eax, kSmiTagSize);
__ 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);
}