Move the Array code into Object itself
authorLars Knoll <lars.knoll@digia.com>
Sun, 3 Feb 2013 10:36:55 +0000 (11:36 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Mon, 4 Feb 2013 14:47:32 +0000 (15:47 +0100)
This allows simplifications of the code moving forward.

Change-Id: If65809fd3646e6dc2da6bc62190d6465b1b1ec12
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
15 files changed:
src/v4/qmljs_engine.cpp
src/v4/qmljs_engine.h
src/v4/qmljs_runtime.cpp
src/v4/qv4argumentsobject.cpp
src/v4/qv4array.cpp
src/v4/qv4array.h
src/v4/qv4arrayobject.cpp
src/v4/qv4jsonobject.cpp
src/v4/qv4object.cpp
src/v4/qv4object.h
src/v4/qv4objectiterator.cpp
src/v4/qv4objectproto.cpp
src/v4/qv4regexpobject.cpp
src/v4/qv4stringobject.cpp
tests/TestExpectations

index 55121cd..8c5dcfc 100644 (file)
@@ -320,13 +320,6 @@ ArrayObject *ExecutionEngine::newArrayObject(ExecutionContext *ctx)
     return object;
 }
 
-ArrayObject *ExecutionEngine::newArrayObject(ExecutionContext *ctx, const Array &value)
-{
-    ArrayObject *object = new (memoryManager) ArrayObject(ctx, value);
-    object->prototype = arrayPrototype;
-    return object;
-}
-
 Object *ExecutionEngine::newDateObject(const Value &value)
 {
     Object *object = new (memoryManager) DateObject(value);
index bf3ccb2..a221c06 100644 (file)
@@ -200,7 +200,7 @@ struct Q_V4_EXPORT ExecutionEngine
     Object *newFunctionObject(ExecutionContext *ctx);
 
     ArrayObject *newArrayObject(ExecutionContext *ctx);
-    ArrayObject *newArrayObject(ExecutionContext *ctx, const Array &value);
+//    ArrayObject *newArrayObject(ExecutionContext *ctx, const Array &value);
 
     Object *newDateObject(const Value &value);
 
index 6330435..d01d76d 100644 (file)
@@ -596,7 +596,7 @@ Value __qmljs_get_element(ExecutionContext *ctx, Value object, Value index)
     Object *o = object.objectValue();
 
     if (idx < UINT_MAX) {
-        const PropertyDescriptor *p = o->array.nonSparseArrayAt(idx);
+        const PropertyDescriptor *p = o->nonSparseArrayAt(idx);
         if (p && p->type == PropertyDescriptor::Data)
             return p->value;
 
@@ -616,7 +616,7 @@ void __qmljs_set_element(ExecutionContext *ctx, Value object, Value index, Value
 
     uint idx = index.asArrayIndex();
     if (idx < UINT_MAX) {
-        PropertyDescriptor *p = o->array.nonSparseArrayAtRef(idx);
+        PropertyDescriptor *p = o->nonSparseArrayAtRef(idx);
         if (p && p->type == PropertyDescriptor::Data && p->isWritable()) {
             p->value = value;
             return;
index cb88028..8211ef2 100644 (file)
@@ -82,7 +82,7 @@ ArgumentsObject::ArgumentsObject(ExecutionContext *context, int formalParameterC
 
 bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const PropertyDescriptor *desc)
 {
-    PropertyDescriptor *pd = array.arrayAt(index);
+    PropertyDescriptor *pd = arrayAt(index);
     PropertyDescriptor map;
     bool isMapped = false;
     if (pd && index < (uint)mappedArguments.size())
index ffefd1b..2f42057 100644 (file)
@@ -462,199 +462,6 @@ SparseArrayNode *SparseArray::insert(uint akey)
     return createNode(s, y, left);
 }
 
-Array::Array(const Array &other)
-    : arrayLen(other.arrayLen)
-    , arrayObject(0)
-    , arrayData(other.arrayData)
-    , sparseArray(0)
-{
-    arrayFreeList = other.arrayFreeList;
-    if (other.sparseArray)
-        sparseArray = new SparseArray(*other.sparseArray);
-}
-
-
-Value Array::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
-{
-    bool protoHasArray = false;
-    Object *p = o;
-    while ((p = p->prototype))
-        if (p->array.arrayLength())
-            protoHasArray = true;
-
-    if (protoHasArray) {
-        // lets be safe and slow
-        for (uint i = fromIndex; i < endIndex; ++i) {
-            bool exists;
-            Value value = o->__get__(ctx, i, &exists);
-            if (exists && __qmljs_strict_equal(value, v))
-                return Value::fromDouble(i);
-        }
-    } else if (sparseArray) {
-        for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n && 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;
-        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());
-            ++pd;
-        }
-    }
-    return Value::fromInt32(-1);
-}
-
-void Array::arrayConcat(const Array &other)
-{
-    initSparse();
-    int newLen = arrayLen + 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));
-        } else {
-            int oldSize = arrayData.size();
-            arrayData.resize(oldSize + other.arrayLength());
-            memcpy(arrayData.data() + oldSize, other.arrayData.constData() + other.arrayOffset, other.arrayLength()*sizeof(PropertyDescriptor));
-            for (uint i = 0; i < other.arrayLength(); ++i) {
-                SparseArrayNode *n = sparseArray->insert(arrayLen + 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));
-    }
-    setArrayLengthUnchecked(newLen);
-}
-
-void Array::arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint len)
-{
-    if (sparseArray) {
-        context->throwUnimplemented("Array::sort unimplemented for sparse arrays");
-        return;
-        delete sparseArray;
-    }
-
-    ArrayElementLessThan lessThan(context, thisObject, comparefn);
-    if (len > arrayData.size() - arrayOffset)
-        len = arrayData.size() - arrayOffset;
-    PropertyDescriptor *begin = arrayData.begin() + arrayOffset;
-    std::sort(begin, begin + len, lessThan);
-}
-
-
-void Array::initSparse()
-{
-    if (!sparseArray) {
-        sparseArray = new SparseArray;
-        for (int i = arrayOffset; i < arrayData.size(); ++i) {
-            SparseArrayNode *n = sparseArray->insert(i - arrayOffset);
-            n->value = i;
-        }
-
-        if (arrayOffset) {
-            int o = arrayOffset;
-            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();
-        }
-    }
-}
-
-void Array::setArrayLengthUnchecked(uint l)
-{
-    arrayLen = l;
-    if (arrayObject) {
-        // length is always the first property of an array
-        PropertyDescriptor &lengthProperty = arrayObject->memberData[ArrayObject::LengthPropertyIndex];
-        lengthProperty.value = Value::fromUInt32(l);
-    }
-}
-
-bool Array::setArrayLength(uint newLen) {
-    const PropertyDescriptor *lengthProperty = arrayObject->memberData.constData() + ArrayObject::LengthPropertyIndex;
-    if (lengthProperty && !lengthProperty->isWritable())
-        return false;
-    uint oldLen = arrayLength();
-    bool ok = true;
-    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;
-                }
-                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;
-            while (--it >= begin) {
-                if (it->type != PropertyDescriptor::Generic && !it->isConfigurable()) {
-                    ok = false;
-                    newLen = it - arrayData.data() + arrayOffset + 1;
-                    break;
-                }
-            }
-            arrayData.resize(newLen + arrayOffset);
-        }
-    } else {
-        if (newLen >= 0x100000)
-            initSparse();
-    }
-    setArrayLengthUnchecked(newLen);
-    return ok;
-}
-
-void Array::markArrayObjects() const
-{
-    uint i = sparseArray ? 0 : arrayOffset;
-    for (; i < (uint)arrayData.size(); ++i) {
-        const PropertyDescriptor &pd = arrayData.at(i);
-        if (pd.isData()) {
-            if (Managed *m = pd.value.asManaged())
-                m->mark();
-         } else if (pd.isAccessor()) {
-            if (pd.get)
-                pd.get->mark();
-            if (pd.set)
-                pd.set->mark();
-        }
-    }
-}
 
 }
 }
