Revision: 6093
Author: [email protected]
Date: Tue Dec 21 02:52:50 2010
Log: Implement inlining of instanceof tests on ARM.

TBR=sgjesse

BUG=
TEST=

Review URL: http://codereview.chromium.org/6004005
http://code.google.com/p/v8/source/detail?r=6093

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Dec 7 03:31:57 2010 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Dec 21 02:52:50 2010
@@ -2893,80 +2893,97 @@
 }


-// This stub performs an instanceof, calling the builtin function if
-// necessary.  Uses r1 for the object, r0 for the function that it may
-// be an instance of (these are fetched from the stack).
+// Uses registers r0 to r4. Expected input is
+// function in r0 (or at sp+1*ptrsz) and object in
+// r1 (or at sp), depending on whether or not
+// args_in_registers() is true.
 void InstanceofStub::Generate(MacroAssembler* masm) {
-  // Get the object - slow case for smis (we may need to throw an exception
-  // depending on the rhs).
-  Label slow, loop, is_instance, is_not_instance;
-  __ ldr(r0, MemOperand(sp, 1 * kPointerSize));
-  __ BranchOnSmi(r0, &slow);
-
-  // Check that the left hand is a JS object and put map in r3.
-  __ CompareObjectType(r0, r3, r2, FIRST_JS_OBJECT_TYPE);
-  __ b(lt, &slow);
-  __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
-  __ b(gt, &slow);
-
-  // Get the prototype of the function (r4 is result, r2 is scratch).
-  __ ldr(r1, MemOperand(sp, 0));
-  // r1 is function, r3 is map.
+  // Fixed register usage throughout the stub:
+  const Register object = r1;  // Object (lhs).
+  const Register map = r3;  // Map of the object.
+  const Register function = r0;  // Function (rhs).
+  const Register prototype = r4;  // Prototype of the function.
+  const Register scratch = r2;
+  Label slow, loop, is_instance, is_not_instance, not_js_object;
+  if (!args_in_registers()) {
+    __ ldr(function, MemOperand(sp, 1 * kPointerSize));
+    __ ldr(object, MemOperand(sp, 0));
+  }
+
+  // Check that the left hand is a JS object and load map.
+  __ BranchOnSmi(object, &slow);
+  __ IsObjectJSObjectType(object, map, scratch, &slow);

   // Look up the function and the map in the instanceof cache.
   Label miss;
   __ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex);
-  __ cmp(r1, ip);
+  __ cmp(object, ip);
   __ b(ne, &miss);
   __ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex);
-  __ cmp(r3, ip);
+  __ cmp(map, ip);
   __ b(ne, &miss);
-  __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
-  __ pop();
-  __ pop();
-  __ mov(pc, Operand(lr));
+  __ LoadRoot(function, Heap::kInstanceofCacheAnswerRootIndex);
+  __ Ret(args_in_registers() ? 0 : 2);

   __ bind(&miss);
-  __ TryGetFunctionPrototype(r1, r4, r2, &slow);
+  __ TryGetFunctionPrototype(object, prototype, scratch, &slow);

   // Check that the function prototype is a JS object.
-  __ BranchOnSmi(r4, &slow);
-  __ CompareObjectType(r4, r5, r5, FIRST_JS_OBJECT_TYPE);
-  __ b(lt, &slow);
-  __ cmp(r5, Operand(LAST_JS_OBJECT_TYPE));
-  __ b(gt, &slow);
-
-  __ StoreRoot(r1, Heap::kInstanceofCacheFunctionRootIndex);
-  __ StoreRoot(r3, Heap::kInstanceofCacheMapRootIndex);
+  __ BranchOnSmi(prototype, &slow);
+  __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
+
+  __ StoreRoot(object, Heap::kInstanceofCacheFunctionRootIndex);
+  __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);

   // Register mapping: r3 is object map and r4 is function prototype.
   // Get prototype of object into r2.
-  __ ldr(r2, FieldMemOperand(r3, Map::kPrototypeOffset));
+  __ ldr(scratch, FieldMemOperand(map, Map::kPrototypeOffset));

   // Loop through the prototype chain looking for the function prototype.
   __ bind(&loop);
-  __ cmp(r2, Operand(r4));
+  __ cmp(scratch, Operand(prototype));
   __ b(eq, &is_instance);
   __ LoadRoot(ip, Heap::kNullValueRootIndex);
-  __ cmp(r2, ip);
+  __ cmp(scratch, ip);
   __ b(eq, &is_not_instance);
-  __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
-  __ ldr(r2, FieldMemOperand(r2, Map::kPrototypeOffset));
+  __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
+  __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
   __ jmp(&loop);

   __ bind(&is_instance);
   __ mov(r0, Operand(Smi::FromInt(0)));
   __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
-  __ pop();
-  __ pop();
-  __ mov(pc, Operand(lr));  // Return.
+  __ Ret(args_in_registers() ? 0 : 2);

   __ bind(&is_not_instance);
   __ mov(r0, Operand(Smi::FromInt(1)));
