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