aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4arraydata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4arraydata.cpp')
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp376
1 files changed, 195 insertions, 181 deletions
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