Don't use a QVector to store the array data
authorLars Knoll <lars.knoll@digia.com>
Sun, 3 Feb 2013 21:08:39 +0000 (22:08 +0100)
committerErik Verbruggen <erik.verbruggen@digia.com>
Wed, 6 Feb 2013 14:47:30 +0000 (15:47 +0100)
Refactor the code to store the array data in a simple
C array. This will later on allow for direct inline
access to the data.

Change-Id: Ic829bf1a90abfcda27ab4291cb7d5721bbd58403
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
src/v4/qv4arrayobject.cpp
src/v4/qv4jsonobject.cpp
src/v4/qv4object.cpp
src/v4/qv4object.h
src/v4/qv4objectiterator.cpp

index 8f1fc21..bec7c22 100644 (file)
@@ -62,11 +62,14 @@ Value ArrayCtor::call(ExecutionContext *ctx)
             return Value::undefinedValue();
         }
 
+        if (len < 0x1000)
+            a->arrayReserve(len);
     } else {
         len = ctx->argumentCount;
-        for (unsigned int i = 0; i < len; ++i) {
-            a->arraySet(i, ctx->argument(i));
-        }
+        a->arrayReserve(len);
+        for (unsigned int i = 0; i < len; ++i)
+            fillDescriptor(a->arrayData + i, ctx->argument(i));
+        a->arrayDataLen = len;
     }
     a->setArrayLengthUnchecked(len);
 
@@ -138,14 +141,13 @@ Value ArrayPrototype::method_concat(ExecutionContext *ctx)
     }
 
     for (uint i = 0; i < ctx->argumentCount; ++i) {
-        quint32 k = result->arrayLength();
         Value arg = ctx->argument(i);
 
         if (ArrayObject *elt = arg.asArrayObject())
             result->arrayConcat(elt);
 
         else
-            result->arraySet(k, arg);
+            result->arraySet(getLength(ctx, result), arg);
     }
 
     return Value::fromObject(result);
@@ -252,25 +254,37 @@ Value ArrayPrototype::method_push(ExecutionContext *ctx)
     bool protoHasArray = false;
     Object *p = instance;
     while ((p = p->prototype))
-        if (p->arrayLength())
+        if (p->arrayDataLen)
             protoHasArray = true;
 
-    if (!protoHasArray && len == instance->arrayLength()) {
+    if (!protoHasArray && instance->arrayDataLen <= len) {
         for (uint i = 0; i < ctx->argumentCount; ++i) {
             Value v = ctx->argument(i);
-            instance->push_back(v);
+
+            if (!instance->sparseArray) {
+                if (len >= instance->arrayAlloc)
+                    instance->arrayReserve(len + 1);
+                fillDescriptor(instance->arrayData + len, v);
+                instance->arrayDataLen = len + 1;
+            } else {
+                uint i = instance->allocArrayValue(v);
+                instance->sparseArray->push_back(i, len);
+            }
+            ++len;
         }
     } else {
         for (uint i = 0; i < ctx->argumentCount; ++i)
             instance->__put__(ctx, len + i, ctx->argument(i));
+        len += ctx->argumentCount;
     }
-    uint newLen = len + ctx->argumentCount;
-    if (!instance->isArrayObject())
-        instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(newLen));
+    if (instance->isArrayObject())
+        instance->setArrayLengthUnchecked(len);
+    else
+        instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(len));
 
-    if (newLen < INT_MAX)
-        return Value::fromInt32(newLen);
-    return Value::fromDouble((double)newLen);
+    if (len < INT_MAX)
+        return Value::fromInt32(len);
+    return Value::fromDouble((double)len);
 
 }
 
@@ -313,11 +327,21 @@ Value ArrayPrototype::method_shift(ExecutionContext *ctx)
     bool protoHasArray = false;
     Object *p = instance;
     while ((p = p->prototype))
-        if (p->arrayLength())
+        if (p->arrayDataLen)
             protoHasArray = true;
 
