Add a SimpleArrayData class
authorLars Knoll <lars.knoll@digia.com>
Mon, 13 Jan 2014 08:09:14 +0000 (09:09 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Mon, 20 Jan 2014 20:14:31 +0000 (21:14 +0100)
This makes the ArrayData class 'pure virtual'. SimpleArrayData
now contains the implementation of simple arrays. This makes the
separation between simple and sparse arrays a lot cleaner.

It also allows us to move len and offset from the base class into
the SimpleArrayClass. This fixes some bugs where we accessed len
for sparse arrays leading to some buggy behavior.

Added a virtual length() method to ArrayData to query the highes
used index in the Array.

Change-Id: Iab2ba2a48ebe5b7031759eeb4ebe02b4d86233f0
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
14 files changed:
src/qml/jsruntime/qv4argumentsobject.cpp
src/qml/jsruntime/qv4arraydata.cpp
src/qml/jsruntime/qv4arraydata_p.h
src/qml/jsruntime/qv4arrayobject.cpp
src/qml/jsruntime/qv4jsonobject.cpp
src/qml/jsruntime/qv4object.cpp
src/qml/jsruntime/qv4object_p.h
src/qml/jsruntime/qv4objectproto.cpp
src/qml/jsruntime/qv4qobjectwrapper.cpp
src/qml/jsruntime/qv4regexpobject.cpp
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4serialize.cpp
src/qml/qml/qqmllocale.cpp
src/qml/qml/v8/qv8engine.cpp

index fccfd50..e23972d 100644 (file)
@@ -66,7 +66,6 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
 
         arrayReserve(context->callData->argc);
         arrayData->put(0, context->callData->args, context->callData->argc);
-        arrayData->setLength(context->callData->argc);
         fullyCreated = true;
     } else {
         hasAccessorProperty = 1;
@@ -103,7 +102,6 @@ void ArgumentsObject::fullyCreate()
     arrayData->put(numAccessors, context->callData->args + numAccessors, argCount - numAccessors);
     for (uint i = numAccessors; i < argCount; ++i)
         arrayData->setAttributes(i, Attr_Data);
-    arrayData->setLength(argCount);
 
     fullyCreated = true;
 }
index 09e9a7f..360aa8b 100644 (file)
 
 using namespace QV4;
 
-const ArrayVTable ArrayData::static_vtbl =
-{
-    ArrayData::Simple,
-    ArrayData::freeData,
-    ArrayData::reserve,
-    ArrayData::get,
-    ArrayData::put,
-    ArrayData::putArray,
-    ArrayData::del,
-    ArrayData::setAttribute,
-    ArrayData::attribute,
-    ArrayData::push_front,
-    ArrayData::pop_front,
-    ArrayData::truncate
+const ArrayVTable SimpleArrayData::static_vtbl =
+{
+    SimpleArrayData::Simple,
+    SimpleArrayData::freeData,
+    SimpleArrayData::reserve,
+    SimpleArrayData::get,
+    SimpleArrayData::put,
+    SimpleArrayData::putArray,
+    SimpleArrayData::del,
+    SimpleArrayData::setAttribute,
+    SimpleArrayData::attribute,
+    SimpleArrayData::push_front,
+    SimpleArrayData::pop_front,
+    SimpleArrayData::truncate,
+    SimpleArrayData::length
 };
 
 const ArrayVTable SparseArrayData::static_vtbl =
@@ -73,48 +74,51 @@ const ArrayVTable SparseArrayData::static_vtbl =
     SparseArrayData::attribute,
     SparseArrayData::push_front,
     SparseArrayData::pop_front,
-    SparseArrayData::truncate
+    SparseArrayData::truncate,
+    SparseArrayData::length
 };
 
 
