Optimize array-length and fast element loads.
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 30 Dec 2010 19:30:42 +0000 (19:30 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 30 Dec 2010 19:30:42 +0000 (19:30 +0000)
1. Separating out the instance-type check from the array-length operation.

2. I also changed the bounds-check on keyed loads to use the length property
for JS arrays (like we do for array stores).

The new pattern should use less registers and allow more checks to be eliminated.

Review URL: http://codereview.chromium.org/5961016

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

src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h

index bc0f153..9c8e834 100644 (file)
@@ -1666,19 +1666,15 @@ LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoArrayLength(HArrayLength* instr) {
-  LOperand* array = NULL;
-  LOperand* temporary = NULL;
+LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LJSArrayLength(array));
+}
 
-  if (instr->value()->IsLoadElements()) {
-    array = UseRegisterAtStart(instr->value());
-  } else {
-    array = UseRegister(instr->value());
-    temporary = TempRegister();
-  }
 
-  LInstruction* result = new LArrayLength(array, temporary);
-  return AssignEnvironment(DefineAsRegister(result));
+LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LFixedArrayLength(array));
 }
 
 
index a0b18a5..5b152ef 100644 (file)
@@ -101,7 +101,8 @@ class Translation;
 //     LStoreNamedField
 //     LStoreNamedGeneric
 //   LUnaryOperation
-//     LArrayLength
+//     LJSArrayLength
+//     LFixedArrayLength
 //     LBitNotI
 //     LBranch
 //     LCallNew
@@ -162,7 +163,6 @@ class Translation;
   V(ArgumentsLength)                            \
   V(ArithmeticD)                                \
   V(ArithmeticT)                                \
-  V(ArrayLength)                                \
   V(ArrayLiteral)                               \
   V(BitI)                                       \
   V(BitNotI)                                    \
@@ -196,6 +196,7 @@ class Translation;
   V(Deoptimize)                                 \
   V(DivI)                                       \
   V(DoubleToI)                                  \
+  V(FixedArrayLength)                           \
   V(FunctionLiteral)                            \
   V(Gap)                                        \
   V(GlobalObject)                               \
@@ -210,6 +211,7 @@ class Translation;
   V(IsObjectAndBranch)                          \
   V(IsSmi)                                      \
   V(IsSmiAndBranch)                             \
+  V(JSArrayLength)                              \
   V(HasInstanceType)                            \
   V(HasInstanceTypeAndBranch)                   \
   V(HasCachedArrayIndex)                        \
@@ -1143,18 +1145,21 @@ class LCmpMapAndBranch: public LUnaryOperation {
 };
 
 
-class LArrayLength: public LUnaryOperation {
+class LJSArrayLength: public LUnaryOperation {
  public:
-  LArrayLength(LOperand* input, LOperand* temporary)
-      : LUnaryOperation(input), temporary_(temporary) { }
+  explicit LJSArrayLength(LOperand* input) : LUnaryOperation(input) { }
 
-  LOperand* temporary() const { return temporary_; }
+  DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
+  DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
+};
 
-  DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array-length")
-  DECLARE_HYDROGEN_ACCESSOR(ArrayLength)
 
- private:
-  LOperand* temporary_;
+class LFixedArrayLength: public LUnaryOperation {
+ public:
+  explicit LFixedArrayLength(LOperand* input) : LUnaryOperation(input) { }
+
+  DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
+  DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
 };
 
 
index dd94c68..53a4325 100644 (file)
@@ -898,24 +898,19 @@ void LCodeGen::DoConstantT(LConstantT* instr) {
 }
 
 
-void LCodeGen::DoArrayLength(LArrayLength* instr) {
+void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
   Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->input());
+  __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
+  Abort("DoJSArrayLength untested.");
+}
 
-  if (instr->hydrogen()->value()->IsLoadElements()) {
-    // We load the length directly from the elements array.
-    Register elements = ToRegister(instr->input());
-    __ ldr(result, FieldMemOperand(elements, FixedArray::kLengthOffset));
-  } else {
-    // Check that the receiver really is an array.
-    Register array = ToRegister(instr->input());
-    Register temporary = ToRegister(instr->temporary());
-    __ CompareObjectType(array, temporary, temporary, JS_ARRAY_TYPE);
-    DeoptimizeIf(ne, instr->environment());
 
-    // Load length directly from the array.
-    __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
-  }
-  Abort("DoArrayLength untested.");
+void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
+  Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->input());
+  __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
+  Abort("DoFixedArrayLength untested.");
 }
 
 
index ab72e34..e9c437f 100644 (file)
@@ -118,7 +118,6 @@ class LChunkBuilder;
 //       HStoreKeyedFastElement
 //       HStoreKeyedGeneric
 //     HUnaryOperation