-    if (!protoHasArray && len >= instance->arrayLength()) {
-        instance->pop_front();
+    if (!protoHasArray && instance->arrayDataLen <= len) {
+        if (!instance->sparseArray) {
+            if (instance->arrayDataLen) {
+                ++instance->arrayOffset;
+                ++instance->arrayData;
+                --instance->arrayDataLen;
+                --instance->arrayAlloc;
+            }
+        } else {
+            uint idx = instance->sparseArray->pop_front();
+            instance->freeArrayValue(idx);
+        }
     } else {
         // do it the slow way
         for (uint k = 1; k < len; ++k) {
@@ -331,7 +355,9 @@ Value ArrayPrototype::method_shift(ExecutionContext *ctx)
         instance->__delete__(ctx, len - 1);
     }
 
-    if (!instance->isArrayObject())
+    if (instance->isArrayObject())
+        instance->setArrayLengthUnchecked(len - 1);
+    else
         instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(len - 1));
     return result;
 }
@@ -365,8 +391,9 @@ Value ArrayPrototype::method_slice(ExecutionContext *ctx)
     for (uint i = start; i < end; ++i) {
         bool exists;
         Value v = o->__get__(ctx, i, &exists);
-        if (exists)
+        if (exists) {
             result->arraySet(n, v);
+        }
         ++n;
     }
     return Value::fromObject(result);
@@ -399,8 +426,8 @@ Value ArrayPrototype::method_splice(ExecutionContext *ctx)
 
     uint deleteCount = (uint)qMin(qMax(ctx->argument(1).toInteger(ctx), 0.), (double)(len - start));
 
-    newArray->arrayData.resize(deleteCount);
-    PropertyDescriptor *pd = newArray->arrayData.data();
+    newArray->arrayReserve(deleteCount);
+    PropertyDescriptor *pd = newArray->arrayData;
     for (uint i = 0; i < deleteCount; ++i) {
         pd->type = PropertyDescriptor::Data;
         pd->writable = PropertyDescriptor::Enabled;
@@ -409,6 +436,7 @@ Value ArrayPrototype::method_splice(ExecutionContext *ctx)
         pd->value = instance->__get__(ctx, start + i);
         ++pd;
     }
+    newArray->arrayDataLen = deleteCount;
     newArray->setArrayLengthUnchecked(deleteCount);
 
     uint itemCount = ctx->argumentCount < 2 ? 0 : ctx->argumentCount - 2;
@@ -454,13 +482,25 @@ Value ArrayPrototype::method_unshift(ExecutionContext *ctx)
     bool protoHasArray = false;
     Object *p = instance;
     while ((p = p->prototype))
-        if (p->arrayLength())
+        if (p->arrayDataLen)
             protoHasArray = true;
 