-void ArrayData::getHeadRoom(ArrayData *d)
+void SimpleArrayData::getHeadRoom(ArrayData *d)
 {
-    Q_ASSERT(d);
-    Q_ASSERT(!d->offset);
-    d->offset = qMax(d->len >> 2, (uint)16);
-    SafeValue *newArray = new SafeValue[d->offset + d->alloc];
-    memcpy(newArray + d->offset, d->data, d->len*sizeof(SafeValue));
-    delete [] d->data;
-    d->data = newArray + d->offset;
-    if (d->attrs) {
-        PropertyAttributes *newAttrs = new PropertyAttributes[d->offset + d->alloc];
-        memcpy(newAttrs + d->offset, d->attrs, d->len*sizeof(PropertyAttributes));
-        delete [] d->attrs;
-        d->attrs = newAttrs + d->offset;
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    Q_ASSERT(dd);
+    Q_ASSERT(!dd->offset);
+    dd->offset = qMax(dd->len >> 2, (uint)16);
+    SafeValue *newArray = new SafeValue[dd->offset + dd->alloc];
+    memcpy(newArray + dd->offset, dd->data, dd->len*sizeof(SafeValue));
+    delete [] dd->data;
+    dd->data = newArray + dd->offset;
+    if (dd->attrs) {
+        PropertyAttributes *newAttrs = new PropertyAttributes[dd->offset + dd->alloc];
+        memcpy(newAttrs + dd->offset, dd->attrs, dd->len*sizeof(PropertyAttributes));
+        delete [] dd->attrs;
+        dd->attrs = newAttrs + dd->offset;
     }
 }
 
-void ArrayData::reserve(ArrayData *d, uint n)
+void SimpleArrayData::reserve(ArrayData *d, uint n)
 {
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
     if (n < 8)
         n = 8;
-    if (n <= d->alloc)
+    if (n <= dd->alloc)
         return;
 
-    d->alloc = qMax(n, 2*d->alloc);
-    SafeValue *newArrayData = new SafeValue[d->alloc + d->offset];
-    if (d->data) {
-        memcpy(newArrayData + d->offset, d->data, sizeof(SafeValue)*d->len);
-        delete [] (d->data - d->offset);
+    dd->alloc = qMax(n, 2*dd->alloc);
+    SafeValue *newArrayData = new SafeValue[dd->alloc + dd->offset];
+    if (dd->data) {
+        memcpy(newArrayData + dd->offset, dd->data, sizeof(SafeValue)*dd->len);
+        delete [] (dd->data - dd->offset);
     }
-    d->data = newArrayData + d->offset;
+    dd->data = newArrayData + dd->offset;
 
-    if (d->attrs) {
-        PropertyAttributes *newAttrs = new PropertyAttributes[d->alloc];
-        memcpy(newAttrs, d->attrs, sizeof(PropertyAttributes)*d->len);
-        delete [] (d->attrs - d->offset);
+    if (dd->attrs) {
+        PropertyAttributes *newAttrs = new PropertyAttributes[dd->alloc];
+        memcpy(newAttrs, dd->attrs, sizeof(PropertyAttributes)*dd->len);
+        delete [] (dd->attrs - dd->offset);
 
-        d->attrs = newAttrs;
+        dd->attrs = newAttrs;
     }
 }
 
@@ -123,125 +127,144 @@ void ArrayData::ensureAttributes()
     if (attrs)
         return;
 
-    if (type == Simple)
+    uint off = 0;
+    if (type == Simple) {
         type = Complex;
-    attrs = new PropertyAttributes[alloc + offset];
-    attrs += offset;
-    for (uint i = 0; i < len; ++i)
+        off = static_cast<SimpleArrayData *>(this)->offset;
+    }
+    attrs = new PropertyAttributes[alloc + off];
+    attrs += off;
+    for (uint i = 0; i < alloc; ++i)
         attrs[i] = Attr_Data;
 }
 
 
-void ArrayData::freeData(ArrayData *d)
+void SimpleArrayData::freeData(ArrayData *d)
 {
-    delete [] (d->data - d->offset);
-    if (d->attrs)
-        delete [] (d->attrs - d->offset);
-    delete d;
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    delete [] (dd->data - dd->offset);
+    if (dd->attrs)
+        delete [] (dd->attrs - dd->offset);
+    delete dd;
 }
 
-ReturnedValue ArrayData::get(const ArrayData *d, uint index)
+ReturnedValue SimpleArrayData::get(const ArrayData *d, uint index)
 {
-    if (index >= d->len)
+    const SimpleArrayData *dd = static_cast<const SimpleArrayData *>(d);
+    if (index >= dd->len)
         return Primitive::emptyValue().asReturnedValue();
-    return d->data[index].asReturnedValue();
+    return dd->data[index].asReturnedValue();
 }
 
-bool ArrayData::put(ArrayData *d, uint index, ValueRef value)
+bool SimpleArrayData::put(ArrayData *d, uint index, ValueRef value)
 {
-    Q_ASSERT(index >= d->len || !d->attrs || !d->attrs[index].isAccessor());
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor());
     // ### honour attributes
-    d->data[index] = value;
-    if (index >= d->len) {
-        if (d->attrs)
-            d->attrs[index] = Attr_Data;
-        d->len = index;
+    dd->data[index] = value;
+    if (index >= dd->len) {
+        if (dd->attrs)
+            dd->attrs[index] = Attr_Data;
+        dd->len = index + 1;
     }
     return true;
 }
 
-bool ArrayData::del(ArrayData *d, uint index)
+bool SimpleArrayData::del(ArrayData *d, uint index)
 {
-    if (index >= d->len)
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    if (index >= dd->len)
         return true;
 
-    if (!d->attrs || d->attrs[index].isConfigurable()) {
-        d->data[index] = Primitive::emptyValue();
-        if (d->attrs)
-            d->attrs[index] = Attr_Data;
+    if (!dd->attrs || dd->attrs[index].isConfigurable()) {
+        dd->data[index] = Primitive::emptyValue();
+        if (dd->attrs)
+            dd->attrs[index] = Attr_Data;
         return true;
     }
-    if (d->data[index].isEmpty())
+    if (dd->data[index].isEmpty())
         return true;
     return false;
 }
 
-void ArrayData::setAttribute(ArrayData *d, uint index, PropertyAttributes attrs)
+void SimpleArrayData::setAttribute(ArrayData *d, uint index, PropertyAttributes attrs)
 {
     d->attrs[index] = attrs;
 }
 
-PropertyAttributes ArrayData::attribute(const ArrayData *d, uint index)
+PropertyAttributes SimpleArrayData::attribute(const ArrayData *d, uint index)
 {
     return d->attrs[index];
 }
 
-void ArrayData::push_front(ArrayData *d, SafeValue *values, uint n)
+void SimpleArrayData::push_front(ArrayData *d, SafeValue *values, uint n)
 {
-    Q_ASSERT(!d->attrs);
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    Q_ASSERT(!dd->attrs);
     for (int i = n - 1; i >= 0; --i) {
-        if (!d->offset)
-            ArrayData::getHeadRoom(d);
-
-        --d->offset;
-        --d->data;
-        ++d->len;
-        ++d->alloc;
-        *d->data = values[i].asReturnedValue();
+        if (!dd->offset)
+            getHeadRoom(dd);
+
+        --dd->offset;
+        --dd->data;
+        ++dd->len;
+        ++dd->alloc;
+        *dd->data = values[i].asReturnedValue();
     }
 
 }
 
-ReturnedValue ArrayData::pop_front(ArrayData *d)
+ReturnedValue SimpleArrayData::pop_front(ArrayData *d)
 {
-    Q_ASSERT(!d->attrs);
-    if (!d->len)
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    Q_ASSERT(!dd->attrs);
+    if (!dd->len)
         return Encode::undefined();
 
-    ReturnedValue v = d->data[0].isEmpty() ? Encode::undefined() : d->data[0].asReturnedValue();
-    ++d->offset;
-    ++d->data;
-    --d->len;
-    --d->alloc;
+    ReturnedValue v = dd->data[0].isEmpty() ? Encode::undefined() : dd->data[0].asReturnedValue();
+    ++dd->offset;
+    ++dd->data;
+    --dd->len;
+    --dd->alloc;
     return v;
 }
 
-uint ArrayData::truncate(ArrayData *d, uint newLen)
+uint SimpleArrayData::truncate(ArrayData *d, uint newLen)
 {
-    if (d->attrs) {
-        SafeValue *it = d->data + d->len;
-        const SafeValue *begin = d->data + newLen;
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    if (dd->len < newLen)
+        return newLen;
+
+    if (dd->attrs) {
+        SafeValue *it = dd->data + dd->len;
+        const SafeValue *begin = dd->data + newLen;
         while (--it >= begin) {
-            if (!it->isEmpty() && !d->attrs[it - d->data].isConfigurable()) {
-                newLen = it - d->data + 1;
+            if (!it->isEmpty() && !dd->attrs[it - dd->data].isConfigurable()) {
+                newLen = it - dd->data + 1;
                 break;
             }
             *it = Primitive::emptyValue();
         }
     }
-    d->len = newLen;
+    dd->len = newLen;
     return newLen;
 }
 
-bool ArrayData::putArray(ArrayData *d, uint index, SafeValue *values, uint n)
+uint SimpleArrayData::length(const ArrayData *d)
+{
+    return static_cast<const SimpleArrayData *>(d)->len;
+}
+
+bool SimpleArrayData::putArray(ArrayData *d, uint index, SafeValue *values, uint n)
 {
-    if (index + n > d->alloc)
-        reserve(d, index + n + 1);
-    for (uint i = d->len; i < index; ++i)
-        d->data[i] = Primitive::emptyValue();
+    SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
+    if (index + n > dd->alloc)
+        reserve(dd, index + n + 1);
+    for (uint i = dd->len; i < index; ++i)
+        dd->data[i] = Primitive::emptyValue();
     for (uint i = 0; i < n; ++i)
-        d->data[index + i] = values[i];
-    d->len = qMax(d->len, index + n);
+        dd->data[index + i] = values[i];
+    dd->len = qMax(dd->len, index + n);
     return true;
 }
 
@@ -269,7 +292,10 @@ void SparseArrayData::free(ArrayData *d, uint idx)
 void SparseArrayData::freeData(ArrayData *d)
 {
     delete static_cast<SparseArrayData *>(d)->sparse;
-    ArrayData::freeData(d);
+    delete [] d->data;
+    if (d->attrs)
+        delete [] d->attrs;
+    delete d;
 }
 
 void SparseArrayData::reserve(ArrayData *d, uint n)
@@ -281,18 +307,16 @@ void SparseArrayData::reserve(ArrayData *d, uint n)
 
     SparseArrayData *dd = static_cast<SparseArrayData *>(d);
     uint oldAlloc = dd->alloc;
-    // ### FIXME
-    dd->len = dd->alloc;
     dd->alloc = qMax(n, 2*dd->alloc);
     SafeValue *newArrayData = new SafeValue[dd->alloc];
     if (dd->data) {
-        memcpy(newArrayData, dd->data, sizeof(SafeValue)*dd->len);
+        memcpy(newArrayData, dd->data, sizeof(SafeValue)*oldAlloc);
         delete [] dd->data;
     }
     dd->data = newArrayData;
     if (dd->attrs) {
         PropertyAttributes *newAttrs = new PropertyAttributes[dd->alloc];
-        memcpy(newAttrs, dd->attrs, sizeof(PropertyAttributes)*dd->len);
+        memcpy(newAttrs, dd->attrs, sizeof(PropertyAttributes)*oldAlloc);
         delete [] dd->attrs;
         dd->attrs = newAttrs;
     }
@@ -460,66 +484,54 @@ uint SparseArrayData::truncate(ArrayData *d, uint newLen)
     return newLen;
 }
 
+uint SparseArrayData::length(const ArrayData *d)
+{
+    const SparseArrayData *dd = static_cast<const SparseArrayData *>(d);
+    if (!dd->sparse)
+        return 0;
+    SparseArrayNode *n = dd->sparse->end();
+    n = n->previousNode();
+    return n ? n->key() + 1 : 0;
+}
+
 bool SparseArrayData::putArray(ArrayData *d, uint index, SafeValue *values, uint n)
 {
     for (uint i = 0; i < n; ++i)
         put(d, index + i, values[i]);
-    d->len = qMax(d->len, index + n);
     return true;
 }
 
 
-uint ArrayData::append(Object *o, const ArrayObject *otherObj, uint n)
+uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n)
 {
-    ArrayData *d = o->arrayData;
+    Q_ASSERT(!obj->arrayData->hasAttributes());
+
     if (!n)
-        return o->getLength();
+        return obj->getLength();
 
     const ArrayData *other = otherObj->arrayData;
 
-    if (other->isSparse()) {
-        o->initSparseArray();
-        d = o->arrayData;
-    }
+    if (other->isSparse())
+        obj->initSparseArray();
 
-    uint oldSize = o->getLength();
-
-    // ### copy attributes as well!
-    if (d->type == ArrayData::Sparse) {
-        if (other->isSparse()) {
-            if (otherObj->hasAccessorProperty && other->hasAttributes()) {
-                for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin();
-                     it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode())
-                    o->arraySet(oldSize + it->key(), *reinterpret_cast<Property *>(other->data + it->value), other->attrs[it->value]);
-            } else {
-                for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin();
-                     it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode())
-                    o->arraySet(oldSize + it->key(), other->data[it->value]);
-            }
-        } else {
-            d->put(oldSize, other->data, n);
-        }
-    } else if (other->length()) {
-        d->vtable->reserve(d, oldSize + other->length());
-        if (oldSize > d->len) {
-            for (uint i = d->len; i < oldSize; ++i)
-                d->data[i] = Primitive::emptyValue();
-        }
-        if (other->attrs) {
-            for (uint i = 0; i < other->len; ++i) {
-                bool exists;
-                d->data[oldSize + i] = const_cast<ArrayObject *>(otherObj)->getIndexed(i, &exists);
-                d->len = oldSize + i + 1;
-                o->arrayData->setAttributes(oldSize + i, Attr_Data);
-                if (!exists)
-                    d->data[oldSize + i] = Primitive::emptyValue();
+    uint oldSize = obj->getLength();
+
+    if (other->isSparse()) {
+        if (otherObj->hasAccessorProperty && other->hasAttributes()) {
+            Scope scope(obj->engine());
+            ScopedValue v(scope);
+            for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin();
+                 it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode()) {
+                v = otherObj->getValue(reinterpret_cast<Property *>(other->data + it->value), other->attrs[it->value]);
+                obj->arraySet(oldSize + it->key(), v);
             }
         } else {
-            d->len = oldSize + other->len;
-            memcpy(d->data + oldSize, other->data, other->len*sizeof(Property));
-            if (d->attrs)
-                std::fill(d->attrs + oldSize, d->attrs + oldSize + other->len, PropertyAttributes(Attr_Data));
+            for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin();
+                 it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode())
+                obj->arraySet(oldSize + it->key(), other->data[it->value]);
         }
+    } else {
+        obj->arrayData->put(oldSize, other->data, n);
     }
 
     return oldSize + n;
@@ -527,31 +539,34 @@ uint ArrayData::append(Object *o, const ArrayObject *otherObj, uint n)
 
 Property *ArrayData::insert(Object *o, uint index, bool isAccessor)
 {
-    Property *pd;
-    if (o->arrayData->type != ArrayData::Sparse && (index < 0x1000 || index < o->arrayData->len + (o->arrayData->len >> 2))) {
-        Q_ASSERT(!isAccessor);
-        if (index >= o->arrayData->alloc)
-            o->arrayReserve(index + 1);
-        if (index >= o->arrayData->len) {
-            // mark possible hole in the array
-            for (uint i = o->arrayData->len; i < index; ++i)
-                o->arrayData->data[i] = Primitive::emptyValue();
-            o->arrayData->len = index + 1;
+    if (!isAccessor && o->arrayData->type != ArrayData::Sparse) {
+        SimpleArrayData *d = static_cast<SimpleArrayData *>(o->arrayData);
+        if (index < 0x1000 || index < d->len + (d->len >> 2)) {
+            if (index >= o->arrayData->alloc) {
+                o->arrayReserve(index + 1);
+                d = static_cast<SimpleArrayData *>(o->arrayData);
+            }
+            if (index >= d->len) {
+                // mark possible hole in the array
+                for (uint i = d->len; i < index; ++i)
+                    d->data[i] = Primitive::emptyValue();
+                d->len = index + 1;
+            }
+            return reinterpret_cast<Property *>(o->arrayData->data + index);
         }
-        pd = reinterpret_cast<Property *>(o->arrayData->data + index);
-    } else {
-        o->initSparseArray();
-        SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index);
-        if (n->value == UINT_MAX)
-            n->value = SparseArrayData::allocate(o->arrayData, isAccessor);
-        pd = reinterpret_cast<Property *>(o->arrayData->data + n->value);
     }
-    return pd;
+
+    o->initSparseArray();
+    SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index);
+    if (n->value == UINT_MAX)
+        n->value = SparseArrayData::allocate(o->arrayData, isAccessor);
+    return reinterpret_cast<Property *>(o->arrayData->data + n->value);
 }
 
 void ArrayData::markObjects(ExecutionEngine *e)
 {
-    for (uint i = 0; i < len; ++i)
+    uint l = (type == Simple) ? static_cast<SimpleArrayData *>(this)->len : alloc;
+    for (uint i = 0; i < l; ++i)
         data[i].mark(e);
 }
 
@@ -560,8 +575,7 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
     if (!len)
         return;
 
-    ArrayData *d = thisObject->arrayData;
-    if (!d || (!d->len && d->type != ArrayData::Sparse))
+    if (!thisObject->arrayData->length())
         return;
 
     if (!(comparefn->isUndefined() || comparefn->asObject())) {
@@ -572,16 +586,16 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
     // The spec says the sorting goes through a series of get,put and delete operations.
     // this implies that the attributes don't get sorted around.
 
-    if (d->type == ArrayData::Sparse) {
+    if (thisObject->arrayData->type == ArrayData::Sparse) {
         // since we sort anyway, we can simply iterate over the entries in the sparse
         // array and append them one by one to a regular one.
-        SparseArrayData *sparse = static_cast<SparseArrayData *>(d);
+        SparseArrayData *sparse = static_cast<SparseArrayData *>(thisObject->arrayData);
 
         if (!sparse->sparse->nEntries())
             return;
 
-        thisObject->arrayData = new ArrayData;
-        d = thisObject->arrayData;
+        SimpleArrayData *d = new SimpleArrayData;
+        thisObject->arrayData = d;
         d->vtable->reserve(d, sparse->sparse->nEntries());
 
         SparseArrayNode *n = sparse->sparse->begin();
@@ -614,7 +628,6 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
         if (n != sparse->sparse->end()) {
             // have some entries outside the sort range that we need to ignore when sorting
             thisObject->initSparseArray();
-            d = thisObject->arrayData;
             while (n != sparse->sparse->end()) {
                 PropertyAttributes a = sparse->attrs ? sparse->attrs[n->value] : Attr_Data;
                 thisObject->arraySet(n->value, *reinterpret_cast<Property *>(sparse->data + n->value), a);
@@ -626,18 +639,19 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
 
         sparse->ArrayData::free();
     } else {
+        SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData);
         if (len > d->len)
             len = d->len;
 
         // sort empty values to the end
         for (uint i = 0; i < len; i++) {
-            if (d->data[i].isEmpty()) {
+            if (thisObject->arrayData->data[i].isEmpty()) {
                 while (--len > i)
-                    if (!d->data[len].isEmpty())
+                    if (!thisObject->arrayData->data[len].isEmpty())
                         break;
-                Q_ASSERT(!d->attrs || !d->attrs[len].isAccessor());
-                d->data[i] = d->data[len];
-                d->data[len] = Primitive::emptyValue();
+                Q_ASSERT(!thisObject->arrayData->attrs || !thisObject->arrayData->attrs[len].isAccessor());
+                thisObject->arrayData->data[i] = thisObject->arrayData->data[len];
+                thisObject->arrayData->data[len] = Primitive::emptyValue();
             }
         }
 
@@ -648,7 +662,7 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
 
     ArrayElementLessThan lessThan(context, thisObject, comparefn);
 
-    SafeValue *begin = d->data;
+    SafeValue *begin = thisObject->arrayData->data;
     std::sort(begin, begin + len, lessThan);
 
 #ifdef CHECK_SPARSE_ARRAYS
index 3e09010..f82b45c 100644 (file)
@@ -66,15 +66,14 @@ struct ArrayVTable
     void (*push_front)(ArrayData *d, SafeValue *values, uint n);
     ReturnedValue (*pop_front)(ArrayData *d);
     uint (*truncate)(ArrayData *d, uint newLen);
+    uint (*length)(const ArrayData *d);
 };
 
 
 struct Q_QML_EXPORT ArrayData
 {
     ArrayData()
-        : vtable(&static_vtbl)
-        , offset(0)
-        , len(0)
+        : vtable(0)
         , alloc(0)
         , type(0)
         , attrs(0)
@@ -90,8 +89,6 @@ struct Q_QML_EXPORT ArrayData
     };
 
     const ArrayVTable *vtable;
-    uint offset;
-    uint len;
     uint alloc;
     uint type;
     PropertyAttributes *attrs;
@@ -100,11 +97,9 @@ struct Q_QML_EXPORT ArrayData
     bool isSparse() const { return this && type == Sparse; }
 
     uint length() const {
-        return this ? len : 0;
-    }
-    void setLength(uint l) {
-        Q_ASSERT(this);
-        len = l;
+        if (!this)
+            return 0;
+        return vtable->length(this);
     }
 
     bool hasAttributes() const {
@@ -143,13 +138,13 @@ struct Q_QML_EXPORT ArrayData
     }
     inline uint push_back(uint l, uint n, SafeValue *values) {
         vtable->putArray(this, l, values, n);
-        return len;
+        return length();
     }
     inline bool deleteIndex(uint index) {
         return vtable->del(this, index);
     }
     inline uint truncate(uint newLen) {
-        if (!this || len < newLen)
+        if (!this)
             return newLen;
         return vtable->truncate(this, newLen);
     }
@@ -166,13 +161,24 @@ struct Q_QML_EXPORT ArrayData
     }
     inline Property *getProperty(uint index) const;
 
-
-
     static void sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint dataLen);
-    static uint append(Object *o, const ArrayObject *otherObj, uint n);
+    static uint append(Object *obj, const ArrayObject *otherObj, uint n);
     static Property *insert(Object *o, uint index, bool isAccessor = false);
     void markObjects(ExecutionEngine *e);
 
+};
+
+struct Q_QML_EXPORT SimpleArrayData : public ArrayData
+{
+    SimpleArrayData()
+        : ArrayData()
+        , len(0)
+        , offset(0)
+    { vtable = &static_vtbl; }
+
+    uint len;
+    uint offset;
+
     static void getHeadRoom(ArrayData *d);
     static void reserve(ArrayData *d, uint n);
 
@@ -186,8 +192,10 @@ struct Q_QML_EXPORT ArrayData
     static void push_front(ArrayData *d, SafeValue *values, uint n);
     static ReturnedValue pop_front(ArrayData *d);
     static uint truncate(ArrayData *d, uint newLen);
+    static uint length(const ArrayData *d);
 
     static const ArrayVTable static_vtbl;
+
 };
 
 struct Q_QML_EXPORT SparseArrayData : public ArrayData
@@ -214,6 +222,7 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
     static void push_front(ArrayData *d, SafeValue *values, uint n);
     static ReturnedValue pop_front(ArrayData *d);
     static uint truncate(ArrayData *d, uint newLen);
+    static uint length(const ArrayData *d);
 
     static const ArrayVTable static_vtbl;
 };
@@ -224,7 +233,8 @@ inline Property *ArrayData::getProperty(uint index) const
     if (!this)
         return 0;
     if (type != Sparse) {
-        if (index >= len || data[index].isEmpty())
+        const SimpleArrayData *that = static_cast<const SimpleArrayData *>(this);
+        if (index >= that->len || data[index].isEmpty())
             return 0;
         return reinterpret_cast<Property *>(data + index);
     } else {
index 4ea979d..b79e4b1 100644 (file)
@@ -73,7 +73,6 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData)
         len = callData->argc;
         a->arrayReserve(len);
         a->arrayData->put(0, callData->args, len);
-        a->arrayData->setLength(len);
     }
     a->setArrayLengthUnchecked(len);
 
@@ -303,7 +302,9 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
         return Encode(newLen);
     }
 
-    if (!instance->protoHasArray() && instance->arrayData->length() <= len) {
+    if (!ctx->callData->argc) {
+        ;
+    } else if (!instance->protoHasArray() && instance->arrayData->length() <= len) {
         len = instance->arrayData->push_back(len, ctx->callData->argc, ctx->callData->args);
     } else {
         for (int i = 0; i < ctx->callData->argc; ++i)
@@ -483,10 +484,8 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
         v = instance->getIndexed(start + i, &exists);
         if (scope.hasException())
             return Encode::undefined();
-        if (exists) {
+        if (exists)
             newArray->arrayData->put(i, v);
-            newArray->arrayData->setLength(i + 1);
-        }
     }
     newArray->setArrayLengthUnchecked(deleteCount);
 
index f40c765..facc2da 100644 (file)
@@ -1057,10 +1057,8 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso
     Scoped<ArrayObject> a(scope, engine->newArrayObject());
     a->arrayReserve(size);
     ScopedValue v(scope);
-    for (int i = 0; i < size; i++) {
+    for (int i = 0; i < size; i++)
         a->arrayData->put(i, (v = fromJsonValue(engine, array.at(i))));
-        a->arrayData->setLength(i + 1);
-    }
     a->setArrayLengthUnchecked(size);
     return a.asReturnedValue();
 }
index f3a4b8a..5c6a648 100644 (file)
@@ -1091,9 +1091,12 @@ void Object::copyArrayData(Object *other)
         ;
     } else if (other->hasAccessorProperty && other->arrayData->attrs && other->arrayData->isSparse()){
         // do it the slow way
+        ScopedValue v(scope);
         for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other->arrayData)->sparse->begin();
