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:
parent
2dcb4d2c59
commit
721b7298e2
@ -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));
|
||||
|
13
src/ic.cc
13
src/ic.cc
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user