-    if (!protoHasArray && len >= instance->arrayLength()) {
+    if (!protoHasArray && instance->arrayDataLen <= len) {
         for (int i = ctx->argumentCount - 1; i >= 0; --i) {
             Value v = ctx->argument(i);
-            instance->push_front(v);
+
+            if (!instance->sparseArray) {
+                if (!instance->arrayOffset)
+                    instance->getArrayHeadRoom();
+
+                --instance->arrayOffset;
+                --instance->arrayData;
+                ++instance->arrayDataLen;
+                fillDescriptor(instance->arrayData, v);
+            } else {
+                uint idx = instance->allocArrayValue(v);
+                instance->sparseArray->push_front(idx);
+            }
         }
     } else {
         for (uint k = len; k > 0; --k) {
@@ -474,8 +514,11 @@ Value ArrayPrototype::method_unshift(ExecutionContext *ctx)
         for (uint i = 0; i < ctx->argumentCount; ++i)
             instance->__put__(ctx, i, ctx->argument(i));
     }
+
     uint newLen = len + ctx->argumentCount;
-    if (!instance->isArrayObject())
+    if (instance->isArrayObject())
+        instance->setArrayLengthUnchecked(newLen);
+    else
         instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(newLen));
 
     if (newLen < INT_MAX)
@@ -655,6 +698,7 @@ Value ArrayPrototype::method_map(ExecutionContext *ctx)
     Value thisArg = ctx->argument(1);
 
     ArrayObject *a = ctx->engine->newArrayObject(ctx);
+    a->arrayReserve(len);
     a->setArrayLengthUnchecked(len);
 
     for (uint k = 0; k < len; ++k) {
@@ -686,6 +730,7 @@ Value ArrayPrototype::method_filter(ExecutionContext *ctx)
     Value thisArg = ctx->argument(1);
 
     ArrayObject *a = ctx->engine->newArrayObject(ctx);
+    a->arrayReserve(len);
 
     uint to = 0;
     for (uint k = 0; k < len; ++k) {
index d30c10a..4bb6cd5 100644 (file)
@@ -897,7 +897,8 @@ Value JsonObject::method_stringify(ExecutionContext *ctx)
     if (o) {
         stringify.replacerFunction = o->asFunctionObject();
         if (o->isArrayObject()) {
-            for (uint i = 0; i < o->arrayLength(); ++i) {
+            uint arrayLen = o->arrayLength();
+            for (uint i = 0; i < arrayLen; ++i) {
                 Value v = o->__get__(ctx, i);
                 if (v.asNumberObject() || v.asStringObject() || v.isNumber())
                     v = __qmljs_to_string(v, ctx);
index 7ea8f3a..dda340b 100644 (file)
@@ -70,7 +70,8 @@ using namespace QQmlJS::VM;
 //
 Object::~Object()
 {
-    delete memberData;
+    delete [] memberData;
+    delete [] (arrayData - (sparseArray ? 0 : arrayOffset));
     delete sparseArray;
 }
 
@@ -217,7 +218,7 @@ PropertyDescriptor *Object::insertMember(String *s)
             memberDataAlloc = qMax((uint)8, 2*memberDataAlloc);
             PropertyDescriptor *newMemberData = new PropertyDescriptor[memberDataAlloc];
             memcpy(newMemberData, memberData, sizeof(PropertyDescriptor)*memberDataSize);
-            delete memberData;
+            delete [] memberData;
             memberData = newMemberData;
         }
         e->valueIndex = memberDataSize;
@@ -717,13 +718,16 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const QString &name, c
 
 void Object::copyArrayData(Object *other)
 {
-    arrayLen = other->arrayLen;
-    arrayData = other->arrayData;
-    arrayFreeList = other->arrayFreeList;
-    if (other->sparseArray)
+    arrayReserve(other->arrayDataLen);
+    arrayDataLen = other->arrayDataLen;
+    memcpy(arrayData, other->arrayData, arrayDataLen*sizeof(PropertyDescriptor));
+    arrayOffset = 0;
+    if (other->sparseArray) {
         sparseArray = new SparseArray(*other->sparseArray);
+        arrayFreeList = other->arrayFreeList;
+    }
     if (isArrayObject())
-        setArrayLengthUnchecked(arrayLen);
+        setArrayLengthUnchecked(other->arrayLength());
 }
 
 
@@ -732,7 +736,7 @@ Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionCont
     bool protoHasArray = false;
     Object *p = o;
     while ((p = p->prototype))
-        if (p->arrayLength())
+        if (p->arrayDataLen)
             protoHasArray = true;
 
     if (protoHasArray) {
@@ -744,23 +748,23 @@ Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionCont
                 return Value::fromDouble(i);
         }
     } else if (sparseArray) {
-        for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n && n->key() < endIndex; n = n->nextNode()) {
+        for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n != sparseArray->end() && n->key() < endIndex; n = n->nextNode()) {
             bool exists;
             Value value = o->getValueChecked(ctx, arrayDecriptor(n->value), &exists);
             if (exists && __qmljs_strict_equal(value, v))
                 return Value::fromDouble(n->key());
         }
     } else {
-        if ((int) endIndex > arrayData.size())
-            endIndex = arrayData.size();
-        PropertyDescriptor *pd = arrayData.data() + arrayOffset;
+        if ((int) endIndex > arrayDataLen)
+            endIndex = arrayDataLen;
+        PropertyDescriptor *pd = arrayData;
         PropertyDescriptor *end = pd + endIndex;
         pd += fromIndex;
         while (pd < end) {
             bool exists;
             Value value = o->getValueChecked(ctx, pd, &exists);
             if (exists && __qmljs_strict_equal(value, v))
-                return Value::fromDouble(pd - arrayOffset - arrayData.constData());
+                return Value::fromDouble(pd - arrayData);
             ++pd;
         }
     }
@@ -769,32 +773,43 @@ Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionCont
 
 void Object::arrayConcat(const ArrayObject *other)
 {
-    int newLen = arrayLen + other->arrayLength();
+    int newLen = arrayDataLen + other->arrayLength();
     if (other->sparseArray)
         initSparse();
     if (sparseArray) {
         if (other->sparseArray) {
             for (const SparseArrayNode *it = other->sparseArray->begin(); it != other->sparseArray->end(); it = it->nextNode())
-                arraySet(arrayLen + it->key(), other->arrayDecriptor(it->value));
+                arraySet(arrayDataLen + it->key(), other->arrayDecriptor(it->value));
         } else {
-            int oldSize = arrayData.size();
-            arrayData.resize(oldSize + other->arrayLength());
-            memcpy(arrayData.data() + oldSize, other->arrayData.constData() + other->arrayOffset, other->arrayLength()*sizeof(PropertyDescriptor));
+            int oldSize = arrayDataLen;
+            arrayReserve(oldSize + other->arrayLength());
+            memcpy(arrayData + oldSize, other->arrayData, other->arrayLength()*sizeof(PropertyDescriptor));
             for (uint i = 0; i < other->arrayLength(); ++i) {
-                SparseArrayNode *n = sparseArray->insert(arrayLen + i);
+                SparseArrayNode *n = sparseArray->insert(arrayDataLen + i);
                 n->value = oldSize + i;
             }
         }
     } else {
-        int oldSize = arrayData.size();
-        arrayData.resize(oldSize + other->arrayLength());
-        memcpy(arrayData.data() + oldSize, other->arrayData.constData() + other->arrayOffset, other->arrayLength()*sizeof(PropertyDescriptor));
+        int oldSize = arrayLength();
+        arrayReserve(oldSize + other->arrayDataLen);
+        if (oldSize > arrayDataLen) {
+            PropertyDescriptor generic;
+            generic.type = PropertyDescriptor::Generic;
+            generic.writable = PropertyDescriptor::Undefined;
+            generic.value = Value::undefinedValue();
+            std::fill(arrayData + arrayDataLen, arrayData + oldSize, generic);
+        }
+        arrayDataLen = oldSize + other->arrayDataLen;
+        memcpy(arrayData + oldSize, other->arrayData, other->arrayDataLen*sizeof(PropertyDescriptor));
     }
     setArrayLengthUnchecked(newLen);
 }
 
 void Object::arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint len)
 {
+    if (!arrayDataLen)
+        return;
+
     if (sparseArray) {
         context->throwUnimplemented("Object::sort unimplemented for sparse arrays");
         return;
@@ -802,9 +817,10 @@ void Object::arraySort(ExecutionContext *context, Object *thisObject, const Valu
     }
 
     ArrayElementLessThan lessThan(context, thisObject, comparefn);
-    if (len > arrayData.size() - arrayOffset)
-        len = arrayData.size() - arrayOffset;
-    PropertyDescriptor *begin = arrayData.begin() + arrayOffset;
+    if (len > arrayDataLen)
+        len = arrayDataLen;
+
+    PropertyDescriptor *begin = arrayData;
     std::sort(begin, begin + len, lessThan);
 }
 
@@ -813,36 +829,64 @@ void Object::initSparse()
 {
     if (!sparseArray) {
         sparseArray = new SparseArray;
-        for (int i = arrayOffset; i < arrayData.size(); ++i) {
-            SparseArrayNode *n = sparseArray->insert(i - arrayOffset);
-            n->value = i;
+        for (int i = 0; i < arrayDataLen; ++i) {
+            SparseArrayNode *n = sparseArray->insert(i);
+            n->value = i + arrayOffset;
         }
 
-        if (arrayOffset) {
-            int o = arrayOffset;
+        uint off = arrayOffset;
+        if (!arrayOffset) {
+            arrayFreeList = arrayDataLen;
+        } else {
+            arrayFreeList = 0;
+            arrayData -= off;
+            arrayAlloc += off;
+            int o = off;
             for (int i = 0; i < o - 1; ++i) {
                 arrayData[i].type = PropertyDescriptor::Generic;
                 arrayData[i].value = Value::fromInt32(i + 1);
             }
             arrayData[o - 1].type = PropertyDescriptor::Generic;
-            arrayData[o - 1].value = Value::fromInt32(arrayData.size());
-            arrayFreeList = 0;
-        } else {
-            arrayFreeList = arrayData.size();
+            arrayData[o - 1].value = Value::fromInt32(arrayDataLen + off);
+        }
+        for (int i = arrayDataLen + off; i < arrayAlloc; ++i) {
+            arrayData[i].type = PropertyDescriptor::Generic;
+            arrayData[i].value = Value::fromInt32(i + 1);
         }
     }
 }
 
-void Object::setArrayLengthUnchecked(uint l)
+void Object::arrayReserve(uint n)
 {
-    arrayLen = l;
-    if (isArrayObject()) {
-        // length is always the first property of an array
-        PropertyDescriptor &lengthProperty = memberData[ArrayObject::LengthPropertyIndex];
-        lengthProperty.value = Value::fromUInt32(l);
+    if (n < 8)
+        n = 8;
+    if (n >= arrayAlloc) {
+        uint off;
+        if (sparseArray) {
+            assert(arrayFreeList == arrayAlloc);
+            // ### FIXME
+            arrayDataLen = arrayAlloc;
+            off = 0;
+        } else {
+            off = arrayOffset;
+        }
+        arrayAlloc = qMax(n, 2*arrayAlloc);
+        PropertyDescriptor *newArrayData = new PropertyDescriptor[arrayAlloc];
+        memcpy(newArrayData, arrayData, sizeof(PropertyDescriptor)*arrayDataLen);
+        delete [] (arrayData - off);
+        arrayData = newArrayData;
+        if (sparseArray) {
+            for (uint i = arrayFreeList; i < arrayAlloc; ++i) {
+                arrayData[i].type = PropertyDescriptor::Generic;
+                arrayData[i].value = Value::fromInt32(i + 1);
+            }
+        } else {
+            arrayOffset = 0;
+        }
     }
 }
 
+
 bool Object::setArrayLength(uint newLen) {
     assert(isArrayObject());
     const PropertyDescriptor *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
@@ -853,36 +897,38 @@ bool Object::setArrayLength(uint newLen) {
     if (newLen < oldLen) {
         if (sparseArray) {
             SparseArrayNode *begin = sparseArray->lowerBound(newLen);
-            SparseArrayNode *it = sparseArray->end()->previousNode();
-            while (1) {
-                PropertyDescriptor &pd = arrayData[it->value];
-                if (pd.type != PropertyDescriptor::Generic && !pd.isConfigurable()) {
-                    ok = false;
-                    newLen = it->key() + 1;
-                    break;
+            if (begin != sparseArray->end()) {
+                SparseArrayNode *it = sparseArray->end()->previousNode();
+                while (1) {
+                    PropertyDescriptor &pd = arrayData[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 = arrayFreeList;
+                    arrayFreeList = it->value;
+                    bool brk = (it == begin);
+                    SparseArrayNode *prev = it->previousNode();
+                    sparseArray->erase(it);
+                    if (brk)
+                        break;
+                    it = prev;
                 }
-                pd.type = PropertyDescriptor::Generic;
-                pd.value.tag = Value::_Undefined_Type;
-                pd.value.int_32 = arrayFreeList;
-                arrayFreeList = it->value;
-                bool brk = (it == begin);
-                SparseArrayNode *prev = it->previousNode();
-                sparseArray->erase(it);
-                if (brk)
-                    break;
-                it = prev;
             }
         } else {
-            PropertyDescriptor *it = arrayData.data() + arrayData.size();
-            const PropertyDescriptor *begin = arrayData.constData() + arrayOffset + newLen;
+            PropertyDescriptor *it = arrayData + arrayDataLen;
+            const PropertyDescriptor *begin = arrayData + newLen;
             while (--it >= begin) {
                 if (it->type != PropertyDescriptor::Generic && !it->isConfigurable()) {
                     ok = false;
-                    newLen = it - arrayData.data() + arrayOffset + 1;
+                    newLen = it - arrayData + 1;
                     break;
                 }
             }
-            arrayData.resize(newLen + arrayOffset);
+            arrayDataLen = newLen;
         }
     } else {
         if (newLen >= 0x100000)
@@ -894,9 +940,8 @@ bool Object::setArrayLength(uint newLen) {
 
 void Object::markArrayObjects() const
 {
-    uint i = sparseArray ? 0 : arrayOffset;
-    for (; i < (uint)arrayData.size(); ++i) {
-        const PropertyDescriptor &pd = arrayData.at(i);
+    for (uint i = 0; i < arrayDataLen; ++i) {
+        const PropertyDescriptor &pd = arrayData[i];
         if (pd.isData()) {
             if (Managed *m = pd.value.asManaged())
                 m->mark();
index d481566..948948b 100644 (file)
@@ -107,18 +107,19 @@ struct Q_V4_EXPORT Object: Managed {
     uint memberDataAlloc;
     PropertyDescriptor *memberData;
 
-    uint arrayLen;
     union {
         uint arrayFreeList;
         uint arrayOffset;
     };
-    QVector<PropertyDescriptor> arrayData;
+    uint arrayDataLen;
+    uint arrayAlloc;
+    PropertyDescriptor *arrayData;
     SparseArray *sparseArray;
 
     Object()
         : prototype(0)
         , memberDataSize(0), memberDataAlloc(0), memberData(0)
-        , arrayLen(0), arrayOffset(0), sparseArray(0) { type = Type_Object; }
+        , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), sparseArray(0) { type = Type_Object; }
 
     virtual ~Object();
 
@@ -167,7 +168,7 @@ struct Q_V4_EXPORT Object: Managed {
 
     // Array handling
 
-    void fillDescriptor(PropertyDescriptor *pd, Value v)
+    static void fillDescriptor(PropertyDescriptor *pd, Value v)
     {
         pd->type = PropertyDescriptor::Data;
         pd->writable = PropertyDescriptor::Enabled;
@@ -178,10 +179,9 @@ struct Q_V4_EXPORT Object: Managed {
 
     uint allocArrayValue() {
         uint idx = arrayFreeList;
-        if (arrayData.size() <= (int)arrayFreeList)
-            arrayData.resize(++arrayFreeList);
-        else
-            arrayFreeList = arrayData.at(arrayFreeList).value.integerValue();
+        if (arrayAlloc <= arrayFreeList)
+            arrayReserve(arrayAlloc + 1);
+        arrayFreeList = arrayData[arrayFreeList].value.integerValue();
         return idx;
     }
 
@@ -200,44 +200,42 @@ struct Q_V4_EXPORT Object: Managed {
     }
 
     PropertyDescriptor *arrayDecriptor(uint index) {
-        PropertyDescriptor *pd = arrayData.data() + index;
-        if (!sparseArray)
-            pd += arrayOffset;
-        return pd;
+        return arrayData + index;
     }
     const PropertyDescriptor *arrayDecriptor(uint index) const {
-        const PropertyDescriptor *pd = arrayData.data() + index;
-        if (!sparseArray)
-            pd += arrayOffset;
-        return pd;
+        return arrayData + index;
     }
 
     void getArrayHeadRoom() {
         assert(!sparseArray && !arrayOffset);
-        arrayOffset = qMax(arrayData.size() >> 2, 16);
-        QVector<PropertyDescriptor> newValues(arrayData.size() + arrayOffset);
-        memcpy(newValues.data() + arrayOffset, arrayData.constData(), arrayData.size()*sizeof(PropertyDescriptor));
-        arrayData = newValues;
+        arrayOffset = qMax(arrayDataLen >> 2, (uint)16);
+        PropertyDescriptor *newArray = new PropertyDescriptor[arrayOffset + arrayAlloc];
+        memcpy(newArray + arrayOffset, arrayData, arrayDataLen*sizeof(PropertyDescriptor));
+        delete [] arrayData;
+        arrayData = newArray + arrayOffset;
     }
 
 public:
     void copyArrayData(Object *other);
     void initSparse();
 
-    uint arrayLength() const { return arrayLen; }
+    uint arrayLength() const;
     bool setArrayLength(uint newLen);
 
     void setArrayLengthUnchecked(uint l);
 
     PropertyDescriptor *arrayInsert(uint index) {
         PropertyDescriptor *pd;
-        if (!sparseArray && (index < 0x1000 || index < arrayLen + (arrayLen >> 2))) {
-            if (index + arrayOffset >= (uint)arrayData.size()) {
-                arrayData.resize(arrayOffset + index + 1);
-                for (uint i = arrayLen + 1; i < index; ++i) {
+        if (!sparseArray && (index < 0x1000 || index < arrayDataLen + (arrayDataLen >> 2))) {
+            if (index >= arrayAlloc)
+                arrayReserve(index + 1);
+            if (index >= arrayDataLen) {
+                for (uint i = arrayDataLen; i < index; ++i) {
                     arrayData[i].type = PropertyDescriptor::Generic;
+                    arrayData[i].writable = PropertyDescriptor::Undefined;
                     arrayData[i].value.tag = Value::_Undefined_Type;
                 }
+                arrayDataLen = index + 1;
             }
             pd = arrayDecriptor(index);
         } else {
@@ -247,7 +245,7 @@ public:
                 n->value = allocArrayValue();
             pd = arrayDecriptor(n->value);
         }
-        if (index >= arrayLen)
+        if (index >= arrayLength())
             setArrayLengthUnchecked(index + 1);
         return pd;
     }
@@ -262,10 +260,10 @@ public:
     }
 
     bool deleteArrayIndex(uint index) {
-        if (index >= arrayLen)
-            return true;
         PropertyDescriptor *pd = 0;
         if (!sparseArray) {
+            if (index >= arrayDataLen)
+                return true;
             pd = arrayAt(index);
         } else {
             SparseArrayNode *n = sparseArray->findNode(index);
@@ -277,80 +275,63 @@ public:
         if (!pd->isConfigurable())
             return false;
         pd->type = PropertyDescriptor::Generic;
-        pd->value.tag = Value::_Undefined_Type;
+        pd->value = Value::undefinedValue();
         if (sparseArray) {
             pd->value.int_32 = arrayFreeList;
-            arrayFreeList = pd - arrayData.constData();
+            arrayFreeList = pd - arrayData;
         }
         return true;
     }
 
     PropertyDescriptor *arrayAt(uint index) {
         if (!sparseArray) {
-            if (index >= arrayData.size() - arrayOffset)
+            if (index >= arrayDataLen)
                 return 0;
-            return arrayData.data() + index + arrayOffset;
+            return arrayData + index;
         } else {
             SparseArrayNode *n = sparseArray->findNode(index);
             if (!n)
                 return 0;
-            return arrayData.data() + n->value;
+            return arrayData + n->value;
         }
     }
 
     const PropertyDescriptor *nonSparseArrayAt(uint index) const {
         if (sparseArray)
             return 0;
-        index += arrayOffset;
-        if (index >= (uint)arrayData.size())
+        if (index >= arrayDataLen)
             return 0;
-        return arrayData.constData() + index;
+        return arrayData + index;
     }
 
     PropertyDescriptor *nonSparseArrayAtRef(uint index) {
         if (sparseArray)
             return 0;
-        index += arrayOffset;
-        if (index >= (uint)arrayData.size())
+        if (index >= arrayDataLen)
             return 0;
-        return arrayData.data() + index;
+        return arrayData + index;
     }
 
     const PropertyDescriptor *arrayAt(uint index) const {
         if (!sparseArray) {
-            if (index >= arrayData.size() - arrayOffset)
+            if (index >= arrayDataLen)
                 return 0;
-            return arrayData.constData() + index + arrayOffset;
+            return arrayData + index;
         } else {
             SparseArrayNode *n = sparseArray->findNode(index);
             if (!n)
                 return 0;
-            return arrayData.constData() + n->value;
+            return arrayData + n->value;
         }
     }
 
     void markArrayObjects() const;
 
-    void push_front(Value v) {
-        if (!sparseArray) {
-            if (!arrayOffset)
-                getArrayHeadRoom();
-
-            PropertyDescriptor pd;
-            fillDescriptor(&pd, v);
-            --arrayOffset;
-            arrayData[arrayOffset] = pd;
-        } else {
-            uint idx = allocArrayValue(v);
-            sparseArray->push_front(idx);
-        }
-        setArrayLengthUnchecked(arrayLen + 1);
-    }
     PropertyDescriptor *front() {
         PropertyDescriptor *pd = 0;
         if (!sparseArray) {
-            if (arrayLen)
-                pd = arrayData.data() + arrayOffset;
+            if (arrayDataLen)
+                pd = arrayData;
         } else {
             SparseArrayNode *n = sparseArray->findNode(0);
             if (n)
@@ -360,63 +341,28 @@ public:
             return 0;
         return pd;
     }
-    void pop_front() {
-        if (!arrayLen)
-            return;
-        if (!sparseArray) {
-            ++arrayOffset;
-        } else {
-            uint idx = sparseArray->pop_front();
-            freeArrayValue(idx);
-        }
-        setArrayLengthUnchecked(arrayLen - 1);
-    }
     void push_back(Value v) {
+        uint idx = arrayLength();
         if (!sparseArray) {
-            PropertyDescriptor pd;
-            fillDescriptor(&pd, v);
-            arrayData.append(pd);
+            if (idx >= arrayAlloc)
+                arrayReserve(idx + 1);
+            fillDescriptor(arrayData + idx, v);
+            arrayDataLen = idx + 1;
         } else {
             uint idx = allocArrayValue(v);
-            sparseArray->push_back(idx, arrayLen);
+            sparseArray->push_back(idx, arrayLength());
         }
-        setArrayLengthUnchecked(arrayLen + 1);
-    }
-    PropertyDescriptor *back() {
-        PropertyDescriptor *pd = 0;
-        if (!sparseArray) {
-            if (arrayLen)
-                pd = arrayData.data() + arrayOffset + arrayLen;
-        } else {
-            SparseArrayNode *n = sparseArray->findNode(arrayLen - 1);
-            if (n)
-                pd = arrayDecriptor(n->value);
-        }
-        if (pd && pd->type == PropertyDescriptor::Generic)
-            return 0;
-        return pd;
-    }
-    void pop_back() {
-        if (!arrayLen)
-            return;
-        if (!sparseArray) {
-            arrayData.resize(arrayData.size() - 1);
-        } else {
-            uint idx = sparseArray->pop_back(arrayLen);
-            if (idx != UINT_MAX)
-                freeArrayValue(idx);
-        }
-        setArrayLengthUnchecked(arrayLen - 1);
+        setArrayLengthUnchecked(idx + 1);
     }
 
-    SparseArrayNode *sparseArrayLowerBound(uint idx) { return sparseArray ? sparseArray->lowerBound(idx) : 0; }
     SparseArrayNode *sparseArrayBegin() { return sparseArray ? sparseArray->begin() : 0; }
     SparseArrayNode *sparseArrayEnd() { return sparseArray ? sparseArray->end() : 0; }
 
     void arrayConcat(const ArrayObject *other);
-    void arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint arrayLen);
-    Value arrayIndexOf(Value v, uint fromIndex, uint arrayLen, ExecutionContext *ctx, Object *o);
+    void arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint arrayDataLen);
+    Value arrayIndexOf(Value v, uint fromIndex, uint arrayDataLen, ExecutionContext *ctx, Object *o);
 
+    void arrayReserve(uint n);
 
 protected:
     virtual void markObjects();
@@ -452,14 +398,30 @@ struct ArrayObject: Object {
     };
 
     ArrayObject(ExecutionContext *ctx) { init(ctx); }
-    ArrayObject(ExecutionContext *ctx, const QVector<PropertyDescriptor> &value): Object() {
-        init(ctx);
-        arrayData = value;
-        setArrayLengthUnchecked(value.size());
-    }
     void init(ExecutionContext *context);
 };
 
+inline uint Object::arrayLength() const
+{
+    if (isArrayObject()) {
+        // length is always the first property of an array
+        Value v = memberData[ArrayObject::LengthPropertyIndex].value;
+        if (v.isInteger())
+            return v.integerValue();
+        return Value::toUInt32(v.doubleValue());
+    }
+    return 0;
+}
+
+inline void Object::setArrayLengthUnchecked(uint l)
+{
+    if (isArrayObject()) {
+        // length is always the first property of an array
+        PropertyDescriptor &lengthProperty = memberData[ArrayObject::LengthPropertyIndex];
+        lengthProperty.value = Value::fromUInt32(l);
+    }
+}
+
 
 } // namespace VM
 } // namespace QQmlJS
index 04f11c6..7bcf872 100644 (file)
@@ -101,7 +101,7 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
             arrayIndex = UINT_MAX;
         }
         // dense arrays
-        while (arrayIndex < current->arrayLength()) {
+        while (arrayIndex < current->arrayDataLen) {
             p = current->arrayAt(arrayIndex);
             ++arrayIndex;
             if (p && p->type != PropertyDescriptor::Generic && (!(flags & EnumberableOnly) || p->isEnumerable())) {