Correctly working Array.length setter
authorLars Knoll <lars.knoll@digia.com>
Mon, 14 Jan 2013 16:41:53 +0000 (17:41 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Mon, 14 Jan 2013 21:11:46 +0000 (22:11 +0100)
The setter will remove elements from the array that
have an index larger then the new length, but only
if they are configurable.

Change-Id: Id9f09d5ab038aaba6ca1c93be608c46383e1f2a1
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
qmljs_objects.cpp
qv4array.cpp
qv4array.h
tests/TestExpectations

index f4ca55d..3ea7ede 100644 (file)
@@ -485,16 +485,18 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, Property
         PropertyDescriptor *lp = array.getLengthProperty();
         if (!lp->isWritable() || desc->type == PropertyDescriptor::Accessor || desc->isConfigurable() || desc->isEnumerable())
             goto reject;
+        bool succeeded = false;
         if (desc->type == PropertyDescriptor::Data) {
             bool ok;
             uint l = desc->value.asArrayLength(ctx, &ok);
             if (!ok)
                 ctx->throwRangeError(desc->value);
-            if (!array.setLength(l))
-                goto reject;
+            succeeded = array.setLength(l);
         }
         if (desc->writable == PropertyDescriptor::Disabled)
             lp->writable = PropertyDescriptor::Disabled;
+        if (!succeeded)
+            goto reject;
         return true;
     }
 
index ab6a18e..a190c78 100644 (file)
@@ -604,6 +604,52 @@ void Array::initSparse()
     }
 }
 
+bool Array::setLength(uint newLen) {
+    if (lengthProperty && !lengthProperty->isWritable())
+        return false;
+    uint oldLen = length();
+    bool ok = true;
+    if (newLen < oldLen) {
+        if (sparse) {
+            SparseArrayNode *begin = sparse->lowerBound(newLen);
+            SparseArrayNode *it = sparse->end()->previousNode();
+            while (1) {
+                PropertyDescriptor &pd = values[it->value];
+                if (pd.type != PropertyDescriptor::Generic && !pd.isConfigurable()) {
+                    ok = false;
+                    newLen = it->key() + 1;
+                    break;
+                }
+                pd.type = PropertyDescriptor::Generic;
+                pd.value.tag = Value::_Undefined_Type;
+                pd.value.int_32 = freeList;
+                freeList = it->value;
+                bool brk = (it == begin);
+                SparseArrayNode *prev = it->previousNode();
+                sparse->erase(it);
+                if (brk)
+                    break;
+                it = prev;
+            }
+        } else {
+            PropertyDescriptor *it = values.data() + offset + values.size();
+            const PropertyDescriptor *begin = values.constData() + offset + newLen;
+            while (--it >= begin) {
+                if (it->type != PropertyDescriptor::Generic && !it->isConfigurable()) {
+                    ok = false;
+                    newLen = it - values.data() + offset + 1;
+                    break;
+                }
+            }
+            values.resize(newLen);
+        }
+    } else {
+        if (newLen >= 0x100000)
+            initSparse();
+    }
+    setLengthUnchecked(newLen);
+    return ok;
+}
 
 }
 }
index 1957d2c..c36d4a9 100644 (file)
@@ -430,27 +430,7 @@ public:
     void initSparse();
 
     uint length() const { return len; }
-    bool setLength(uint l) {
-        if (lengthProperty && !lengthProperty->isWritable())
-            return false;
-        setLengthUnchecked(l);
-        if (len >= 0x100000)
-            initSparse();
-        if (sparse) {
-            SparseArrayNode *it = sparse->lowerBound(l);
-            while (it != sparse->end()) {
-                PropertyDescriptor &pd = values[it->value];
-                pd.type = PropertyDescriptor::Generic;
-                pd.value.tag = Value::_Undefined_Type;
-                pd.value.int_32 = freeList;
-                freeList = it->value;
-                it = sparse->erase(it);
-            }
-        } else if (values.size() > (int)len){
-            values.resize(len);
-        }
-        return true;
-    }
+    bool setLength(uint newLen);
 
     void setLengthProperty(PropertyDescriptor *pd) { lengthProperty = pd; }
     PropertyDescriptor *getLengthProperty() { return lengthProperty; }
@@ -631,6 +611,7 @@ public:
         setLengthUnchecked(len - 1);
     }
 
+    SparseArrayNode *sparseLowerBound(uint idx) { return sparse ? sparse->lowerBound(idx) : 0; }
     SparseArrayNode *sparseBegin() { return sparse ? sparse->begin() : 0; }
     SparseArrayNode *sparseEnd() { return sparse ? sparse->end() : 0; }
 
index 081d719..349066a 100644 (file)
@@ -825,17 +825,7 @@ S15.1.3.2_A5.3 failing
 15.2.3.6-3-94 failing
 15.2.3.6-4-108 failing
 15.2.3.6-4-111 failing
-15.2.3.6-4-116 failing
-15.2.3.6-4-117 failing
 15.2.3.6-4-163 failing
-15.2.3.6-4-168 failing
-15.2.3.6-4-169 failing
-15.2.3.6-4-170 failing
-15.2.3.6-4-172 failing
-15.2.3.6-4-173 failing
-15.2.3.6-4-174 failing
-15.2.3.6-4-176 failing
-15.2.3.6-4-177 failing
 15.2.3.6-4-188 failing
 15.2.3.6-4-189 failing
 15.2.3.6-4-20 failing
@@ -2985,11 +2975,3 @@ S15.4.4.13_A1_T2 failing
 15.4.4.20-9-c-i-6 failing
 15.4.4.21-8-b-iii-1-6 failing
 15.4.4.22-8-b-iii-1-6 failing
-
-15.4.4.16-7-b-16 failing
-15.4.4.17-7-b-16 failing
-15.4.4.18-7-b-16 failing
-15.4.4.19-8-b-16 failing
-15.4.4.20-9-b-16 failing
-15.4.4.21-9-b-29 failing
-15.4.4.22-9-b-16 failing
\ No newline at end of file