index d0057e4..ce6a697 100644 (file)
@@ -361,274 +361,6 @@ inline SparseArrayNode *SparseArray::upperBound(uint akey)
     return ub;
 }
 
-
-class Array
-{
-    friend struct ArrayPrototype;
-
-    uint arrayLen;
-    ArrayObject *arrayObject;
-    union {
-        uint arrayFreeList;
-        uint arrayOffset;
-    };
-    QVector<PropertyDescriptor> arrayData;
-    SparseArray *sparseArray;
-
-    void fillDescriptor(PropertyDescriptor *pd, Value v)
-    {
-        pd->type = PropertyDescriptor::Data;
-        pd->writable = PropertyDescriptor::Enabled;
-        pd->enumberable = PropertyDescriptor::Enabled;
-        pd->configurable = PropertyDescriptor::Enabled;
-        pd->value = v;
-    }
-
-    uint allocArrayValue() {
-        uint idx = arrayFreeList;
-        if (arrayData.size() <= (int)arrayFreeList)
-            arrayData.resize(++arrayFreeList);
-        else
-            arrayFreeList = arrayData.at(arrayFreeList).value.integerValue();
-        return idx;
-    }
-
-    uint allocArrayValue(Value v) {
-        uint idx = allocArrayValue();
-        PropertyDescriptor *pd = &arrayData[idx];
-        fillDescriptor(pd, v);
-        return idx;
-    }
-    void freeArrayValue(int idx) {
-        PropertyDescriptor &pd = arrayData[idx];
-        pd.type = PropertyDescriptor::Generic;
-        pd.value.tag = Value::_Undefined_Type;
-        pd.value.int_32 = arrayFreeList;
-        arrayFreeList = idx;
-    }
-
-    PropertyDescriptor *arrayDecriptor(uint index) {
-        PropertyDescriptor *pd = arrayData.data() + index;
-        if (!sparseArray)
-            pd += arrayOffset;
-        return pd;
-    }
-    const PropertyDescriptor *arrayDecriptor(uint index) const {
-        const PropertyDescriptor *pd = arrayData.data() + index;
-        if (!sparseArray)
-            pd += arrayOffset;
-        return pd;
-    }
-
-    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;
-    }
-
-public:
-    Array() : arrayLen(0), arrayObject(0), arrayOffset(0), sparseArray(0) {}
-    Array(const Array &other);
-    ~Array() { delete sparseArray; }
-    void initSparse();
-
-    uint arrayLength() const { return arrayLen; }
-    bool setArrayLength(uint newLen);
-
-    void setArrayObject(ArrayObject *a) { arrayObject = a; }
-
-    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) {
-                    arrayData[i].type = PropertyDescriptor::Generic;
-                    arrayData[i].value.tag = Value::_Undefined_Type;
-                }
-            }
-            pd = arrayDecriptor(index);
-        } else {
-            initSparse();
-            SparseArrayNode *n = sparseArray->insert(index);
-            if (n->value == UINT_MAX)
-                n->value = allocArrayValue();
-            pd = arrayDecriptor(n->value);
-        }
-        if (index >= arrayLen)
-            setArrayLengthUnchecked(index + 1);
-        return pd;
-    }
-
-    void arraySet(uint index, const PropertyDescriptor *pd) {
-        *arrayInsert(index) = *pd;
-    }
-
-    void arraySet(uint index, Value value) {
-        PropertyDescriptor *pd = arrayInsert(index);
-        fillDescriptor(pd, value);
-    }
-
-    bool deleteArrayIndex(uint index) {
-        if (index >= arrayLen)
-            return true;
-        PropertyDescriptor *pd = 0;
-        if (!sparseArray) {
-            pd = arrayAt(index);
-        } else {
-            SparseArrayNode *n = sparseArray->findNode(index);
-            if (n)
-                pd = arrayDecriptor(n->value);
-        }
-        if (!pd || pd->type == PropertyDescriptor::Generic)
-            return true;
-        if (!pd->isConfigurable())
-            return false;
-        pd->type = PropertyDescriptor::Generic;
-        pd->value.tag = Value::_Undefined_Type;
-        if (sparseArray) {
-            pd->value.int_32 = arrayFreeList;
-            arrayFreeList = pd - arrayData.constData();
-        }
-        return true;
-    }
-
-    PropertyDescriptor *arrayAt(uint index) {
-        if (!sparseArray) {
-            if (index >= arrayData.size() - arrayOffset)
-                return 0;
-            return arrayData.data() + index + arrayOffset;
-        } else {
-            SparseArrayNode *n = sparseArray->findNode(index);
-            if (!n)
-                return 0;
-            return arrayData.data() + n->value;
-        }
-    }
-
-    const PropertyDescriptor *nonSparseArrayAt(uint index) const {
-        if (sparseArray)
-            return 0;
-        index += arrayOffset;
-        if (index >= (uint)arrayData.size())
-            return 0;
-        return arrayData.constData() + index;
-    }
-
-    PropertyDescriptor *nonSparseArrayAtRef(uint index) {
-        if (sparseArray)
-            return 0;
-        index += arrayOffset;
-        if (index >= (uint)arrayData.size())
-            return 0;
-        return arrayData.data() + index;
-    }
-
-    const PropertyDescriptor *arrayAt(uint index) const {
-        if (!sparseArray) {
-            if (index >= arrayData.size() - arrayOffset)
-                return 0;
-            return arrayData.constData() + index + arrayOffset;
-        } else {
-            SparseArrayNode *n = sparseArray->findNode(index);
-            if (!n)
-                return 0;
-            return arrayData.constData() + n->value;
-        }
-    }
-
-    void markArrayObjects() const;
-
-    void push_front(Value v) {
-        if (!sparseArray) {
-            if (!arrayOffset)
-                getArrayHeadRoom();
-
-            --arrayOffset;
-            PropertyDescriptor &pd = values[offset];
-            fillDescriptor(&pd, v);
-        } 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;
-        } else {
-            SparseArrayNode *n = sparseArray->findNode(0);
-            if (n)
-                pd = arrayDecriptor(n->value);
-        }
-        if (pd && pd->type == PropertyDescriptor::Generic)
-            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) {
-        if (!sparseArray) {
-            PropertyDescriptor pd;
-            fillDescriptor(&pd, v);
-            arrayData.append(pd);
-        } else {
-            uint idx = allocArrayValue(v);
-            sparseArray->push_back(idx, arrayLen);
-        }
-        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);
-    }
-
-    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 Array &other);
-    void arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint arrayLen);
-    Value arrayIndexOf(Value v, uint fromIndex, uint arrayLen, ExecutionContext *ctx, Object *o);
-};
-
 }
 }
 
