From: ager@chromium.org Date: Mon, 27 Oct 2008 14:36:08 +0000 (+0000) Subject: Allow inline caching for getting the length of string wrapper objects. X-Git-Tag: upstream/4.7.83~25106 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=721b7298e2119832a18de5bd4dfa2fa49fac02bb;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/ic-arm.cc b/src/ic-arm.cc index c29caf125..bdb3b768a 100644 --- a/src/ic-arm.cc +++ b/src/ic-arm.cc @@ -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(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(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 ic(Builtins::builtin(Builtins::LoadIC_Miss)); diff --git a/src/ic.cc b/src/ic.cc index 92fc9c935..2ec7b0953 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -453,8 +453,17 @@ Object* LoadIC::Load(State state, Handle object, Handle 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(Handle::cast(object)->value()); + } #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); #endif diff --git a/src/objects-inl.h b/src/objects-inl.h index cff533403..beb6c0e1a 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -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; diff --git a/src/objects.h b/src/objects.h index fa4921514..d627935ed 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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(); diff --git a/src/stub-cache-ia32.cc b/src/stub-cache-ia32.cc index da3d8858b..f59ed57a2 100644 --- a/src/stub-cache-ia32.cc +++ b/src/stub-cache-ia32.cc @@ -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); }