-             it != static_cast<const SparseArrayData *>(other->arrayData)->sparse->end(); it = it->nextNode())
-            arraySet(it->key(), *reinterpret_cast<Property *>(other->arrayData->data + it->value), other->arrayData->attrs[it->value]);
+             it != static_cast<const SparseArrayData *>(other->arrayData)->sparse->end(); it = it->nextNode()) {
+            v = other->getValue(reinterpret_cast<Property *>(other->arrayData->data + it->value), other->arrayData->attrs[it->value]);
+            arraySet(it->key(), v);
+        }
     } else {
         Q_ASSERT(!arrayData && other->arrayData);
         if (other->arrayType() == ArrayData::Sparse) {
@@ -1103,13 +1106,15 @@ void Object::copyArrayData(Object *other)
             dd->sparse = new SparseArray(*od->sparse);
             dd->freeList = od->freeList;
             arrayData = dd;
-            other->arrayData->len = other->arrayData->alloc;
         }
-        arrayReserve(other->arrayData->len);
-        arrayData->len = other->arrayData->len;
-        memcpy(arrayData->data, other->arrayData->data, arrayData->len*sizeof(SafeValue));
+        arrayReserve(other->arrayData->alloc);
+        if (other->arrayType() != ArrayData::Sparse) {
+            SimpleArrayData *d = static_cast<SimpleArrayData *>(arrayData);
+            d->len = static_cast<SimpleArrayData *>(other->arrayData)->len;
+            d->offset = 0;
+        }
+        memcpy(arrayData->data, other->arrayData->data, arrayData->alloc*sizeof(SafeValue));
 
-        arrayData->offset = 0;
     }
     setArrayLengthUnchecked(other->getLength());
 }
