Fix setting array length to zero for slow elements.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Sep 2012 11:52:33 +0000 (11:52 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Sep 2012 11:52:33 +0000 (11:52 +0000)
R=verwaest@chromium.org
BUG=chromium:146910
TEST=mjsunit/regress/regress-crbug-146910

Review URL: https://codereview.chromium.org/10937026

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

src/elements.cc
test/mjsunit/regress/regress-crbug-146910.js [new file with mode: 0644]

index 4cb50a4..39686a2 100644 (file)
@@ -1268,7 +1268,30 @@ class DictionaryElementsAccessor
       JSArray* array,
       Object* length_object,
       uint32_t length) {
-    if (length == 0) {
+    Heap* heap = array->GetHeap();
+    int capacity = dict->Capacity();
+    uint32_t new_length = length;
+    uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
+    if (new_length < old_length) {
+      // Find last non-deletable element in range of elements to be
+      // deleted and adjust range accordingly.
+      for (int i = 0; i < capacity; i++) {
+        Object* key = dict->KeyAt(i);
+        if (key->IsNumber()) {
+          uint32_t number = static_cast<uint32_t>(key->Number());
+          if (new_length <= number && number < old_length) {
+            PropertyDetails details = dict->DetailsAt(i);
+            if (details.IsDontDelete()) new_length = number + 1;
+          }
+        }
+      }
+      if (new_length != length) {
+        MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
+        if (!maybe_object->To(&length_object)) return maybe_object;
+      }
+    }
+
+    if (new_length == 0) {
       // If the length of a slow array is reset to zero, we clear
       // the array and flush backing storage. This has the added
       // benefit that the array returns to fast mode.
@@ -1276,45 +1299,22 @@ class DictionaryElementsAccessor
       MaybeObject* maybe_obj = array->ResetElements();
       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
     } else {
-      uint32_t new_length = length;
-      uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
-      if (new_length < old_length) {
-        // Find last non-deletable element in range of elements to be
-        // deleted and adjust range accordingly.
-        Heap* heap = array->GetHeap();
-        int capacity = dict->Capacity();
-        for (int i = 0; i < capacity; i++) {
-          Object* key = dict->KeyAt(i);
-          if (key->IsNumber()) {
-            uint32_t number = static_cast<uint32_t>(key->Number());
-            if (new_length <= number && number < old_length) {
-              PropertyDetails details = dict->DetailsAt(i);
-              if (details.IsDontDelete()) new_length = number + 1;
-            }
+      // Remove elements that should be deleted.
+      int removed_entries = 0;
+      Object* the_hole_value = heap->the_hole_value();
+      for (int i = 0; i < capacity; i++) {
+        Object* key = dict->KeyAt(i);
+        if (key->IsNumber()) {
+          uint32_t number = static_cast<uint32_t>(key->Number());
+          if (new_length <= number && number < old_length) {
+            dict->SetEntry(i, the_hole_value, the_hole_value);
+            removed_entries++;
           }
         }
-        if (new_length != length) {
-          MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
-          if (!maybe_object->To(&length_object)) return maybe_object;
-        }
-
-        // Remove elements that should be deleted.
-        int removed_entries = 0;
-        Object* the_hole_value = heap->the_hole_value();
-        for (int i = 0; i < capacity; i++) {
-          Object* key = dict->KeyAt(i);
-          if (key->IsNumber()) {
-            uint32_t number = static_cast<uint32_t>(key->Number());
-            if (new_length <= number && number < old_length) {
-              dict->SetEntry(i, the_hole_value, the_hole_value);
-              removed_entries++;
-            }
-          }
-        }
-
-        // Update the number of elements.
-        dict->ElementsRemoved(removed_entries);
       }
+
+      // Update the number of elements.
+      dict->ElementsRemoved(removed_entries);
     }
     return length_object;
   }
diff --git a/test/mjsunit/regress/regress-crbug-146910.js b/test/mjsunit/regress/regress-crbug-146910.js
new file mode 100644 (file)
index 0000000..120f809
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var x = [];
+assertSame(0, x.length);
+assertSame(undefined, x[0]);
+
+Object.defineProperty(x, '0', { value: 7, configurable: false });
+assertSame(1, x.length);
+assertSame(7, x[0]);
+
+x.length = 0;
+assertSame(1, x.length);
+assertSame(7, x[0]);