-  __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
-  __ pop();
-  __ pop();
-  __ mov(pc, Operand(lr));  // Return.
+  __ Ret(args_in_registers() ? 0 : 2);
+
+  Label object_not_null, object_not_null_or_smi;
+  __ bind(&not_js_object);
+ // Before null, smi and string value checks, check that the rhs is a function
+  // as for a non-function rhs an exception needs to be thrown.
+  __ BranchOnSmi(function, &slow);
+  __ CompareObjectType(function, map, scratch, JS_FUNCTION_TYPE);
+  __ b(ne, &slow);
+
+  // Null is not instance of anything.
+  __ cmp(scratch, Operand(Factory::null_value()));
+  __ b(ne, &object_not_null);
+  __ mov(r0, Operand(Smi::FromInt(1)));
+  __ Ret(args_in_registers() ? 0 : 2);
+
+  __ bind(&object_not_null);
+  // Smi values are not instances of anything.
+  __ BranchOnNotSmi(object, &object_not_null_or_smi);
+  __ mov(r0, Operand(Smi::FromInt(1)));
+  __ Ret(args_in_registers() ? 0 : 2);
+
+  __ bind(&object_not_null_or_smi);
+  // String values are not instances of anything.
+  __ IsObjectJSStringType(object, scratch, &slow);
+  __ mov(r0, Operand(Smi::FromInt(1)));
+  __ Ret(args_in_registers() ? 0 : 2);

   // Slow-case.  Tail call builtin.
   __ bind(&slow);
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Mon Dec 20 05:52:14 2010
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Tue Dec 21 02:52:50 2010
@@ -1316,7 +1316,8 @@

 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
   LInstruction* result =
-      new LInstanceOf(Use(instr->left()), Use(instr->right()));
+      new LInstanceOf(UseFixed(instr->left(), r1),
+                      UseFixed(instr->right(), r0));
   return MarkAsCall(DefineFixed(result, r0), instr);
 }

=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Dec 20 05:52:14 2010 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Dec 21 02:52:50 2010
@@ -1337,7 +1337,14 @@


 void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
-  Abort("DoInstanceOf unimplemented.");
+  // We expect object and function in registers r1 and r0.
+  InstanceofStub stub(InstanceofStub::kArgsInRegisters);
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+
+  Label true_value, done;
+  __ tst(r0, r0);
+  __ mov(r0, Operand(Factory::false_value()), LeaveCC, eq);
+  __ mov(r0, Operand(Factory::true_value()), LeaveCC, ne);
 }


=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Fri Dec 10 06:10:54 2010 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Dec 21 02:52:50 2010
@@ -176,6 +176,12 @@
     add(sp, sp, Operand(count * kPointerSize), LeaveCC, cond);
   }
 }
+
+
+void MacroAssembler::Ret(int drop, Condition cond) {
+  Drop(drop, cond);
+  Ret(cond);
+}


 void MacroAssembler::Swap(Register reg1,
@@ -819,6 +825,38 @@
     InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
   }
 }
+
+
+void MacroAssembler::IsObjectJSObjectType(Register heap_object,
+                                          Register map,
+                                          Register scratch,
+                                          Label* fail) {
+  ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+  IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map,
+                                            Register scratch,
+                                            Label* fail) {
+  ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  cmp(scratch, Operand(FIRST_JS_OBJECT_TYPE));
+  b(lt, fail);
+  cmp(scratch, Operand(LAST_JS_OBJECT_TYPE));
+  b(gt, fail);
+}
+
+
+void MacroAssembler::IsObjectJSStringType(Register object,
+                                           Register scratch,
+                                           Label* fail) {
+  ASSERT(kNotStringTag != 0);
+
+  ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+  ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+  tst(scratch, Operand(kIsNotStringMask));
+  b(nz, fail);
+}


 #ifdef ENABLE_DEBUGGER_SUPPORT
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Dec 7 03:31:57 2010 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Dec 21 02:52:50 2010
@@ -96,6 +96,7 @@
   // from the stack, clobbering only the sp register.
   void Drop(int count, Condition cond = al);

+  void Ret(int drop, Condition cond = al);

// Swap two registers. If the scratch register is omitted then a slightly
   // less efficient form using xor instead of mov is emitted.
@@ -298,6 +299,18 @@
                       const ParameterCount& actual,
                       InvokeFlag flag);

+  void IsObjectJSObjectType(Register heap_object,
+                            Register map,
+                            Register scratch,
+                            Label* fail);
+
+  void IsInstanceJSObjectType(Register map,
+                              Register scratch,
+                              Label* fail);
+
+  void IsObjectJSStringType(Register object,
+                            Register scratch,
+                            Label* fail);

 #ifdef ENABLE_DEBUGGER_SUPPORT
// ---------------------------------------------------------------------------

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to