@@ -1154,16 +1159,17 @@ void Object::initSparseArray()
         arrayData = data;
         return;
     }
-
-    uint oldOffset = arrayData->offset;
-    data->data = arrayData->data - arrayData->offset;
-    data->attrs = arrayData->attrs;
-    data->len = arrayData->len;
-    data->alloc = arrayData->alloc;
-    data->offset = 0;
-    arrayData->data = 0;
-    arrayData->attrs = 0;
-    delete arrayData;
+    SimpleArrayData *simple = static_cast<SimpleArrayData *>(arrayData);
+
+    uint oldOffset = simple->offset;
+    uint length = simple->ArrayData::length();
+    data->data = simple->data - simple->offset;
+    data->attrs = simple->attrs;
+    data->alloc = simple->alloc;
+    simple->data = 0;
+    simple->attrs = 0;
+    delete simple;
+    arrayData = data;
 
     uint *lastFree = &data->freeList;
     for (uint i = 0; i < oldOffset; ++i) {
@@ -1171,7 +1177,7 @@ void Object::initSparseArray()
         data->data[i].tag = Value::Empty_Type;
         lastFree = &data->data[i].uint_32;
     }
-    for (uint i = 0; i < data->len; ++i) {
+    for (uint i = 0; i < length; ++i) {
         if (!data->data[i + oldOffset].isEmpty()) {
             SparseArrayNode *n = data->sparse->insert(i);
             n->value = i + oldOffset;
@@ -1181,13 +1187,12 @@ void Object::initSparseArray()
             lastFree = &data->data[i + oldOffset].uint_32;
         }
     }
-    for (uint i = data->len + oldOffset; i < data->alloc; ++i) {
+    for (uint i = length + oldOffset; i < data->alloc; ++i) {
         *lastFree = i;
         data->data[i].tag = Value::Empty_Type;
         lastFree = &data->data[i].uint_32;
     }
     *lastFree = data->alloc;
-    arrayData = data;
 }
 
 
@@ -1207,10 +1212,8 @@ ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
     int len = list.count();
     arrayReserve(len);
     ScopedValue v(scope);
-    for (int ii = 0; ii < len; ++ii) {
+    for (int ii = 0; ii < len; ++ii)
         arrayData->put(ii, (v = engine->newString(list.at(ii))));
-        arrayData->setLength(ii + 1);
-    }
     setArrayLengthUnchecked(len);
 }
 
