Reland 8636: Implement setting the length property for FixedDoubleArrays.
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Jul 2011 09:11:38 +0000 (09:11 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Jul 2011 09:11:38 +0000 (09:11 +0000)
R=ager@chromium.org
BUG=none
TEST=unboxed-double-arrays.js

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

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

src/objects-inl.h
src/objects.cc
src/objects.h
test/mjsunit/unbox-double-arrays.js

index e069b79..5726b37 100644 (file)
@@ -4007,7 +4007,8 @@ bool JSObject::HasIndexedInterceptor() {
 
 
 bool JSObject::AllowsSetElementsLength() {
-  bool result = elements()->IsFixedArray();
+  bool result = elements()->IsFixedArray() ||
+      elements()->IsFixedDoubleArray();
   ASSERT(result == !HasExternalArrayElements());
   return result;
 }
index 82ed15c..f25078b 100644 (file)
@@ -3206,7 +3206,7 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
     case FAST_DOUBLE_ELEMENTS: {
       int length = IsJSArray()
           ? Smi::cast(JSArray::cast(this)->length())->value()
-          : FixedArray::cast(elements())->length();
+          : FixedDoubleArray::cast(elements())->length();
       if (index < static_cast<uint32_t>(length)) {
         FixedDoubleArray::cast(elements())->set_the_hole(index);
       }
@@ -7626,32 +7626,57 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
   if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
     const int value = Smi::cast(smi_length)->value();
     if (value < 0) return ArrayLengthRangeError(GetHeap());
-    switch (GetElementsKind()) {
-      case FAST_ELEMENTS: {
-        int old_capacity = FixedArray::cast(elements())->length();
+    JSObject::ElementsKind elements_kind = GetElementsKind();
+    switch (elements_kind) {
+      case FAST_ELEMENTS:
+      case FAST_DOUBLE_ELEMENTS: {
+        int old_capacity = FixedArrayBase::cast(elements())->length();
         if (value <= old_capacity) {
           if (IsJSArray()) {
             Object* obj;
-            { MaybeObject* maybe_obj = EnsureWritableFastElements();
+            if (elements_kind == FAST_ELEMENTS) {
+              MaybeObject* maybe_obj = EnsureWritableFastElements();
               if (!maybe_obj->ToObject(&obj)) return maybe_obj;
             }
-            FixedArray* fast_elements = FixedArray::cast(elements());
             if (2 * value <= old_capacity) {
               // If more than half the elements won't be used, trim the array.
               if (value == 0) {
                 initialize_elements();
               } else {
-                fast_elements->set_length(value);
-                Address filler_start = fast_elements->address() +
-                                       FixedArray::OffsetOfElementAt(value);
-                int filler_size = (old_capacity - value) * kPointerSize;
+                Address filler_start;
+                int filler_size;
+                if (GetElementsKind() == FAST_ELEMENTS) {
+                  FixedArray* fast_elements = FixedArray::cast(elements());
+                  fast_elements->set_length(value);
+                  filler_start = fast_elements->address() +
+                      FixedArray::OffsetOfElementAt(value);
+                  filler_size = (old_capacity - value) * kPointerSize;
+                } else {
+                  ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+                  FixedDoubleArray* fast_double_elements =
+                      FixedDoubleArray::cast(elements());
+                  fast_double_elements->set_length(value);
+                  filler_start = fast_double_elements->address() +
+                      FixedDoubleArray::OffsetOfElementAt(value);
+                  filler_size = (old_capacity - value) * kDoubleSize;
+                }
                 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
               }
             } else {
               // Otherwise, fill the unused tail with holes.
               int old_length = FastD2I(JSArray::cast(this)->length()->Number());
-              for (int i = value; i < old_length; i++) {
-                fast_elements->set_the_hole(i);
+              if (GetElementsKind() == FAST_ELEMENTS) {
+                FixedArray* fast_elements = FixedArray::cast(elements());
+                for (int i = value; i < old_length; i++) {
+                  fast_elements->set_the_hole(i);
+                }
+              } else {
+                ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+                FixedDoubleArray* fast_double_elements =
+                    FixedDoubleArray::cast(elements());
+                for (int i = value; i < old_length; i++) {
+                  fast_double_elements->set_the_hole(i);
+                }
               }
             }
             JSArray::cast(this)->set_length(Smi::cast(smi_length));
@@ -7662,8 +7687,14 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
         int new_capacity = value > min ? value : min;
         if (new_capacity <= kMaxFastElementsLength ||
             !ShouldConvertToSlowElements(new_capacity)) {
-          MaybeObject* result =
-              SetFastElementsCapacityAndLength(new_capacity, value);
+          MaybeObject* result;
+          if (GetElementsKind() == FAST_ELEMENTS) {
+            result = SetFastElementsCapacityAndLength(new_capacity, value);
+          }  else {
+            ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+            result = SetFastDoubleElementsCapacityAndLength(new_capacity,
+                                                            value);
+          }
           if (result->IsFailure()) return result;
           return this;
         }
@@ -7699,7 +7730,6 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
       case EXTERNAL_FLOAT_ELEMENTS:
       case EXTERNAL_DOUBLE_ELEMENTS:
       case EXTERNAL_PIXEL_ELEMENTS:
-      case FAST_DOUBLE_ELEMENTS:
         UNREACHABLE();
         break;
     }
index 43747cc..9b55ea7 100644 (file)
@@ -2169,6 +2169,9 @@ class FixedDoubleArray: public FixedArrayBase {
     return kHeaderSize + length * kDoubleSize;
   }
 
+  // Code Generation support.
+  static int OffsetOfElementAt(int index) { return SizeFor(index); }
+
   inline static bool is_the_hole_nan(double value);
   inline static double hole_nan_as_double();
   inline static double canonical_not_the_hole_nan_as_double();
index 312955b..1149838 100644 (file)
@@ -28,8 +28,8 @@
 // Test dictionary -> double elements -> dictionary elements round trip
 
 // Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc
-var large_array_size = 500000;
-var approx_dict_to_elements_threshold = 69000;
+var large_array_size = 100000;
+var approx_dict_to_elements_threshold = 75000;
 
 var name = 0;
 
@@ -42,14 +42,21 @@ function expected_array_value(i) {
 }
 
 function force_to_fast_double_array(a) {
+  a[large_array_size - 2] = 1;
   for (var i= 0; i < approx_dict_to_elements_threshold; ++i ) {
     a[i] = expected_array_value(i);
   }
   assertTrue(%HasFastDoubleElements(a));
 }
 
+function make_object_like_array(size) {
+  obj = new Object();
+  obj.length = size;
+  return obj;
+}
+
 function testOneArrayType(allocator) {
-  var large_array = new allocator(500000);
+  var large_array = new allocator(large_array_size);
   force_to_fast_double_array(large_array);
   var six = 6;
 
@@ -319,35 +326,94 @@ function testOneArrayType(allocator) {
 
   // Make sure that we haven't converted from fast double.
   assertTrue(%HasFastDoubleElements(large_array));
-  // Cause the array to grow beyond it's JSArray length. This will double the
-  // size of the capacity and force the array into "slow" dictionary case.
-  large_array[large_array_size+1] = 50;
-  assertTrue(%HasDictionaryElements(large_array));
-  assertEquals(50, large_array[large_array_size+1]);
-  assertEquals(large_array_size+2, large_array.length);
-  assertEquals(Infinity, large_array[5]);
-  assertEquals(undefined, large_array[large_array_size-1]);
-  assertEquals(undefined, large_array[-1]);
-  assertEquals(large_array_size+2, large_array.length);
-
-  // Test dictionary -> double elements -> fast elements.
-  var large_array2 = new allocator(large_array_size);
-  force_to_fast_double_array(large_array2);
-  delete large_array2[5];
-
-  // Convert back to fast elements and make sure the contents of the array are
-  // unchanged.
-  large_array2[25] = new Object();
-  assertTrue(%HasFastElements(large_array2));
-  for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) {
-    if (i != 25 && i != 5) {
-      assertEquals(expected_array_value(i), large_array2[i]);
-    }
-  }
-  assertEquals(undefined, large_array2[5])
-      assertEquals(undefined, large_array2[large_array_size-1])
-      assertEquals(undefined, large_array2[-1])
-      assertEquals(large_array_size, large_array2.length);
 }
 
+testOneArrayType(make_object_like_array);
 testOneArrayType(Array);
+
+var large_array = new Array(large_array_size);
+force_to_fast_double_array(large_array);
+assertTrue(%HasFastDoubleElements(large_array));
+
+// Cause the array to grow beyond it's JSArray length. This will double the
+// size of the capacity and force the array into "slow" dictionary case.
+large_array[5] = Infinity;
+large_array[large_array_size+10001] = 50;
+assertTrue(%HasDictionaryElements(large_array));
+assertEquals(50, large_array[large_array_size+10001]);
+assertEquals(large_array_size+10002, large_array.length);
+assertEquals(Infinity, large_array[5]);
+assertEquals(undefined, large_array[large_array_size-1]);
+assertEquals(undefined, large_array[-1]);
+assertEquals(large_array_size+10002, large_array.length);
+
+// Test dictionary -> double elements -> fast elements.
+var large_array2 = new Array(large_array_size);
+force_to_fast_double_array(large_array2);
+delete large_array2[5];
+
+// Convert back to fast elements and make sure the contents of the array are
+// unchanged.
+large_array2[25] = new Object();
+assertTrue(%HasFastElements(large_array2));
+for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) {
+  if (i != 25 && i != 5) {
+    assertEquals(expected_array_value(i), large_array2[i]);
+  }
+}
+assertEquals(undefined, large_array2[5]);
+assertEquals(undefined, large_array2[large_array_size-1]);
+assertEquals(undefined, large_array2[-1]);
+assertEquals(large_array_size, large_array2.length);
+
+// Make sure it's possible to change the array's length and that array is still
+// intact after the resize.
+var large_array3 = new Array(large_array_size);
+force_to_fast_double_array(large_array3);
+large_array3.length = 60000;
+assertEquals(60000, large_array3.length);
+assertEquals(undefined, large_array3[60000]);
+assertTrue(%HasFastDoubleElements(large_array3));
+assertEquals(expected_array_value(5), large_array3[5]);
+assertEquals(expected_array_value(6), large_array3[6]);
+assertEquals(expected_array_value(7), large_array3[7]);
+assertEquals(expected_array_value(large_array3.length-1),
+             large_array3[large_array3.length-1]);
+assertEquals(undefined, large_array3[large_array_size-1]);
+assertEquals(undefined, large_array3[-1]);
+gc();
+
+for (var i= 0; i < large_array3.length; i += 501 ) {
+  assertEquals(expected_array_value(i), large_array3[i]);
+}
+
+large_array3.length = 25;
+assertEquals(25, large_array3.length);
+assertTrue(%HasFastDoubleElements(large_array3));
+assertEquals(undefined, large_array3[25]);
+assertEquals(expected_array_value(5), large_array3[5]);
+assertEquals(expected_array_value(6), large_array3[6]);
+assertEquals(expected_array_value(7), large_array3[7]);
+assertEquals(expected_array_value(large_array3.length-1),
+             large_array3[large_array3.length-1]);
+assertEquals(undefined, large_array3[large_array_size-1]);
+assertEquals(undefined, large_array3[-1]);
+gc();
+
+for (var i= 0; i < large_array3.length; ++i) {
+  assertEquals(expected_array_value(i), large_array3[i]);
+}
+
+large_array3.length = 100;
+assertEquals(100, large_array3.length);
+large_array3[95] = 95;
+assertTrue(%HasFastDoubleElements(large_array3));
+assertEquals(undefined, large_array3[100]);
+assertEquals(95, large_array3[95]);
+assertEquals(expected_array_value(5), large_array3[5]);
+assertEquals(expected_array_value(6), large_array3[6]);
+assertEquals(expected_array_value(7), large_array3[7]);
+assertEquals(undefined, large_array3[large_array3.length-1]);
+assertEquals(undefined, large_array3[large_array_size-1]);
+assertEquals(undefined, large_array3[-1]);
+gc();