From c4bc5f1b24d49a94368dd47d966da94dcde81d4c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 14 Jan 2013 17:41:53 +0100 Subject: [PATCH] Correctly working Array.length setter 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 --- qmljs_objects.cpp | 6 ++++-- qv4array.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ qv4array.h | 23 ++--------------------- tests/TestExpectations | 18 ------------------ 4 files changed, 52 insertions(+), 41 deletions(-) diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp index f4ca55d..3ea7ede 100644 --- a/qmljs_objects.cpp +++ b/qmljs_objects.cpp @@ -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; } diff --git a/qv4array.cpp b/qv4array.cpp index ab6a18e..a190c78 100644 --- a/qv4array.cpp +++ b/qv4array.cpp @@ -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; +} } } diff --git a/qv4array.h b/qv4array.h index 1957d2c..c36d4a9 100644 --- a/qv4array.h +++ b/qv4array.h @@ -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; } diff --git a/tests/TestExpectations b/tests/TestExpectations index 081d719..349066a 100644 --- a/tests/TestExpectations +++ b/tests/TestExpectations @@ -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 -- 2.7.4