index de44d5c..7a2b3bb 100644 (file)
@@ -208,7 +208,7 @@ public:
 
     void arrayCreate() {
         if (!arrayData)
-            arrayData = new ArrayData;
+            arrayData = new SimpleArrayData;
 #ifdef CHECK_SPARSE_ARRAYS
         initSparseArray();
 #endif
@@ -346,7 +346,6 @@ inline void Object::push_back(const ValueRef v)
     uint idx = getLength();
     arrayReserve(idx + 1);
     arrayData->put(idx, v);
-    arrayData->setLength(idx + 1);
     setArrayLengthUnchecked(idx + 1);
 }
 
index 1096aa1..2eec96e 100644 (file)
@@ -274,7 +274,7 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
 
     if (o->arrayData) {
         o->arrayData->ensureAttributes();
-        for (uint i = 0; i < o->arrayData->length(); ++i) {
+        for (uint i = 0; i < o->arrayData->alloc; ++i) {
             if (!o->arrayData->isEmpty(i))
                 o->arrayData->attrs[i].setConfigurable(false);
         }
@@ -299,7 +299,7 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
 
     if (o->arrayData) {
         o->arrayData->ensureAttributes();
-        for (uint i = 0; i < o->arrayData->length(); ++i) {
+        for (uint i = 0; i < o->arrayData->alloc; ++i) {
             if (!o->arrayData->isEmpty(i))
                 o->arrayData->attrs[i].setConfigurable(false);
             if (o->arrayData->attrs[i].isData())
@@ -339,7 +339,7 @@ ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx)
     if (o->arrayData->length() && !o->arrayData->attrs)
         return Encode(false);
 
-    for (uint i = 0; i < o->arrayData->length(); ++i) {
+    for (uint i = 0; i < o->arrayData->alloc; ++i) {
         // ### Fix for sparse arrays
         if (!o->arrayData->isEmpty(i))
             if (o->arrayData->attributes(i).isConfigurable())
@@ -368,7 +368,7 @@ ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx)
     if (o->arrayData->length() && !o->arrayData->attrs)
         return Encode(false);
 
-    for (uint i = 0; i < o->arrayData->length(); ++i) {
+    for (uint i = 0; i < o->arrayData->alloc; ++i) {
         // ### Fix for sparse arrays
         if (!o->arrayData->isEmpty(i))
             if (o->arrayData->attributes(i).isConfigurable() || o->arrayData->attributes(i).isWritable())
index 17673fc..d68a699 100644 (file)
@@ -1687,10 +1687,8 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine)
         QV4::Scoped<ArrayObject> array(scope, v4->newArrayObject());
         array->arrayReserve(list.count());
         QV4::ScopedValue v(scope);
-        for (int ii = 0; ii < list.count(); ++ii) {
+        for (int ii = 0; ii < list.count(); ++ii)
             array->arrayData->put(ii, (v = QV4::QObjectWrapper::wrap(v4, list.at(ii))));
-            array->arrayData->setLength(ii + 1);
-        }
         array->setArrayLengthUnchecked(list.count());
         return array.asReturnedValue();
     } else if (type == qMetaTypeId<QQmlV4Handle>()) {
index 1b55c5a..2d92f12 100644 (file)
@@ -349,7 +349,6 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
         int end = matchOffsets[i * 2 + 1];
         v = (start != -1 && end != -1) ? ctx->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
         array->arrayData->put(i, v);
-        array->arrayData->setLength(i + 1);
     }
     array->setArrayLengthUnchecked(len);
 
index a8b4533..2f1b8a0 100644 (file)
@@ -613,7 +613,7 @@ void __qmljs_set_element(ExecutionContext *ctx, const ValueRef object, const Val
 
     uint idx = index->asArrayIndex();
     if (idx < UINT_MAX) {
-        if (idx < o->arrayData->length() && o->arrayType() == ArrayData::Simple)
+        if (o->arrayType() == ArrayData::Simple && idx < o->arrayData->length())
             o->arrayData->put(idx, value);
         else
             o->putIndexed(idx, value);
@@ -1105,7 +1105,6 @@ ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, SafeValue *val
 
     if (length) {
         a->arrayReserve(length);
-        a->arrayData->setLength(length);
         a->arrayData->put(0, values, length);
         a->setArrayLengthUnchecked(length);
     }
index 5f9e24d..dec0f69 100644 (file)
@@ -391,7 +391,6 @@ ReturnedValue Serialize::deserialize(const char *&data, QV8Engine *engine)
         for (quint32 ii = 0; ii < seqLength; ++ii) {
             value = deserialize(data, engine);
             array->arrayData->put(ii, value);
-            array->arrayData->setLength(ii + 1);
         }
         array->setArrayLengthUnchecked(seqLength);
         QVariant seqVariant = QV4::SequencePrototype::toVariant(array, sequenceType, &succeeded);
index 625b3a3..29fa587 100644 (file)
@@ -498,7 +498,6 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
 
     QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
     result->arrayReserve(days.size());
-    result->arrayData->setLength(days.size());
     for (int i = 0; i < days.size(); ++i) {
         int day = days.at(i);
         if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
@@ -521,10 +520,8 @@ QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx)
     QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
     result->arrayReserve(langs.size());
     QV4::ScopedValue v(scope);
-    for (int i = 0; i < langs.size(); ++i) {
+    for (int i = 0; i < langs.size(); ++i)
         result->arrayData->put(i, (v = ctx->engine->newString(langs.at(i))));
-        result->arrayData->setLength(i + 1);
-    }
 
     result->setArrayLengthUnchecked(langs.size());
 
index aa3b7ee..35fc531 100644 (file)
@@ -197,10 +197,9 @@ static QV4::ReturnedValue arrayFromStringList(QV8Engine *engine, const QStringLi
     int len = list.count();
     a->arrayReserve(len);
     QV4::ScopedValue v(scope);
-    for (int ii = 0; ii < len; ++ii) {
+    for (int ii = 0; ii < len; ++ii)
         a->arrayData->put(ii, (v = QV4::Encode(e->newString(list.at(ii)))));
-        a->arrayData->setLength(ii + 1);
-    }
+
     a->setArrayLengthUnchecked(len);
     return a.asReturnedValue();
 }
@@ -213,10 +212,9 @@ static QV4::ReturnedValue arrayFromVariantList(QV8Engine *engine, const QVariant
     int len = list.count();
     a->arrayReserve(len);
     QV4::ScopedValue v(scope);
-    for (int ii = 0; ii < len; ++ii) {
+    for (int ii = 0; ii < len; ++ii)
         a->arrayData->put(ii, (v = engine->fromVariant(list.at(ii))));
-        a->arrayData->setLength(ii + 1);
-    }
+
     a->setArrayLengthUnchecked(len);
     return a.asReturnedValue();
 }
@@ -329,10 +327,8 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant)
             QV4::Scoped<QV4::ArrayObject> a(scope, m_v4Engine->newArrayObject());
             a->arrayReserve(list.count());
             QV4::ScopedValue v(scope);
-            for (int ii = 0; ii < list.count(); ++ii) {
+            for (int ii = 0; ii < list.count(); ++ii)
                 a->arrayData->put(ii, (v = QV4::QObjectWrapper::wrap(m_v4Engine, list.at(ii))));
-                a->arrayData->setLength(ii + 1);
-            }
             a->setArrayLengthUnchecked(list.count());
             return a.asReturnedValue();
         } else if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) {
@@ -547,10 +543,8 @@ QV4::ReturnedValue QV8Engine::variantListToJS(const QVariantList &lst)
     QV4::Scoped<QV4::ArrayObject> a(scope, m_v4Engine->newArrayObject());
     a->arrayReserve(lst.size());
     QV4::ScopedValue v(scope);
-    for (int i = 0; i < lst.size(); i++) {
+    for (int i = 0; i < lst.size(); i++)
         a->arrayData->put(i, (v = variantToJS(lst.at(i))));
-        a->arrayData->setLength(i + 1);
-    }
     a->setArrayLengthUnchecked(lst.size());
     return a.asReturnedValue();
 }