-//       HArrayLength
 //       HBitNot
 //       HChange
 //       HCheckFunction
@@ -128,6 +127,8 @@ class LChunkBuilder;
 //       HCheckPrototypeMaps
 //       HCheckSmi
 //       HDeleteProperty
+//       HFixedArrayLength
+//       HJSArrayLength
 //       HLoadElements
 //         HTypeofIs
 //       HLoadNamedField
@@ -171,7 +172,6 @@ class LChunkBuilder;
   V(ArgumentsElements)                         \
   V(ArgumentsLength)                           \
   V(ArgumentsObject)                           \
-  V(ArrayLength)                               \
   V(ArrayLiteral)                              \
   V(BitAnd)                                    \
   V(BitNot)                                    \
@@ -204,6 +204,7 @@ class LChunkBuilder;
   V(Deoptimize)                                \
   V(Div)                                       \
   V(EnterInlined)                              \
+  V(FixedArrayLength)                          \
   V(FunctionLiteral)                           \
   V(GlobalObject)                              \
   V(GlobalReceiver)                            \
@@ -214,6 +215,7 @@ class LChunkBuilder;
   V(IsSmi)                                     \
   V(HasInstanceType)                           \
   V(HasCachedArrayIndex)                       \
+  V(JSArrayLength)                             \
   V(ClassOfTest)                               \
   V(LeaveInlined)                              \
   V(LoadElements)                              \
@@ -1339,9 +1341,9 @@ class HCallRuntime: public HCall {
 };
 
 
-class HArrayLength: public HUnaryOperation {
+class HJSArrayLength: public HUnaryOperation {
  public:
-  explicit HArrayLength(HValue* value) : HUnaryOperation(value) {
+  explicit HJSArrayLength(HValue* value) : HUnaryOperation(value) {
     // The length of an array is stored as a tagged value in the array
     // object. It is guaranteed to be 32 bit integer, but it can be
     // represented as either a smi or heap number.
@@ -1354,7 +1356,23 @@ class HArrayLength: public HUnaryOperation {
     return Representation::Tagged();
   }
 
-  DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array_length")
+  DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js_array_length")
+};
+
+
+class HFixedArrayLength: public HUnaryOperation {
+ public:
+  explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Tagged());
+    SetFlag(kDependsOnArrayLengths);
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed_array_length")
 };
 
 
index 87cc43a..03ce5b3 100644 (file)
@@ -3643,9 +3643,18 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
   Handle<Map> map = expr->GetMonomorphicReceiverType();
   ASSERT(map->has_fast_elements());
   AddInstruction(new HCheckMap(object, map));
-  HInstruction* elements = AddInstruction(new HLoadElements(object));
-  HInstruction* length = AddInstruction(new HArrayLength(elements));
-  AddInstruction(new HBoundsCheck(key, length));
+  bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
+  HLoadElements* elements = new HLoadElements(object);
+  HInstruction* length = NULL;
+  if (is_array) {
+    length = AddInstruction(new HJSArrayLength(object));
+    AddInstruction(new HBoundsCheck(key, length));
+    AddInstruction(elements);
+  } else {
+    AddInstruction(elements);
+    length = AddInstruction(new HFixedArrayLength(elements));
+    AddInstruction(new HBoundsCheck(key, length));
+  }
   return new HLoadKeyedFastElement(elements, key);
 }
 
@@ -3671,9 +3680,9 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
   bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
   HInstruction* length = NULL;
   if (is_array) {
-    length = AddInstruction(new HArrayLength(object));
+    length = AddInstruction(new HJSArrayLength(object));
   } else {
-    length = AddInstruction(new HArrayLength(elements));
+    length = AddInstruction(new HFixedArrayLength(elements));
   }
   AddInstruction(new HBoundsCheck(key, length));
   return new HStoreKeyedFastElement(elements, key, val);
@@ -3720,7 +3729,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
   if (expr->IsArrayLength()) {
     HValue* array = Pop();
     AddInstruction(new HCheckNonSmi(array));
-    instr = new HArrayLength(array);
+    AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE));
+    instr = new HJSArrayLength(array);
 
   } else if (expr->IsFunctionPrototype()) {
     HValue* function = Pop();
@@ -4859,7 +4869,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     switch (op) {
       case Token::EQ:
       case Token::EQ_STRICT: {
+        AddInstruction(new HCheckNonSmi(left));
         AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left));
+        AddInstruction(new HCheckNonSmi(right));
         AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right));
         instr = new HCompareJSObjectEq(left, right);
         break;
index 194585e..9569ac8 100644 (file)
@@ -977,23 +977,17 @@ void LCodeGen::DoConstantT(LConstantT* instr) {
 }
 
 
