aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp376
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h42
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4object.cpp49
-rw-r--r--src/qml/jsruntime/qv4object_p.h3
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp8
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp4
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp3
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp1
-rw-r--r--src/qml/qml/qqmllocale.cpp5
-rw-r--r--src/qml/qml/v8/qv8engine.cpp18
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();
}