index b24ca32..3fa1885 100644 (file)
@@ -52,22 +52,23 @@ ArrayCtor::ArrayCtor(ExecutionContext *scope)
 Value ArrayCtor::call(ExecutionContext *ctx)
 {
     ArrayObject *a = ctx->engine->newArrayObject(ctx);
-    Array &value = a->array;
+    uint len;
     if (ctx->argumentCount == 1 && ctx->argument(0).isNumber()) {
         bool ok;
-        uint len = ctx->argument(0).asArrayLength(ctx, &ok);
+        len = ctx->argument(0).asArrayLength(ctx, &ok);
 
         if (!ok) {
             ctx->throwRangeError(ctx->argument(0));
             return Value::undefinedValue();
         }
 
-        value.setArrayLengthUnchecked(len);
     } else {
-        for (unsigned int i = 0; i < ctx->argumentCount; ++i) {
-            value.arraySet(i, ctx->argument(i));
+        len = ctx->argumentCount;
+        for (unsigned int i = 0; i < len; ++i) {
+            a->arraySet(i, ctx->argument(i));
         }
     }
+    a->setArrayLengthUnchecked(len);
 
     return Value::fromObject(a);
 }
@@ -104,7 +105,7 @@ void ArrayPrototype::init(ExecutionContext *ctx, const Value &ctor)
 uint ArrayPrototype::getLength(ExecutionContext *ctx, Object *o)
 {
     if (o->isArrayObject())
-        return o->array.arrayLength();
+        return o->arrayLength();
     return o->__get__(ctx, ctx->engine->id_length).toUInt32(ctx);
 }
 
@@ -127,27 +128,27 @@ Value ArrayPrototype::method_toLocaleString(ExecutionContext *ctx)
 
 Value ArrayPrototype::method_concat(ExecutionContext *ctx)
 {
-    Array result;
+    ArrayObject *result = ctx->engine->newArrayObject(ctx);
 
-    if (ArrayObject *instance = ctx->thisObject.asArrayObject())
-        result = instance->array;
-    else {
+    if (ArrayObject *instance = ctx->thisObject.asArrayObject()) {
+        result->copyArrayData(instance);
+    else {
         QString v = ctx->thisObject.toString(ctx)->toQString();
-        result.arraySet(0, Value::fromString(ctx, v));
+        result->arraySet(0, Value::fromString(ctx, v));
     }
 
     for (uint i = 0; i < ctx->argumentCount; ++i) {
-        quint32 k = result.arrayLength();
+        quint32 k = result->arrayLength();
         Value arg = ctx->argument(i);
 
         if (ArrayObject *elt = arg.asArrayObject())
-            result.arrayConcat(elt->array);
+            result->arrayConcat(elt);
 
         else
-            result.arraySet(k, arg);
+            result->arraySet(k, arg);
     }
 
-    return Value::fromObject(ctx->engine->newArrayObject(ctx, result));
+    return Value::fromObject(result);
 }
 
 Value ArrayPrototype::method_join(ExecutionContext *ctx)
@@ -176,7 +177,7 @@ Value ArrayPrototype::method_join(ExecutionContext *ctx)
 
     // ### FIXME
     if (ArrayObject *a = self.asArrayObject()) {
-        for (uint i = 0; i < a->array.arrayLength(); ++i) {
+        for (uint i = 0; i < a->arrayLength(); ++i) {
             if (i)
                 R += r4;
 
@@ -222,7 +223,7 @@ Value ArrayPrototype::method_pop(ExecutionContext *ctx)
 
     instance->__delete__(ctx, len - 1);
     if (instance->isArrayObject())
-        instance->array.setArrayLengthUnchecked(len - 1);
+        instance->setArrayLengthUnchecked(len - 1);
     else
         instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(len - 1));
     return result;
@@ -251,13 +252,13 @@ Value ArrayPrototype::method_push(ExecutionContext *ctx)
     bool protoHasArray = false;
     Object *p = instance;
     while ((p = p->prototype))
-        if (p->array.arrayLength())
+        if (p->arrayLength())
             protoHasArray = true;
 
-    if (!protoHasArray && len == instance->array.arrayLength()) {
+    if (!protoHasArray && len == instance->arrayLength()) {
         for (uint i = 0; i < ctx->argumentCount; ++i) {
             Value v = ctx->argument(i);
-            instance->array.push_back(v);
+            instance->push_back(v);
         }
     } else {
         for (uint i = 0; i < ctx->argumentCount; ++i)
@@ -307,16 +308,16 @@ Value ArrayPrototype::method_shift(ExecutionContext *ctx)
         return Value::undefinedValue();
     }
 
-    Value result = instance->getValueChecked(ctx, instance->array.front());
+    Value result = instance->getValueChecked(ctx, instance->front());
 
     bool protoHasArray = false;
     Object *p = instance;
     while ((p = p->prototype))
-        if (p->array.arrayLength())
+        if (p->arrayLength())
             protoHasArray = true;
 
-    if (!protoHasArray && len >= instance->array.arrayLength()) {
-        instance->array.pop_front();
+    if (!protoHasArray && len >= instance->arrayLength()) {
+        instance->pop_front();
     } else {
         // do it the slow way
         for (uint k = 1; k < len; ++k) {
@@ -339,7 +340,7 @@ Value ArrayPrototype::method_slice(ExecutionContext *ctx)
 {
     Object *o = ctx->thisObject.toObject(ctx).objectValue();
 
-    Array result;
+    ArrayObject *result = ctx->engine->newArrayObject(ctx);
     uint len = o->__get__(ctx, ctx->engine->id_length).toUInt32(ctx);
     double s = ctx->argument(0).toInteger(ctx);
     uint start;
@@ -365,10 +366,10 @@ Value ArrayPrototype::method_slice(ExecutionContext *ctx)
         bool exists;
         Value v = o->__get__(ctx, i, &exists);
         if (exists)
-            result.arraySet(n, v);
+            result->arraySet(n, v);
         ++n;
     }
-    return Value::fromObject(ctx->engine->newArrayObject(ctx, result));
+    return Value::fromObject(result);
 }
 
 Value ArrayPrototype::method_sort(ExecutionContext *ctx)
@@ -378,7 +379,7 @@ Value ArrayPrototype::method_sort(ExecutionContext *ctx)
     uint len = getLength(ctx, instance);
 
     Value comparefn = ctx->argument(0);
-    instance->array.arraySort(ctx, instance, comparefn, len);
+    instance->arraySort(ctx, instance, comparefn, len);
     return ctx->thisObject;
 }
 
@@ -398,8 +399,8 @@ Value ArrayPrototype::method_splice(ExecutionContext *ctx)
 
     uint deleteCount = (uint)qMin(qMax(ctx->argument(1).toInteger(ctx), 0.), (double)(len - start));
 
-    newArray->array.arrayData.resize(deleteCount);
-    PropertyDescriptor *pd = newArray->array.arrayData.data();
+    newArray->arrayData.resize(deleteCount);
+    PropertyDescriptor *pd = newArray->arrayData.data();
     for (uint i = 0; i < deleteCount; ++i) {
         pd->type = PropertyDescriptor::Data;
         pd->writable = PropertyDescriptor::Enabled;
@@ -408,7 +409,7 @@ Value ArrayPrototype::method_splice(ExecutionContext *ctx)
         pd->value = instance->__get__(ctx, start + i);
         ++pd;
     }
-    newArray->array.setArrayLengthUnchecked(deleteCount);
+    newArray->setArrayLengthUnchecked(deleteCount);
 
     uint itemCount = ctx->argumentCount < 2 ? 0 : ctx->argumentCount - 2;
 
@@ -417,7 +418,7 @@ Value ArrayPrototype::method_splice(ExecutionContext *ctx)
             bool exists;
             Value v = instance->__get__(ctx, k + deleteCount, &exists);
             if (exists)
-                instance->array.arraySet(k + itemCount, v);
+                instance->arraySet(k + itemCount, v);
             else
                 instance->__delete__(ctx, k + itemCount);
         }
@@ -429,7 +430,7 @@ Value ArrayPrototype::method_splice(ExecutionContext *ctx)
             bool exists;
             Value v = instance->__get__(ctx, k + deleteCount - 1, &exists);
             if (exists)
-                instance->array.arraySet(k + itemCount - 1, v);
+                instance->arraySet(k + itemCount - 1, v);
             else
                 instance->__delete__(ctx, k + itemCount - 1);
             --k;
@@ -437,7 +438,7 @@ Value ArrayPrototype::method_splice(ExecutionContext *ctx)
     }
 
     for (uint i = 0; i < itemCount; ++i)
-        instance->array.arraySet(start + i, ctx->argument(i + 2));
+        instance->arraySet(start + i, ctx->argument(i + 2));
 
     ctx->strictMode = true;
     instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(len - deleteCount + itemCount));
@@ -453,13 +454,13 @@ Value ArrayPrototype::method_unshift(ExecutionContext *ctx)
     bool protoHasArray = false;
     Object *p = instance;
     while ((p = p->prototype))
-        if (p->array.arrayLength())
+        if (p->arrayLength())
             protoHasArray = true;
 
-    if (!protoHasArray && len >= instance->array.arrayLength()) {
+    if (!protoHasArray && len >= instance->arrayLength()) {
         for (int i = ctx->argumentCount - 1; i >= 0; --i) {
             Value v = ctx->argument(i);
-            instance->array.push_front(v);
+            instance->push_front(v);
         }
     } else {
         for (uint k = len; k > 0; --k) {
@@ -516,7 +517,7 @@ Value ArrayPrototype::method_indexOf(ExecutionContext *ctx)
         return Value::fromInt32(-1);
     }
 
-    return instance->array.arrayIndexOf(searchValue, fromIndex, len, ctx, instance);
+    return instance->arrayIndexOf(searchValue, fromIndex, len, ctx, instance);
 }
 
 Value ArrayPrototype::method_lastIndexOf(ExecutionContext *ctx)
@@ -654,7 +655,7 @@ Value ArrayPrototype::method_map(ExecutionContext *ctx)
     Value thisArg = ctx->argument(1);
 
     ArrayObject *a = ctx->engine->newArrayObject(ctx);
-    a->array.setArrayLengthUnchecked(len);
+    a->setArrayLengthUnchecked(len);
 
     for (uint k = 0; k < len; ++k) {
         bool exists;
@@ -667,7 +668,7 @@ Value ArrayPrototype::method_map(ExecutionContext *ctx)
         args[1] = Value::fromDouble(k);
         args[2] = ctx->thisObject;
         Value mapped = callback->call(ctx, thisArg, args, 3);
-        a->array.arraySet(k, mapped);
+        a->arraySet(k, mapped);
     }
     return Value::fromObject(a);
 }
@@ -699,7 +700,7 @@ Value ArrayPrototype::method_filter(ExecutionContext *ctx)
         args[2] = ctx->thisObject;
         Value selected = callback->call(ctx, thisArg, args, 3);
         if (__qmljs_to_boolean(selected, ctx)) {
-            a->array.arraySet(to, v);
+            a->arraySet(to, v);
             ++to;
         }
     }
index c5df590..d30c10a 100644 (file)
@@ -295,7 +295,7 @@ bool Parser::parseMember(Object *o)
 Value Parser::parseArray()
 {
     BEGIN << "parseArray";
-    Array array;
+    ArrayObject *array = context->engine->newArrayObject(context);
 
     if (++nestingLevel > nestingLimit) {
         lastError = QJsonParseError::DeepNesting;
@@ -314,7 +314,7 @@ Value Parser::parseArray()
             Value val;
             if (!parseValue(&val))
                 return Value::undefinedValue();
-            array.arraySet(index, val);
+            array->arraySet(index, val);
             QChar token = nextToken();
             if (token == EndArray)
                 break;
@@ -329,11 +329,11 @@ Value Parser::parseArray()
         }
     }
 
-    DEBUG << "size =" << array.arrayLength();
+    DEBUG << "size =" << array->arrayLength();
     END;
 
     --nestingLevel;
-    return Value::fromObject(context->engine->newArrayObject(context, array));
+    return Value::fromObject(array);
 }
 
 /*
@@ -832,7 +832,7 @@ QString Stringify::JA(ArrayObject *a)
     indent += gap;
 
     QStringList partial;
-    uint len = a->array.arrayLength();
+    uint len = a->arrayLength();
     for (uint i = 0; i < len; ++i) {
         bool exists;
         Value v = a->__get__(ctx, i, &exists);
@@ -897,7 +897,7 @@ Value JsonObject::method_stringify(ExecutionContext *ctx)
     if (o) {
         stringify.replacerFunction = o->asFunctionObject();
         if (o->isArrayObject()) {
-            for (uint i = 0; i < o->array.arrayLength(); ++i) {
+            for (uint i = 0; i < o->arrayLength(); ++i) {
                 Value v = o->__get__(ctx, i);
                 if (v.asNumberObject() || v.asStringObject() || v.isNumber())
                     v = __qmljs_to_string(v, ctx);
index e2e49eb..ff4fffc 100644 (file)
@@ -70,6 +70,7 @@ using namespace QQmlJS::VM;
 //
 Object::~Object()
 {
+    delete sparseArray;
 }
 
 void Object::__put__(ExecutionContext *ctx, const QString &name, const Value &value)
@@ -201,7 +202,7 @@ void Object::markObjects()
             }
         }
     }
-    array.markArrayObjects();
+    markArrayObjects();
 }
 
 PropertyDescriptor *Object::insertMember(String *s)
@@ -234,7 +235,7 @@ PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, String *na
 
 PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, uint index)
 {
-    PropertyDescriptor *p = array.arrayAt(index);
+    PropertyDescriptor *p = arrayAt(index);
     if(p && p->type != PropertyDescriptor::Generic)
         return p;
     if (isStringObject())
@@ -267,7 +268,7 @@ PropertyDescriptor *Object::__getPropertyDescriptor__(ExecutionContext *ctx, uin
 {
     Object *o = this;
     while (o) {
-        PropertyDescriptor *p = o->array.arrayAt(index);
+        PropertyDescriptor *p = o->arrayAt(index);
         if(p && p->type != PropertyDescriptor::Generic)
             return p;
         if (o->isStringObject()) {
@@ -318,7 +319,7 @@ Value Object::__get__(ExecutionContext *ctx, uint index, bool *hasProperty)
     PropertyDescriptor *pd = 0;
     Object *o = this;
     while (o) {
-        PropertyDescriptor *p = o->array.arrayAt(index);
+        PropertyDescriptor *p = o->arrayAt(index);
         if (p && p->type != PropertyDescriptor::Generic) {
             pd = p;
             break;
@@ -368,7 +369,7 @@ void Object::__put__(ExecutionContext *ctx, String *name, Value value)
             uint l = value.asArrayLength(ctx, &ok);
             if (!ok)
                 ctx->throwRangeError(value);
-            ok = array.setArrayLength(l);
+            ok = setArrayLength(l);
             if (!ok)
                 goto reject;
         } else {
@@ -480,7 +481,7 @@ void Object::__put__(ExecutionContext *ctx, uint index, Value value)
         return;
     }
 
-    array.arraySet(index, value);
+    arraySet(index, value);
     return;
 
   reject:
@@ -505,7 +506,7 @@ bool Object::__hasProperty__(const ExecutionContext *ctx, String *name) const
 
 bool Object::__hasProperty__(const ExecutionContext *ctx, uint index) const
 {
-    const PropertyDescriptor *p = array.arrayAt(index);
+    const PropertyDescriptor *p = arrayAt(index);
     if (p && p->type != PropertyDescriptor::Generic)
         return true;
 
@@ -541,7 +542,7 @@ bool Object::__delete__(ExecutionContext *ctx, String *name)
 
 bool Object::__delete__(ExecutionContext *ctx, uint index)
 {
-    if (array.deleteArrayIndex(index))
+    if (deleteArrayIndex(index))
         return true;
     if (ctx->strictMode)
         __qmljs_throw_type_error(ctx);
@@ -572,7 +573,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr
             uint l = desc->value.asArrayLength(ctx, &ok);
             if (!ok)
                 ctx->throwRangeError(desc->value);
-            succeeded = array.setArrayLength(l);
+            succeeded = setArrayLength(l);
         }
         if (desc->writable == PropertyDescriptor::Disabled)
             lp->writable = PropertyDescriptor::Disabled;
@@ -609,7 +610,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop
     PropertyDescriptor *current;
 
     // 15.4.5.1, 4b
-    if (isArrayObject() && index >= array.arrayLength() && !memberData.at(ArrayObject::LengthPropertyIndex).isWritable())
+    if (isArrayObject() && index >= arrayLength() && !memberData.at(ArrayObject::LengthPropertyIndex).isWritable())
         goto reject;
 
     if (isNonStrictArgumentsObject)
@@ -622,7 +623,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop
         if (!extensible)
             goto reject;
         // clause 4
-        PropertyDescriptor *pd = array.arrayInsert(index);
+        PropertyDescriptor *pd = arrayInsert(index);
         *pd = *desc;
         pd->fullyPopulated();
         return true;
@@ -706,6 +707,201 @@ 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)
+        sparseArray = new SparseArray(*other->sparseArray);
+    if (isArrayObject())
+        setArrayLengthUnchecked(arrayLen);
+}
+
+
+Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
+{
+    bool protoHasArray = false;
+    Object *p = o;
+    while ((p = p->prototype))
+        if (p->arrayLength())
+            protoHasArray = true;
+
+    if (protoHasArray) {
+        // lets be safe and slow
+        for (uint i = fromIndex; i < endIndex; ++i) {
+            bool exists;
+            Value value = o->__get__(ctx, i, &exists);
+            if (exists && __qmljs_strict_equal(value, v))
+                return Value::fromDouble(i);
+        }
+    } else if (sparseArray) {
+        for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n && 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;
+        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());
+            ++pd;
+        }
+    }
+    return Value::fromInt32(-1);
+}
+
+void Object::arrayConcat(const ArrayObject *other)
+{
+    int newLen = arrayLen + 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));
+        } else {
+            int oldSize = arrayData.size();
+            arrayData.resize(oldSize + other->arrayLength());
+            memcpy(arrayData.data() + oldSize, other->arrayData.constData() + other->arrayOffset, other->arrayLength()*sizeof(PropertyDescriptor));
+            for (uint i = 0; i < other->arrayLength(); ++i) {
+                SparseArrayNode *n = sparseArray->insert(arrayLen + 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));
+    }
+    setArrayLengthUnchecked(newLen);
+}
+
+void Object::arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint len)
+{
+    if (sparseArray) {
+        context->throwUnimplemented("Object::sort unimplemented for sparse arrays");
+        return;
+        delete sparseArray;
+    }
+
+    ArrayElementLessThan lessThan(context, thisObject, comparefn);
+    if (len > arrayData.size() - arrayOffset)
+        len = arrayData.size() - arrayOffset;
+    PropertyDescriptor *begin = arrayData.begin() + arrayOffset;
+    std::sort(begin, begin + len, lessThan);
+}
+
+
+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;
+        }
+
+        if (arrayOffset) {
+            int o = arrayOffset;
+            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();
+        }
+    }
+}
+
+void Object::setArrayLengthUnchecked(uint l)
+{
+    arrayLen = l;
+    if (isArrayObject()) {
+        // length is always the first property of an array
+        PropertyDescriptor &lengthProperty = memberData[ArrayObject::LengthPropertyIndex];
+        lengthProperty.value = Value::fromUInt32(l);
+    }
+}
+
+bool Object::setArrayLength(uint newLen) {
+    assert(isArrayObject());
+    const PropertyDescriptor *lengthProperty = memberData.constData() + ArrayObject::LengthPropertyIndex;
+    if (lengthProperty && !lengthProperty->isWritable())
+        return false;
+    uint oldLen = arrayLength();
+    bool ok = true;
+    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;
+                }
+                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;
+            while (--it >= begin) {
+                if (it->type != PropertyDescriptor::Generic && !it->isConfigurable()) {
+                    ok = false;
+                    newLen = it - arrayData.data() + arrayOffset + 1;
+                    break;
+                }
+            }
+            arrayData.resize(newLen + arrayOffset);
+        }
+    } else {
+        if (newLen >= 0x100000)
+            initSparse();
+    }
+    setArrayLengthUnchecked(newLen);
+    return ok;
+}
+
+void Object::markArrayObjects() const
+{
+    uint i = sparseArray ? 0 : arrayOffset;
+    for (; i < (uint)arrayData.size(); ++i) {
+        const PropertyDescriptor &pd = arrayData.at(i);
+        if (pd.isData()) {
+            if (Managed *m = pd.value.asManaged())
+                m->mark();
+         } else if (pd.isAccessor()) {
+            if (pd.get)
+                pd.get->mark();
+            if (pd.set)
+                pd.set->mark();
+        }
+    }
+}
+
+
 void ArrayObject::init(ExecutionContext *context)
 {
     type = Type_ArrayObject;
@@ -719,7 +915,6 @@ void ArrayObject::init(ExecutionContext *context)
     pd->enumberable = PropertyDescriptor::Disabled;
     pd->configurable = PropertyDescriptor::Disabled;
     pd->value = Value::fromInt32(0);
-    array.setArrayObject(this);
 }
 
 
index d8c0e56..6e69f9f 100644 (file)
@@ -104,12 +104,18 @@ struct Q_V4_EXPORT Object: Managed {
     Object *prototype;
     QScopedPointer<PropertyTable> members;
     QVector<PropertyDescriptor> memberData;
-    Array array;
+
+    uint arrayLen;
+    union {
+        uint arrayFreeList;
+        uint arrayOffset;
+    };
+    QVector<PropertyDescriptor> arrayData;
+    SparseArray *sparseArray;
 
     Object()
-        : prototype(0) { type = Type_Object; }
-    Object(const Array &a)
-        : prototype(0), array(a) {}
+        : prototype(0)
+        , arrayLen(0), arrayOffset(0), sparseArray(0) { type = Type_Object; }
 
     virtual ~Object();
 
@@ -156,6 +162,259 @@ struct Q_V4_EXPORT Object: Managed {
 
     PropertyDescriptor *insertMember(String *s);
 
+    // Array handling
+
+    void fillDescriptor(PropertyDescriptor *pd, Value v)
+    {
+        pd->type = PropertyDescriptor::Data;
+        pd->writable = PropertyDescriptor::Enabled;
+        pd->enumberable = PropertyDescriptor::Enabled;
+        pd->configurable = PropertyDescriptor::Enabled;
+        pd->value = v;
+    }
+
+    uint allocArrayValue() {
+        uint idx = arrayFreeList;
+        if (arrayData.size() <= (int)arrayFreeList)
+            arrayData.resize(++arrayFreeList);
+        else
+            arrayFreeList = arrayData.at(arrayFreeList).value.integerValue();
+        return idx;
+    }
+
+    uint allocArrayValue(Value v) {
+        uint idx = allocArrayValue();
+        PropertyDescriptor *pd = &arrayData[idx];
+        fillDescriptor(pd, v);
+        return idx;
+    }
+    void freeArrayValue(int idx) {
+        PropertyDescriptor &pd = arrayData[idx];
+        pd.type = PropertyDescriptor::Generic;
+        pd.value.tag = Value::_Undefined_Type;
+        pd.value.int_32 = arrayFreeList;
+        arrayFreeList = idx;
+    }
+
+    PropertyDescriptor *arrayDecriptor(uint index) {
+        PropertyDescriptor *pd = arrayData.data() + index;
+        if (!sparseArray)
+            pd += arrayOffset;
+        return pd;
+    }
+    const PropertyDescriptor *arrayDecriptor(uint index) const {
+        const PropertyDescriptor *pd = arrayData.data() + index;
+        if (!sparseArray)
+            pd += arrayOffset;
+        return pd;
+    }
+
+    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;
+    }
+
+public:
+    void copyArrayData(Object *other);
+    void initSparse();
+
+    uint arrayLength() const { return arrayLen; }
+    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) {
+                    arrayData[i].type = PropertyDescriptor::Generic;
+                    arrayData[i].value.tag = Value::_Undefined_Type;
+                }
+            }
+            pd = arrayDecriptor(index);
+        } else {
+            initSparse();
+            SparseArrayNode *n = sparseArray->insert(index);
+            if (n->value == UINT_MAX)
+                n->value = allocArrayValue();
+            pd = arrayDecriptor(n->value);
+        }
+        if (index >= arrayLen)
+            setArrayLengthUnchecked(index + 1);
+        return pd;
+    }
+
+    void arraySet(uint index, const PropertyDescriptor *pd) {
+        *arrayInsert(index) = *pd;
+    }
+
+    void arraySet(uint index, Value value) {
+        PropertyDescriptor *pd = arrayInsert(index);
+        fillDescriptor(pd, value);
+    }
+
+    bool deleteArrayIndex(uint index) {
+        if (index >= arrayLen)
+            return true;
+        PropertyDescriptor *pd = 0;
+        if (!sparseArray) {
+            pd = arrayAt(index);
+        } else {
+            SparseArrayNode *n = sparseArray->findNode(index);
+            if (n)
+                pd = arrayDecriptor(n->value);
+        }
+        if (!pd || pd->type == PropertyDescriptor::Generic)
+            return true;
+        if (!pd->isConfigurable())
+            return false;
+        pd->type = PropertyDescriptor::Generic;
+        pd->value.tag = Value::_Undefined_Type;
+        if (sparseArray) {
+            pd->value.int_32 = arrayFreeList;
+            arrayFreeList = pd - arrayData.constData();
+        }
+        return true;
+    }
+
+    PropertyDescriptor *arrayAt(uint index) {
+        if (!sparseArray) {
+            if (index >= arrayData.size() - arrayOffset)
+                return 0;
+            return arrayData.data() + index + arrayOffset;
+        } else {
+            SparseArrayNode *n = sparseArray->findNode(index);
+            if (!n)
+                return 0;
+            return arrayData.data() + n->value;
+        }
+    }
+
+    const PropertyDescriptor *nonSparseArrayAt(uint index) const {
+        if (sparseArray)
+            return 0;
+        index += arrayOffset;
+        if (index >= (uint)arrayData.size())
+            return 0;
+        return arrayData.constData() + index;
+    }
+
+    PropertyDescriptor *nonSparseArrayAtRef(uint index) {
+        if (sparseArray)
+            return 0;
+        index += arrayOffset;
+        if (index >= (uint)arrayData.size())
+            return 0;
+        return arrayData.data() + index;
+    }
+
+    const PropertyDescriptor *arrayAt(uint index) const {
+        if (!sparseArray) {
+            if (index >= arrayData.size() - arrayOffset)
+                return 0;
+            return arrayData.constData() + index + arrayOffset;
+        } else {
+            SparseArrayNode *n = sparseArray->findNode(index);
+            if (!n)
+                return 0;
+            return arrayData.constData() + 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;
+        } else {
+            SparseArrayNode *n = sparseArray->findNode(0);
+            if (n)
+                pd = arrayDecriptor(n->value);
+        }
+        if (pd && pd->type == PropertyDescriptor::Generic)
+            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) {
+        if (!sparseArray) {
+            PropertyDescriptor pd;
+            fillDescriptor(&pd, v);
+            arrayData.append(pd);
+        } else {
+            uint idx = allocArrayValue(v);
+            sparseArray->push_back(idx, arrayLen);
+        }
+        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);
+    }
+
+    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);
+
+
 protected:
     virtual void markObjects();
 
@@ -189,7 +448,11 @@ struct ArrayObject: Object {
     };
 
     ArrayObject(ExecutionContext *ctx) { init(ctx); }
-    ArrayObject(ExecutionContext *ctx, const Array &value): Object(value) { init(ctx); array.setArrayLengthUnchecked(array.arrayLength()); }
+    ArrayObject(ExecutionContext *ctx, const QVector<PropertyDescriptor> &value): Object() {
+        init(ctx);
+        arrayData = value;
+        setArrayLengthUnchecked(value.size());
+    }
     void init(ExecutionContext *context);
 };
 
index ecbeaec..d94d778 100644 (file)
@@ -76,20 +76,20 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
                 return s->__getOwnProperty__(context, *index);
             }
             flags &= ~CurrentIsString;
-            arrayNode = current->array.sparseArrayBegin();
+            arrayNode = current->sparseArrayBegin();
             // iterate until we're past the end of the string
             while (arrayNode && arrayNode->key() < slen)
                 arrayNode = arrayNode->nextNode();
         }
 
         if (!arrayIndex)
-            arrayNode = current->array.sparseArrayBegin();
+            arrayNode = current->sparseArrayBegin();
 
         // sparse arrays
         if (arrayNode) {
-            while (arrayNode != current->array.sparseArrayEnd()) {
+            while (arrayNode != current->sparseArrayEnd()) {
                 int k = arrayNode->key();
-                p = current->array.arrayAt(k);
+                p = current->arrayAt(k);
                 arrayNode = arrayNode->nextNode();
                 if (p && (!(flags & EnumberableOnly) || p->isEnumerable())) {
                     arrayIndex = k + 1;
@@ -101,8 +101,8 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
             arrayIndex = UINT_MAX;
         }
         // dense arrays
-        while (arrayIndex < current->array.arrayLength()) {
-            p = current->array.arrayAt(arrayIndex);
+        while (arrayIndex < current->arrayLength()) {
+            p = current->arrayAt(arrayIndex);
             ++arrayIndex;
             if (p && p->type != PropertyDescriptor::Generic && (!(flags & EnumberableOnly) || p->isEnumerable())) {
                 *index = arrayIndex - 1;
index 65153a8..6b7bebc 100644 (file)
@@ -150,13 +150,12 @@ Value ObjectPrototype::method_getOwnPropertyNames(ExecutionContext *ctx)
         ctx->throwTypeError();
 
     ArrayObject *array = ctx->engine->newArrayObject(ctx)->asArrayObject();
-    Array &a = array->array;
     ObjectIterator it(ctx, O, ObjectIterator::NoFlags);
     while (1) {
         Value v = it.nextPropertyNameAsString();
         if (v.isNull())
             break;
-        a.push_back(v);
+        array->push_back(v);
     }
     return Value::fromObject(array);
 }
@@ -354,7 +353,7 @@ Value ObjectPrototype::method_keys(ExecutionContext *ctx)
             key = Value::fromDouble(index);
             key = __qmljs_to_string(key, ctx);
         }
-        a->array.push_back(key);
+        a->push_back(key);
     }
 
     return Value::fromObject(a);
index 69fd5bb..0240830 100644 (file)
@@ -195,7 +195,7 @@ Value RegExpPrototype::method_exec(ExecutionContext *ctx)
         Value entry = Value::undefinedValue();
         if (start != -1 && end != -1)
             entry = Value::fromString(ctx, s.mid(start, end - start));
-        array->array.push_back(entry);
+        array->push_back(entry);
     }
 
     array->__put__(ctx, QLatin1String("index"), Value::fromInt32(result));
index a026e46..87506ec 100644 (file)
@@ -337,7 +337,7 @@ Value StringPrototype::method_match(ExecutionContext *parentCtx, Value thisObjec
             previousLastIndex = thisIndex;
         }
         Value matchStr = result.objectValue()->__get__(parentCtx, (uint)0, (bool *)0);
-        a->array.arraySet(n, matchStr);
+        a->arraySet(n, matchStr);
         ++n;
     }
     if (!n)
@@ -543,7 +543,7 @@ Value StringPrototype::method_split(ExecutionContext *ctx)
 
     if (separatorValue.isUndefined()) {
         if (limitValue.isUndefined()) {
-            array->array.push_back(Value::fromString(ctx, text));
+            array->push_back(Value::fromString(ctx, text));
             return result;
         }
         return Value::fromString(ctx, text.left(limitValue.toInteger(ctx)));
@@ -569,40 +569,40 @@ Value StringPrototype::method_split(ExecutionContext *ctx)
             if (result == JSC::Yarr::offsetNoMatch)
                 break;
 
-            array->array.push_back(Value::fromString(ctx, text.mid(offset, matchOffsets[0] - offset)));
+            array->push_back(Value::fromString(ctx, text.mid(offset, matchOffsets[0] - offset)));
             offset = qMax(offset + 1, matchOffsets[1]);
 
-            if (array->array.arrayLength() >= limit)
+            if (array->arrayLength() >= limit)
                 break;
 
             for (int i = 1; i < re->value->captureCount(); ++i) {
                 uint start = matchOffsets[i * 2];
                 uint end = matchOffsets[i * 2 + 1];
-                array->array.push_back(Value::fromString(ctx, text.mid(start, end - start)));
-                if (array->array.arrayLength() >= limit)
+                array->push_back(Value::fromString(ctx, text.mid(start, end - start)));
+                if (array->arrayLength() >= limit)
                     break;
             }
         }
-        if (array->array.arrayLength() < limit)
-            array->array.push_back(Value::fromString(ctx, text.mid(offset)));
+        if (array->arrayLength() < limit)
+            array->push_back(Value::fromString(ctx, text.mid(offset)));
     } else {
         QString separator = separatorValue.toString(ctx)->toQString();
         if (separator.isEmpty()) {
             for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
-                array->array.push_back(Value::fromString(ctx, text.mid(i, 1)));
+                array->push_back(Value::fromString(ctx, text.mid(i, 1)));
             return result;
         }
 
         int start = 0;
         int end;
         while ((end = text.indexOf(separator, start)) != -1) {
-            array->array.push_back(Value::fromString(ctx, text.mid(start, end - start)));
+            array->push_back(Value::fromString(ctx, text.mid(start, end - start)));
             start = end + separator.size();
-            if (array->array.arrayLength() >= limit)
+            if (array->arrayLength() >= limit)
                 break;
         }
-        if (array->array.arrayLength() < limit && start != -1)
-            array->array.push_back(Value::fromString(ctx, text.mid(start)));
+        if (array->arrayLength() < limit && start != -1)
+            array->push_back(Value::fromString(ctx, text.mid(start)));
     }
     return result;
 }
index 9b1165c..1338378 100644 (file)
@@ -30,7 +30,6 @@ S15.12.2_A1 failing
 S15.4.4.3_A1_T1 failing
 S15.4.4.3_A3_T1 failing
 15.4.4.4-5-c-i-1 failing
-S15.4.4.4_A1_T2 failing
 S15.4.4.4_A2_T1 failing
 S15.4.4.4_A2_T2 failing
 S15.4.4.4_A3_T1 failing