-void LCodeGen::DoArrayLength(LArrayLength* instr) {
+void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
   Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->input());
+  __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
+}
 
-  if (instr->hydrogen()->value()->IsLoadElements()) {
-    // We load the length directly from the elements array.
-    Register elements = ToRegister(instr->input());
-    __ mov(result, FieldOperand(elements, FixedArray::kLengthOffset));
-  } else {
-    // Check that the receiver really is an array.
-    Register array = ToRegister(instr->input());
-    Register temporary = ToRegister(instr->temporary());
-    __ CmpObjectType(array, JS_ARRAY_TYPE, temporary);
-    DeoptimizeIf(not_equal, instr->environment());
 
-    // Load length directly from the array.
-    __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
-  }
+void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
+  Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->input());
+  __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
 }
 
 
@@ -2933,9 +2927,6 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
   InstanceType first = instr->hydrogen()->first();
   InstanceType last = instr->hydrogen()->last();
 
-  __ test(input, Immediate(kSmiTagMask));
-  DeoptimizeIf(zero, instr->environment());
-
   __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
   __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
           static_cast<int8_t>(first));
index 44f0417..8c003a5 100644 (file)
@@ -1677,19 +1677,15 @@ LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoArrayLength(HArrayLength* instr) {
-  LOperand* array = NULL;
-  LOperand* temporary = NULL;
+LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LJSArrayLength(array));
+}
 
-  if (instr->value()->IsLoadElements()) {
-    array = UseRegisterAtStart(instr->value());
-  } else {
-    array = UseRegister(instr->value());
-    temporary = TempRegister();
-  }
 
-  LInstruction* result = new LArrayLength(array, temporary);
-  return AssignEnvironment(DefineAsRegister(result));
+LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LFixedArrayLength(array));
 }
 
 
index efd4ab5..94bf8fd 100644 (file)
@@ -104,7 +104,6 @@ class LGapNode;
 //     LStoreNamedField
 //     LStoreNamedGeneric
 //   LUnaryOperation
-//     LArrayLength
 //     LBitNotI
 //     LBranch
 //     LCallNew
@@ -117,6 +116,7 @@ class LGapNode;
 //     LClassOfTestAndBranch
 //     LDeleteProperty
 //     LDoubleToI
+//     LFixedArrayLength
 //     LHasCachedArrayIndex
 //     LHasCachedArrayIndexAndBranch
 //     LHasInstanceType
@@ -128,6 +128,7 @@ class LGapNode;
 //     LIsObjectAndBranch
 //     LIsSmi
 //     LIsSmiAndBranch
+//     LJSArrayLength
 //     LLoadNamedField
 //     LLoadNamedGeneric
 //     LLoadFunctionPrototype
@@ -165,7 +166,6 @@ class LGapNode;
   V(ArgumentsLength)                            \
   V(ArithmeticD)                                \
   V(ArithmeticT)                                \
-  V(ArrayLength)                                \
   V(ArrayLiteral)                               \
   V(BitI)                                       \
   V(BitNotI)                                    \
@@ -204,6 +204,7 @@ class LGapNode;
   V(GlobalObject)                               \
   V(GlobalReceiver)                             \
   V(Goto)                                       \
+  V(FixedArrayLength)                           \
   V(InstanceOf)                                 \
   V(InstanceOfAndBranch)                        \
   V(Integer32ToDouble)                          \
@@ -213,6 +214,7 @@ class LGapNode;
   V(IsObjectAndBranch)                          \
   V(IsSmi)                                      \
   V(IsSmiAndBranch)                             \
+  V(JSArrayLength)                              \
   V(HasInstanceType)                            \
   V(HasInstanceTypeAndBranch)                   \
   V(HasCachedArrayIndex)                        \
@@ -1148,18 +1150,21 @@ class LCmpMapAndBranch: public LUnaryOperation {
 };
 
 
-class LArrayLength: public LUnaryOperation {
+class LJSArrayLength: public LUnaryOperation {
  public:
-  LArrayLength(LOperand* input, LOperand* temporary)
-      : LUnaryOperation(input), temporary_(temporary) { }
+  explicit LJSArrayLength(LOperand* input) : LUnaryOperation(input) { }
 
-  LOperand* temporary() const { return temporary_; }
+  DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
+  DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
+};
 
-  DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array-length")
-  DECLARE_HYDROGEN_ACCESSOR(ArrayLength)
 
- private:
-  LOperand* temporary_;
+class LFixedArrayLength: public LUnaryOperation {
+ public:
+  explicit LFixedArrayLength(LOperand* input) : LUnaryOperation(input) { }
+
+  DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
+  DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
 };