Allow inline caching for getting the length of string wrapper objects.
authorager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 27 Oct 2008 14:36:08 +0000 (14:36 +0000)
committerager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 27 Oct 2008 14:36:08 +0000 (14:36 +0000)
Review URL: http://codereview.chromium.org/8620

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@608 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ic-arm.cc
src/ic.cc
src/objects-inl.h
src/objects.h
src/stub-cache-ia32.cc

index c29caf125bbd50a85a0e825267b4c4d70c6056b8..bdb3b768aeb0f753cde7f3b9890d6489da59005c 100644 (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));
index 92fc9c935122f294fc1a324792c570e262865af9..2ec7b0953c43c508c3306ff3d09bdcca62f66dd7 100644 (file)
--- a/src/ic.cc
+++ b/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
index cff533403732cb0ed38aeae3c45a1dc108fca483..beb6c0e1a46553cc9f231593246159a8a40beb14 100644 (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;
index fa49215149a3e51551af298bb743c83e8cdb6634..d627935edbc1c3cbc3cf2831803a3101659662c3 100644 (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();
index da3d8858bb36d8c8cd2ca238ca371414b1e12572..f59ed57a26ff3be46eca7d77a9ebaeef26ba35b5 100644 (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);
 }