From: Lars Knoll Date: Sun, 3 Feb 2013 10:36:55 +0000 (+0100) Subject: Move the Array code into Object itself X-Git-Tag: upstream/5.2.1~669^2~659^2~319 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=90a710fe96849b24eff58dccd4629c57e55e119c;p=platform%2Fupstream%2Fqtdeclarative.git Move the Array code into Object itself This allows simplifications of the code moving forward. Change-Id: If65809fd3646e6dc2da6bc62190d6465b1b1ec12 Reviewed-by: Simon Hausmann --- diff --git a/src/v4/qmljs_engine.cpp b/src/v4/qmljs_engine.cpp index 55121cd..8c5dcfc 100644 --- a/src/v4/qmljs_engine.cpp +++ b/src/v4/qmljs_engine.cpp @@ -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); diff --git a/src/v4/qmljs_engine.h b/src/v4/qmljs_engine.h index bf3ccb2..a221c06 100644 --- a/src/v4/qmljs_engine.h +++ b/src/v4/qmljs_engine.h @@ -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); diff --git a/src/v4/qmljs_runtime.cpp b/src/v4/qmljs_runtime.cpp index 6330435..d01d76d 100644 --- a/src/v4/qmljs_runtime.cpp +++ b/src/v4/qmljs_runtime.cpp @@ -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; diff --git a/src/v4/qv4argumentsobject.cpp b/src/v4/qv4argumentsobject.cpp index cb88028..8211ef2 100644 --- a/src/v4/qv4argumentsobject.cpp +++ b/src/v4/qv4argumentsobject.cpp @@ -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()) diff --git a/src/v4/qv4array.cpp b/src/v4/qv4array.cpp index ffefd1b..2f42057 100644 --- a/src/v4/qv4array.cpp +++ b/src/v4/qv4array.cpp @@ -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(); - } - } -} } } diff --git a/src/v4/qv4array.h b/src/v4/qv4array.h index d0057e4..ce6a697 100644 --- a/src/v4/qv4array.h +++ b/src/v4/qv4array.h @@ -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 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 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); -}; - } } diff --git a/src/v4/qv4arrayobject.cpp b/src/v4/qv4arrayobject.cpp index b24ca32..3fa1885 100644 --- a/src/v4/qv4arrayobject.cpp +++ b/src/v4/qv4arrayobject.cpp @@ -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; } } diff --git a/src/v4/qv4jsonobject.cpp b/src/v4/qv4jsonobject.cpp index c5df590..d30c10a 100644 --- a/src/v4/qv4jsonobject.cpp +++ b/src/v4/qv4jsonobject.cpp @@ -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); diff --git a/src/v4/qv4object.cpp b/src/v4/qv4object.cpp index e2e49eb..ff4fffc 100644 --- a/src/v4/qv4object.cpp +++ b/src/v4/qv4object.cpp @@ -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); } diff --git a/src/v4/qv4object.h b/src/v4/qv4object.h index d8c0e56..6e69f9f 100644 --- a/src/v4/qv4object.h +++ b/src/v4/qv4object.h @@ -104,12 +104,18 @@ struct Q_V4_EXPORT Object: Managed { Object *prototype; QScopedPointer members; QVector memberData; - Array array; + + uint arrayLen; + union { + uint arrayFreeList; + uint arrayOffset; + }; + QVector 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 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 &value): Object() { + init(ctx); + arrayData = value; + setArrayLengthUnchecked(value.size()); + } void init(ExecutionContext *context); }; diff --git a/src/v4/qv4objectiterator.cpp b/src/v4/qv4objectiterator.cpp index ecbeaec..d94d778 100644 --- a/src/v4/qv4objectiterator.cpp +++ b/src/v4/qv4objectiterator.cpp @@ -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; diff --git a/src/v4/qv4objectproto.cpp b/src/v4/qv4objectproto.cpp index 65153a8..6b7bebc 100644 --- a/src/v4/qv4objectproto.cpp +++ b/src/v4/qv4objectproto.cpp @@ -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); diff --git a/src/v4/qv4regexpobject.cpp b/src/v4/qv4regexpobject.cpp index 69fd5bb..0240830 100644 --- a/src/v4/qv4regexpobject.cpp +++ b/src/v4/qv4regexpobject.cpp @@ -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)); diff --git a/src/v4/qv4stringobject.cpp b/src/v4/qv4stringobject.cpp index a026e46..87506ec 100644 --- a/src/v4/qv4stringobject.cpp +++ b/src/v4/qv4stringobject.cpp @@ -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; } diff --git a/tests/TestExpectations b/tests/TestExpectations index 9b1165c..1338378 100644 --- a/tests/TestExpectations +++ b/tests/TestExpectations @@ -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